From 9a7dcb107770049651ef175fe4380c4f8ab5ba34 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 10 Mar 2024 11:40:51 +0900 Subject: [PATCH] internal/shader: bug fix: failed to return an array in HLSL Closes #2923 --- internal/shader/shader.go | 4 +- internal/shader/testdata/array.expected.vs | 40 ++++++++++--------- .../shader/testdata/array2.expected.metal | 15 +++---- internal/shader/testdata/array2.expected.vs | 29 ++++++++------ .../shader/testdata/issue2840.expected.vs | 26 ++++++------ shader_test.go | 35 ++++++++++++++++ 6 files changed, 98 insertions(+), 51 deletions(-) diff --git a/internal/shader/shader.go b/internal/shader/shader.go index 90ed2d611..12626b12d 100644 --- a/internal/shader/shader.go +++ b/internal/shader/shader.go @@ -740,7 +740,9 @@ func (cs *compileState) parseFuncParams(block *block, fname string, d *ast.FuncD } } - if len(out) == 1 && out[0].name == "" { + // If there is only one returning value, it is treated as a returning value. + // An array cannot be a returning value, especially for HLSL (#2923). + if len(out) == 1 && out[0].name == "" && out[0].typ.Main != shaderir.Array { ret = out[0].typ out = nil } diff --git a/internal/shader/testdata/array.expected.vs b/internal/shader/testdata/array.expected.vs index c098256b1..0b1cf4699 100644 --- a/internal/shader/testdata/array.expected.vs +++ b/internal/shader/testdata/array.expected.vs @@ -1,25 +1,29 @@ uniform vec2 U0[4]; -vec2[2] F0(void); -vec2[2] F1(void); +void F0(out vec2 l0[2]); +void F1(out vec2 l0[2]); -vec2[2] F0(void) { - vec2 l0[2]; - l0[0] = vec2(0); - l0[1] = vec2(0); - return l0; -} - -vec2[2] F1(void) { - vec2 l0[2]; - l0[0] = vec2(0); - l0[1] = vec2(0); +void F0(out vec2 l0[2]) { vec2 l1[2]; l1[0] = vec2(0); l1[1] = vec2(0); - (l0)[0] = vec2(1.0); - l1[0] = l0[0]; - l1[1] = l0[1]; - (l1)[1] = vec2(2.0); - return l1; + l0[0] = l1[0]; + l0[1] = l1[1]; + return; +} + +void F1(out vec2 l0[2]) { + vec2 l1[2]; + l1[0] = vec2(0); + l1[1] = vec2(0); + vec2 l2[2]; + l2[0] = vec2(0); + l2[1] = vec2(0); + (l1)[0] = vec2(1.0); + l2[0] = l1[0]; + l2[1] = l1[1]; + (l2)[1] = vec2(2.0); + l0[0] = l2[0]; + l0[1] = l2[1]; + return; } diff --git a/internal/shader/testdata/array2.expected.metal b/internal/shader/testdata/array2.expected.metal index 8173104d1..1ef317379 100644 --- a/internal/shader/testdata/array2.expected.metal +++ b/internal/shader/testdata/array2.expected.metal @@ -1,11 +1,12 @@ -array F0(void); +void F0(thread array& l0); -array F0(void) { - array l0 = {}; - array l1 = {}; +void F0(thread array& l0) { + array l1 = {}; + array l2 = {}; { - array l1 = {}; - l1 = l0; + array l2 = {}; + l2 = l1; } - return l1; + l0 = l2; + return; } diff --git a/internal/shader/testdata/array2.expected.vs b/internal/shader/testdata/array2.expected.vs index 9d8837dbb..1c89be5ea 100644 --- a/internal/shader/testdata/array2.expected.vs +++ b/internal/shader/testdata/array2.expected.vs @@ -1,19 +1,22 @@ -vec2[3] F0(void); +void F0(out vec2 l0[3]); -vec2[3] F0(void) { - vec2 l0[2]; - l0[0] = vec2(0); - l0[1] = vec2(0); - vec2 l1[3]; +void F0(out vec2 l0[3]) { + vec2 l1[2]; l1[0] = vec2(0); l1[1] = vec2(0); - l1[2] = vec2(0); + vec2 l2[3]; + l2[0] = vec2(0); + l2[1] = vec2(0); + l2[2] = vec2(0); { - vec2 l1[2]; - l1[0] = vec2(0); - l1[1] = vec2(0); - l1[0] = l0[0]; - l1[1] = l0[1]; + vec2 l2[2]; + l2[0] = vec2(0); + l2[1] = vec2(0); + l2[0] = l1[0]; + l2[1] = l1[1]; } - return l1; + l0[0] = l2[0]; + l0[1] = l2[1]; + l0[2] = l2[2]; + return; } diff --git a/internal/shader/testdata/issue2840.expected.vs b/internal/shader/testdata/issue2840.expected.vs index 1b4e506ae..2af784fe9 100644 --- a/internal/shader/testdata/issue2840.expected.vs +++ b/internal/shader/testdata/issue2840.expected.vs @@ -1,16 +1,18 @@ -float[1] F0(void); -int[1] F1(void); +void F0(out float l0[1]); +void F1(out int l0[1]); -float[1] F0(void) { - float l0[1]; - l0[0] = float(0); - (l0)[0] = 1.0; - return l0; +void F0(out float l0[1]) { + float l1[1]; + l1[0] = float(0); + (l1)[0] = 1.0; + l0[0] = l1[0]; + return; } -int[1] F1(void) { - int l0[1]; - l0[0] = 0; - (l0)[0] = 1; - return l0; +void F1(out int l0[1]) { + int l1[1]; + l1[0] = 0; + (l1)[0] = 1; + l0[0] = l1[0]; + return; } diff --git a/shader_test.go b/shader_test.go index 023be864d..6af4ebd6e 100644 --- a/shader_test.go +++ b/shader_test.go @@ -2394,3 +2394,38 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 { } } } + +// Issue #2923 +func TestShaderReturnArray(t *testing.T) { + const w, h = 16, 16 + + dst := ebiten.NewImage(w, h) + s, err := ebiten.NewShader([]byte(`//kage:unit pixels + +package main + +func foo() [4]float { + return [4]float{0.25, 0.5, 0.75, 1} +} + +func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 { + a := foo() + return vec4(a[0], a[1], a[2], a[3]) +} +`)) + if err != nil { + t.Fatal(err) + } + + dst.DrawRectShader(w, h, s, nil) + + for j := 0; j < h; j++ { + for i := 0; i < w; i++ { + got := dst.At(i, j).(color.RGBA) + want := color.RGBA{R: 0x40, G: 0x80, B: 0xc0, A: 0xff} + if !sameColors(got, want, 2) { + t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want) + } + } + } +}