From f6d87f6ee8a60aa91aab98c773a842803e043781 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 26 Mar 2022 23:46:37 +0900 Subject: [PATCH] internal/graphicsdriver/directx, internal/graphicsdriver/metal: bug fix: uniform matrix variables were passed wrongly Updates #2036 --- .../directx/graphics_windows.go | 28 +++-- .../graphicsdriver/metal/graphics_darwin.go | 13 +- shader_test.go | 111 ++++++++++++++++++ 3 files changed, 138 insertions(+), 14 deletions(-) diff --git a/internal/graphicsdriver/directx/graphics_windows.go b/internal/graphicsdriver/directx/graphics_windows.go index 4f681962d..aaf89ed4e 100644 --- a/internal/graphicsdriver/directx/graphics_windows.go +++ b/internal/graphicsdriver/directx/graphics_windows.go @@ -1637,21 +1637,23 @@ func (s *Shader) uniformsToFloat32s(uniforms [][]float32) []float32 { case shaderir.Float, shaderir.Vec2, shaderir.Vec3, shaderir.Vec4: fs = append(fs, u...) case shaderir.Mat2: - for j := 0; j < 2; j++ { - fs = append(fs, u[2*j:2*(j+1)]...) - if j < 1 { - fs = append(fs, 0, 0) - } - } + fs = append(fs, + u[0], u[2], 0, 0, + u[1], u[3], + ) case shaderir.Mat3: - for j := 0; j < 3; j++ { - fs = append(fs, u[3*j:3*(j+1)]...) - if j < 2 { - fs = append(fs, 0) - } - } + fs = append(fs, + u[0], u[3], u[6], 0, + u[1], u[4], u[7], 0, + u[2], u[5], u[8], + ) case shaderir.Mat4: - fs = append(fs, u...) + fs = append(fs, + u[0], u[4], u[8], u[12], + u[1], u[5], u[9], u[13], + u[2], u[6], u[10], u[14], + u[3], u[7], u[11], u[15], + ) case shaderir.Array: // Each element is aligned to the boundary. switch t.Sub[0].Main { diff --git a/internal/graphicsdriver/metal/graphics_darwin.go b/internal/graphicsdriver/metal/graphics_darwin.go index 847b25a23..79fc56c17 100644 --- a/internal/graphicsdriver/metal/graphics_darwin.go +++ b/internal/graphicsdriver/metal/graphics_darwin.go @@ -998,7 +998,18 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics. // Set the additional uniform variables. for i, v := range uniforms { const offset = graphics.PreservedUniformVariablesNum - uniformVars[offset+i] = v + switch g.shaders[shaderID].ir.Uniforms[offset+i].Main { + case shaderir.Mat3: + println("yo") + // float3x3 requires 16-byte alignment (#2036). + newV := make([]float32, 12) + copy(newV[0:3], v[0:3]) + copy(newV[4:7], v[3:6]) + copy(newV[8:11], v[6:9]) + uniformVars[offset+i] = newV + default: + uniformVars[offset+i] = v + } } } diff --git a/shader_test.go b/shader_test.go index 1a11d36cc..4f2c34951 100644 --- a/shader_test.go +++ b/shader_test.go @@ -726,3 +726,114 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 { } } } + +func TestShaderUniformMatrix2(t *testing.T) { + const w, h = 16, 16 + + dst := ebiten.NewImage(w, h) + s, err := ebiten.NewShader([]byte(`package main + +var Mat2 mat2 + +func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + return vec4(Mat2 * vec2(1), 1, 1) +} +`)) + if err != nil { + t.Fatal(err) + } + + op := &ebiten.DrawRectShaderOptions{} + op.Uniforms = map[string]interface{}{ + "Mat2": []float32{ + 1.0 / 256.0, 2.0 / 256.0, + 3.0 / 256.0, 4.0 / 256.0, + }, + } + dst.DrawRectShader(w, h, s, op) + + for j := 0; j < h; j++ { + for i := 0; i < w; i++ { + got := dst.At(i, j).(color.RGBA) + want := color.RGBA{4, 6, 0xff, 0xff} + if !sameColors(got, want, 2) { + t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want) + } + } + } +} + +func TestShaderUniformMatrix3(t *testing.T) { + const w, h = 16, 16 + + dst := ebiten.NewImage(w, h) + s, err := ebiten.NewShader([]byte(`package main + +var Mat3 mat3 + +func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + return vec4(Mat3 * vec3(1), 1) +} +`)) + if err != nil { + t.Fatal(err) + } + + op := &ebiten.DrawRectShaderOptions{} + op.Uniforms = map[string]interface{}{ + "Mat3": []float32{ + 1.0 / 256.0, 2.0 / 256.0, 3.0 / 256.0, + 4.0 / 256.0, 5.0 / 256.0, 6.0 / 256.0, + 7.0 / 256.0, 8.0 / 256.0, 9.0 / 256.0, + }, + } + dst.DrawRectShader(w, h, s, op) + + for j := 0; j < h; j++ { + for i := 0; i < w; i++ { + got := dst.At(i, j).(color.RGBA) + want := color.RGBA{12, 15, 18, 0xff} + if !sameColors(got, want, 2) { + t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want) + } + } + } +} + +func TestShaderUniformMatrix4(t *testing.T) { + const w, h = 16, 16 + + dst := ebiten.NewImage(w, h) + s, err := ebiten.NewShader([]byte(`package main + +var Mat4 mat4 + +func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + return Mat4 * vec4(1) +} +`)) + if err != nil { + t.Fatal(err) + } + + op := &ebiten.DrawRectShaderOptions{} + op.Uniforms = map[string]interface{}{ + "Mat4": []float32{ + 1.0 / 256.0, 2.0 / 256.0, 3.0 / 256.0, 4.0 / 256.0, + 5.0 / 256.0, 6.0 / 256.0, 7.0 / 256.0, 8.0 / 256.0, + 9.0 / 256.0, 10.0 / 256.0, 11.0 / 256.0, 12.0 / 256.0, + 13.0 / 256.0, 14.0 / 256.0, 15.0 / 256.0, 16.0 / 256.0, + }, + } + dst.DrawRectShader(w, h, s, op) + + for j := 0; j < h; j++ { + for i := 0; i < w; i++ { + got := dst.At(i, j).(color.RGBA) + want := color.RGBA{28, 32, 36, 40} + if !sameColors(got, want, 2) { + t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want) + } + } + } +}