diff --git a/internal/graphicsdriver/directx/graphics11_windows.go b/internal/graphicsdriver/directx/graphics11_windows.go index 0d329de5ff6b..71c40d758455 100644 --- a/internal/graphicsdriver/directx/graphics11_windows.go +++ b/internal/graphicsdriver/directx/graphics11_windows.go @@ -24,7 +24,6 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/graphics" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" "github.com/hajimehoshi/ebiten/v2/internal/shaderir" - "github.com/hajimehoshi/ebiten/v2/internal/shaderir/hlsl" ) var inputElementDescsForDX11 []_D3D11_INPUT_ELEMENT_DESC @@ -513,7 +512,7 @@ func (g *graphics11) NewShader(program *shaderir.Program) (graphicsdriver.Shader graphics: g, id: g.genNextShaderID(), uniformTypes: program.Uniforms, - uniformOffsets: hlsl.CalcUniformMemoryOffsetsInDWords(program), + uniformOffsets: program.UniformOffsetsInDWords(), vertexShaderBlob: vsh, pixelShaderBlob: psh, } diff --git a/internal/graphicsdriver/directx/graphics12_windows.go b/internal/graphicsdriver/directx/graphics12_windows.go index 50da1ff16467..5b5c37a855e8 100644 --- a/internal/graphicsdriver/directx/graphics12_windows.go +++ b/internal/graphicsdriver/directx/graphics12_windows.go @@ -25,7 +25,6 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" "github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk" "github.com/hajimehoshi/ebiten/v2/internal/shaderir" - "github.com/hajimehoshi/ebiten/v2/internal/shaderir/hlsl" ) type resourceWithSize struct { @@ -1073,7 +1072,7 @@ func (g *graphics12) NewShader(program *shaderir.Program) (graphicsdriver.Shader graphics: g, id: g.genNextShaderID(), uniformTypes: program.Uniforms, - uniformOffsets: hlsl.CalcUniformMemoryOffsetsInDWords(program), + uniformOffsets: program.UniformOffsetsInDWords(), vertexShader: vsh, pixelShader: psh, } diff --git a/internal/shaderir/hlsl/hlsl.go b/internal/shaderir/hlsl/hlsl.go index edd87f8d558b..5b35d16ad5c6 100644 --- a/internal/shaderir/hlsl/hlsl.go +++ b/internal/shaderir/hlsl/hlsl.go @@ -81,7 +81,7 @@ float4x4 float4x4FromScalar(float x) { }` func Compile(p *shaderir.Program) (vertexShader, pixelShader, prelude string) { - offsets := CalcUniformMemoryOffsetsInDWords(p) + offsets := p.UniformOffsetsInDWords() c := &compileContext{ unit: p.Unit, @@ -119,8 +119,8 @@ func Compile(p *shaderir.Program) (vertexShader, pixelShader, prelude string) { lines = append(lines, "cbuffer Uniforms : register(b0) {") for i, t := range p.Uniforms { // packingoffset is not mandatory, but this is useful to ensure the correct offset is used. - offset := fmt.Sprintf("c%d", offsets[i]/boundaryInDWords) - switch offsets[i] % boundaryInDWords { + offset := fmt.Sprintf("c%d", offsets[i]/shaderir.UniformVariableBoundaryInDWords) + switch offsets[i] % shaderir.UniformVariableBoundaryInDWords { case 1: offset += ".y" case 2: diff --git a/internal/shaderir/program.go b/internal/shaderir/program.go index 8688057cbc8d..f114be2f7a17 100644 --- a/internal/shaderir/program.go +++ b/internal/shaderir/program.go @@ -59,7 +59,8 @@ type Program struct { SourceHash SourceHash - uniformFactors []uint32 + uniformFactors []uint32 + offsetsInDWords []int } type Func struct { diff --git a/internal/shaderir/hlsl/packing.go b/internal/shaderir/uniform.go similarity index 75% rename from internal/shaderir/hlsl/packing.go rename to internal/shaderir/uniform.go index 8a6af7bbf8b5..2eb38d16ef8c 100644 --- a/internal/shaderir/hlsl/packing.go +++ b/internal/shaderir/uniform.go @@ -12,89 +12,92 @@ // See the License for the specific language governing permissions and // limitations under the License. -package hlsl +package shaderir import ( "fmt" - - "github.com/hajimehoshi/ebiten/v2/internal/shaderir" ) -const boundaryInDWords = 4 +const UniformVariableBoundaryInDWords = 4 + +// UniformOffsetsInDWords returns the offsets of the uniform variables in DWROD units in the HLSL layout. +func (p *Program) UniformOffsetsInDWords() []int { + if len(p.offsetsInDWords) > 0 { + return p.offsetsInDWords + } -func CalcUniformMemoryOffsetsInDWords(program *shaderir.Program) []int { // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules // https://github.com/microsoft/DirectXShaderCompiler/wiki/Buffer-Packing - var offsetsInDWords []int - var headInDWords int - align := func(x int) int { if x == 0 { return 0 } - return ((x-1)/boundaryInDWords + 1) * boundaryInDWords + return ((x-1)/UniformVariableBoundaryInDWords + 1) * UniformVariableBoundaryInDWords } + var offsetsInDWords []int + var headInDWords int + // TODO: Reorder the variables with packoffset. // See https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-packoffset - for _, u := range program.Uniforms { + for _, u := range p.Uniforms { switch u.Main { - case shaderir.Float: + case Float: offsetsInDWords = append(offsetsInDWords, headInDWords) headInDWords += 1 - case shaderir.Int: + case Int: offsetsInDWords = append(offsetsInDWords, headInDWords) headInDWords += 1 - case shaderir.Vec2, shaderir.IVec2: - if headInDWords%boundaryInDWords >= 3 { + case Vec2, IVec2: + if headInDWords%UniformVariableBoundaryInDWords >= 3 { headInDWords = align(headInDWords) } offsetsInDWords = append(offsetsInDWords, headInDWords) headInDWords += 2 - case shaderir.Vec3, shaderir.IVec3: - if headInDWords%boundaryInDWords >= 2 { + case Vec3, IVec3: + if headInDWords%UniformVariableBoundaryInDWords >= 2 { headInDWords = align(headInDWords) } offsetsInDWords = append(offsetsInDWords, headInDWords) headInDWords += 3 - case shaderir.Vec4, shaderir.IVec4: - if headInDWords%boundaryInDWords >= 1 { + case Vec4, IVec4: + if headInDWords%UniformVariableBoundaryInDWords >= 1 { headInDWords = align(headInDWords) } offsetsInDWords = append(offsetsInDWords, headInDWords) headInDWords += 4 - case shaderir.Mat2: + case Mat2: // For matrices, each column is aligned to the boundary. headInDWords = align(headInDWords) offsetsInDWords = append(offsetsInDWords, headInDWords) headInDWords += 6 - case shaderir.Mat3: + case Mat3: headInDWords = align(headInDWords) offsetsInDWords = append(offsetsInDWords, headInDWords) headInDWords += 11 - case shaderir.Mat4: + case Mat4: headInDWords = align(headInDWords) offsetsInDWords = append(offsetsInDWords, headInDWords) headInDWords += 16 - case shaderir.Array: + case Array: // Each array is 16-byte aligned. // TODO: What if the array has 2 or more dimensions? headInDWords = align(headInDWords) offsetsInDWords = append(offsetsInDWords, headInDWords) n := u.Sub[0].Uint32Count() switch u.Sub[0].Main { - case shaderir.Mat2: + case Mat2: n = 6 - case shaderir.Mat3: + case Mat3: n = 11 - case shaderir.Mat4: + case Mat4: n = 16 } headInDWords += (u.Length - 1) * align(n) // The last element is not with a padding. headInDWords += n - case shaderir.Struct: + case Struct: // TODO: Implement this panic("hlsl: offset for a struct is not implemented yet") default: @@ -102,5 +105,6 @@ func CalcUniformMemoryOffsetsInDWords(program *shaderir.Program) []int { } } - return offsetsInDWords + p.offsetsInDWords = offsetsInDWords + return p.offsetsInDWords }