internal/shader: bug fix: failed to return an array in HLSL

Closes #2923
This commit is contained in:
Hajime Hoshi 2024-03-10 11:40:51 +09:00
parent 927e025982
commit 9a7dcb1077
6 changed files with 98 additions and 51 deletions

View File

@ -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 ret = out[0].typ
out = nil out = nil
} }

View File

@ -1,25 +1,29 @@
uniform vec2 U0[4]; uniform vec2 U0[4];
vec2[2] F0(void); void F0(out vec2 l0[2]);
vec2[2] F1(void); void F1(out vec2 l0[2]);
vec2[2] F0(void) { void F0(out vec2 l0[2]) {
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);
vec2 l1[2]; vec2 l1[2];
l1[0] = vec2(0); l1[0] = vec2(0);
l1[1] = vec2(0); l1[1] = vec2(0);
(l0)[0] = vec2(1.0); l0[0] = l1[0];
l1[0] = l0[0]; l0[1] = l1[1];
l1[1] = l0[1]; return;
(l1)[1] = vec2(2.0); }
return l1;
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;
} }

View File

@ -1,11 +1,12 @@
array<float2, 3> F0(void); void F0(thread array<float2, 3>& l0);
array<float2, 3> F0(void) { void F0(thread array<float2, 3>& l0) {
array<float2, 2> l0 = {}; array<float2, 2> l1 = {};
array<float2, 3> l1 = {}; array<float2, 3> l2 = {};
{ {
array<float2, 2> l1 = {}; array<float2, 2> l2 = {};
l1 = l0; l2 = l1;
} }
return l1; l0 = l2;
return;
} }

View File

@ -1,19 +1,22 @@
vec2[3] F0(void); void F0(out vec2 l0[3]);
vec2[3] F0(void) { void F0(out vec2 l0[3]) {
vec2 l0[2]; vec2 l1[2];
l0[0] = vec2(0);
l0[1] = vec2(0);
vec2 l1[3];
l1[0] = vec2(0); l1[0] = vec2(0);
l1[1] = 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]; vec2 l2[2];
l1[0] = vec2(0); l2[0] = vec2(0);
l1[1] = vec2(0); l2[1] = vec2(0);
l1[0] = l0[0]; l2[0] = l1[0];
l1[1] = l0[1]; l2[1] = l1[1];
} }
return l1; l0[0] = l2[0];
l0[1] = l2[1];
l0[2] = l2[2];
return;
} }

View File

@ -1,16 +1,18 @@
float[1] F0(void); void F0(out float l0[1]);
int[1] F1(void); void F1(out int l0[1]);
float[1] F0(void) { void F0(out float l0[1]) {
float l0[1]; float l1[1];
l0[0] = float(0); l1[0] = float(0);
(l0)[0] = 1.0; (l1)[0] = 1.0;
return l0; l0[0] = l1[0];
return;
} }
int[1] F1(void) { void F1(out int l0[1]) {
int l0[1]; int l1[1];
l0[0] = 0; l1[0] = 0;
(l0)[0] = 1; (l1)[0] = 1;
return l0; l0[0] = l1[0];
return;
} }

View File

@ -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)
}
}
}
}