blob: aee1adc2b4d7d19b9a3389346f8ba95517fb7295 [file]
//
// Copyright 2024 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// WGSLOutput_test.cpp:
// Tests for corect WGSL translations.
//
#include <regex>
#include "GLSLANG/ShaderLang.h"
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "tests/test_utils/compiler_test.h"
using namespace sh;
class WGSLVertexOutputTest : public MatchOutputCodeTest
{
public:
WGSLVertexOutputTest() : MatchOutputCodeTest(GL_VERTEX_SHADER, SH_WGSL_OUTPUT)
{
ShCompileOptions defaultCompileOptions = {};
defaultCompileOptions.validateAST = true;
setDefaultCompileOptions(defaultCompileOptions);
}
};
class WGSLOutputTest : public MatchOutputCodeTest
{
public:
WGSLOutputTest() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_WGSL_OUTPUT)
{
ShCompileOptions defaultCompileOptions = {};
defaultCompileOptions.validateAST = true;
setDefaultCompileOptions(defaultCompileOptions);
}
};
TEST_F(WGSLOutputTest, BasicTranslation)
{
const std::string &shaderString =
R"(#version 310 es
precision highp float;
out vec4 outColor;
struct Foo {
float x;
float y;
vec3 multiArray[2][3];
mat3 aMatrix;
};
vec4 doFoo(Foo foo, float zw);
vec4 doFoo(Foo foo, float zw)
{
// foo.x = foo.y;
return vec4(foo.x, foo.y, zw, zw);
}
Foo returnFoo(Foo foo) {
return foo;
}
float returnFloat(float x) {
return x;
}
float takeArgs(vec2 x, float y) {
return y;
}
void main()
{
Foo foo;
// Struct field accesses.
foo.x = 2.0;
foo.y = 2.0;
// Complicated constUnion should be emitted correctly.
foo.multiArray = vec3[][](
vec3[](
vec3(1.0, 2.0, 3.0),
vec3(1.0, 2.0, 3.0),
vec3(1.0, 2.0, 3.0)),
vec3[](
vec3(4.0, 5.0, 6.0),
vec3(4.0, 5.0, 6.0),
vec3(4.0, 5.0, 6.0)
)
);
int arrIndex = 1;
// Access an array index with a constant index.
float f = foo.multiArray[0][1].x;
// Access an array index with a non-const index, should clamp by default.
float f2 = foo.multiArray[0][arrIndex].x;
gl_FragDepth = f + f2;
doFoo(returnFoo(foo), returnFloat(3.0));
takeArgs(vec2(1.0, 2.0), foo.x);
returnFloat(doFoo(foo, 7.0 + 9.0).x);
outColor = vec4(0.0, 0.0, 0.0, 0.0);
})";
const std::string &outputString =
R"(struct ANGLE_Output_Global {
outColor : vec4<f32>,
gl_FragDepth_ : f32,
};
var<private> ANGLE_output_global : ANGLE_Output_Global;
struct ANGLE_Output_Annotated {
@location(@@@@@@) outColor : vec4<f32>,
@builtin(frag_depth) gl_FragDepth_ : f32,
};
;
struct _uFoo
{
_ux : f32,
_uy : f32,
_umultiArray : array<array<vec3<f32>, 3>, 2>,
_uaMatrix : mat3x3<f32>,
};
fn _udoFoo(_ufoo : _uFoo, _uzw : f32) -> vec4<f32>;
fn _udoFoo(_ufoo : _uFoo, _uzw : f32) -> vec4<f32>
{
return vec4<f32>((_ufoo)._ux, (_ufoo)._uy, _uzw, _uzw);
}
fn _ureturnFoo(_ufoo : _uFoo) -> _uFoo
{
return _ufoo;
}
fn _ureturnFloat(_ux : f32) -> f32
{
return _ux;
}
fn _utakeArgs(_ux : vec2<f32>, _uy : f32) -> f32
{
return _uy;
}
fn _umain()
{
var _ufoo : _uFoo;
((_ufoo)._ux) = (2.0f);
((_ufoo)._uy) = (2.0f);
((_ufoo)._umultiArray) = (array<array<vec3<f32>, 3>, 2>(array<vec3<f32>, 3>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(1.0f, 2.0f, 3.0f)), array<vec3<f32>, 3>(vec3<f32>(4.0f, 5.0f, 6.0f), vec3<f32>(4.0f, 5.0f, 6.0f), vec3<f32>(4.0f, 5.0f, 6.0f))));
var _uarrIndex : i32 = (1i);
var _uf : f32 = (((((_ufoo)._umultiArray)[0i])[1i]).x);
var _uf2 : f32 = (((((_ufoo)._umultiArray)[0i])[clamp((_uarrIndex), 0, 2)]).x);
(ANGLE_output_global.gl_FragDepth_) = ((_uf) + (_uf2));
_udoFoo(_ureturnFoo(_ufoo), _ureturnFloat(3.0f));
_utakeArgs(vec2<f32>(1.0f, 2.0f), (_ufoo)._ux);
_ureturnFloat((_udoFoo(_ufoo, 16.0f)).x);
(ANGLE_output_global.outColor) = (vec4<f32>(0.0f, 0.0f, 0.0f, 0.0f));
}
@fragment
fn wgslMain() -> ANGLE_Output_Annotated
{
_umain();
var ANGLE_output_annotated : ANGLE_Output_Annotated;
ANGLE_output_annotated.outColor = ANGLE_output_global.outColor;
ANGLE_output_annotated.gl_FragDepth_ = ANGLE_output_global.gl_FragDepth_;
return ANGLE_output_annotated;
}
)";
compile(shaderString);
EXPECT_TRUE(foundInCode(outputString.c_str()));
}
TEST_F(WGSLOutputTest, ControlFlow)
{
const std::string &shaderString =
R"(#version 300 es
precision highp float;
int ifElseDemo() {
int x = 5;
if (x == 5) {
return 6;
} else if (x == 6) {
return 7;
} else {
return 8;
}
}
void switchDemo() {
int x = 5;
switch (x) {
case 5:
case 6:
discard;
case 7: {
return;
}
case 8:
case 9:
{
x = 7;
}
return;
default:
return;
}
}
void forLoopDemo() {
for (int i = 0; i < 5; i++) {
if (i == 4) {
break;
} else if (i == 5) {
continue;
}
}
}
void whileLoopDemo() {
int i = 0;
while (i < 5) {
i++;
}
do {
i++;
} while (i < 5);
}
void main()
{
ifElseDemo();
switchDemo();
forLoopDemo();
whileLoopDemo();
})";
const std::string &outputString =
R"(fn _uifElseDemo() -> i32
{
var _ux : i32 = (5i);
if ((_ux) == (5i))
{
return 6i;
}
else
{
if ((_ux) == (6i))
{
return 7i;
}
else
{
return 8i;
}
}
}
fn _uswitchDemo()
{
var _ux : i32 = (5i);
switch _ux
{
case 5i, 6i:
{
discard;
}
case 7i:
{
{
return;
}
}
case 8i, 9i:
{
{
(_ux) = (7i);
}
return;
}
case default:
{
return;
}
}
}
fn _uforLoopDemo()
{
for (var _ui : i32 = (0i); (_ui) < (5i); (_ui)++)
{
if ((_ui) == (4i))
{
break;
}
else
{
if ((_ui) == (5i))
{
continue;
}
}
}
}
fn _uwhileLoopDemo()
{
var _ui : i32 = (0i);
while ((_ui) < (5i))
{
(_ui)++;
}
loop {
{
(_ui)++;
}
if (!((_ui) < (5i)) { break; }
}
}
fn _umain()
{
_uifElseDemo();
_uswitchDemo();
_uforLoopDemo();
_uwhileLoopDemo();
}
@fragment
fn wgslMain()
{
_umain();
}
)";
compile(shaderString);
EXPECT_TRUE(foundInCode(outputString.c_str()));
}
TEST_F(WGSLOutputTest, GLFragColorWithUniform)
{
const std::string &shaderString =
R"(
uniform mediump vec4 u_color;
void main(void)
{
gl_FragColor = u_color;
})";
const std::string &outputString =
R"(struct ANGLE_Output_Global {
gl_FragColor_ : vec4<f32>,
};
var<private> ANGLE_output_global : ANGLE_Output_Global;
struct ANGLE_Output_Annotated {
@location(0) gl_FragColor_ : vec4<f32>,
};
var<uniform> _uu_color : vec4<f32>;
fn _umain()
{
(ANGLE_output_global.gl_FragColor_) = (_uu_color);
}
@fragment
fn wgslMain() -> ANGLE_Output_Annotated
{
_umain();
var ANGLE_output_annotated : ANGLE_Output_Annotated;
ANGLE_output_annotated.gl_FragColor_ = ANGLE_output_global.gl_FragColor_;
return ANGLE_output_annotated;
}
)";
compile(shaderString);
EXPECT_TRUE(foundInCode(outputString.c_str()));
}