GLSL: Implement 1D texture emulation for ES.

ES does not support 1D images at all. Fake it by promoting 1D images to
2D.
This commit is contained in:
Hans-Kristian Arntzen 2022-05-27 11:51:34 +02:00
parent 3f855646f0
commit 1c88730e12
6 changed files with 172 additions and 7 deletions

View File

@ -0,0 +1,30 @@
#version 310 es
precision mediump float;
precision highp int;
layout(binding = 0) uniform highp sampler2D uSamp;
layout(binding = 1) uniform highp sampler2DShadow uSampShadow;
layout(binding = 2) uniform highp sampler2DArray uSampArray;
layout(binding = 3) uniform highp sampler2DArrayShadow uSampArrayShadow;
layout(binding = 4, r32f) uniform highp image2D uImage;
layout(location = 0) out highp vec4 FragColor;
layout(location = 0) in highp vec4 vUV;
void main()
{
FragColor = texture(uSamp, vec2(vUV.x, 0.0));
FragColor += textureProj(uSamp, vec3(vUV.xy.x, 0.0, vUV.xy.y));
FragColor += texelFetch(uSamp, ivec2(int(vUV.x), 0), 0);
FragColor += vec4(texture(uSampShadow, vec3(vUV.xyz.x, 0.0, vUV.xyz.z)));
highp vec4 _54 = vUV;
highp vec4 _57 = _54;
_57.y = _54.w;
FragColor += vec4(textureProj(uSampShadow, vec4(_57.x, 0.0, _54.z, _57.y)));
FragColor = texture(uSampArray, vec3(vUV.xy.x, 0.0, vUV.xy.y));
FragColor += texelFetch(uSampArray, ivec3(ivec2(vUV.xy).x, 0, ivec2(vUV.xy).y), 0);
FragColor += vec4(texture(uSampArrayShadow, vec4(vUV.xyz.xy.x, 0.0, vUV.xyz.xy.y, vUV.xyz.z)));
FragColor += imageLoad(uImage, ivec2(int(vUV.x), 0));
imageStore(uImage, ivec2(int(vUV.x), 0), FragColor);
}

View File

@ -0,0 +1,21 @@
#version 100
#extension GL_EXT_shadow_samplers : require
precision mediump float;
precision highp int;
uniform highp sampler2D uSamp;
uniform highp sampler2DShadow uSampShadow;
varying highp vec4 vUV;
void main()
{
gl_FragData[0] = texture2D(uSamp, vec2(vUV.x, 0.0));
gl_FragData[0] += texture2DProj(uSamp, vec3(vUV.xy.x, 0.0, vUV.xy.y));
gl_FragData[0] += vec4(shadow2DEXT(uSampShadow, vec3(vUV.xyz.x, 0.0, vUV.xyz.z)));
highp vec4 _44 = vUV;
highp vec4 _47 = _44;
_47.y = _44.w;
gl_FragData[0] += vec4(shadow2DProjEXT(uSampShadow, vec4(_47.x, 0.0, _44.z, _47.y)));
}

View File

@ -0,0 +1,32 @@
#version 450
layout(set = 0, binding = 0) uniform sampler1D uSamp;
layout(set = 0, binding = 1) uniform sampler1DShadow uSampShadow;
layout(set = 0, binding = 2) uniform sampler1DArray uSampArray;
layout(set = 0, binding = 3) uniform sampler1DArrayShadow uSampArrayShadow;
layout(set = 0, binding = 4, r32f) uniform image1D uImage;
layout(location = 0) in vec4 vUV;
layout(location = 0) out vec4 FragColor;
void main()
{
// 1D
FragColor = texture(uSamp, vUV.x);
FragColor += textureProj(uSamp, vUV.xy);
FragColor += texelFetch(uSamp, int(vUV.x), 0);
// 1D Shadow
FragColor += texture(uSampShadow, vUV.xyz);
FragColor += textureProj(uSampShadow, vUV);
// 1D Array
FragColor = texture(uSampArray, vUV.xy);
FragColor += texelFetch(uSampArray, ivec2(vUV.xy), 0);
// 1D Array Shadow
FragColor += texture(uSampArrayShadow, vUV.xyz);
// 1D images
FragColor += imageLoad(uImage, int(vUV.x));
imageStore(uImage, int(vUV.x), FragColor);
}

View File

@ -0,0 +1,17 @@
#version 450
layout(set = 0, binding = 0) uniform sampler1D uSamp;
layout(set = 0, binding = 1) uniform sampler1DShadow uSampShadow;
layout(location = 0) in vec4 vUV;
layout(location = 0) out vec4 FragColor;
void main()
{
// 1D
FragColor = texture(uSamp, vUV.x);
FragColor += textureProj(uSamp, vUV.xy);
// 1D Shadow
FragColor += texture(uSampShadow, vUV.xyz);
FragColor += textureProj(uSampShadow, vUV);
}

View File

@ -6340,7 +6340,11 @@ string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtyp
switch (imgtype.image.dim)
{
case spv::Dim1D:
type = (imgtype.image.arrayed && !options.es) ? "1DArray" : "1D";
// Force 2D path for ES.
if (options.es)
type = (imgtype.image.arrayed && !options.es) ? "2DArray" : "2D";
else
type = (imgtype.image.arrayed && !options.es) ? "1DArray" : "1D";
break;
case spv::Dim2D:
type = (imgtype.image.arrayed && !options.es) ? "2DArray" : "2D";
@ -7018,8 +7022,8 @@ std::string CompilerGLSL::to_texture_op(const Instruction &i, bool sparse, bool
expr += to_function_args(args, forward);
expr += ")";
// texture(samplerXShadow) returns float. shadowX() returns vec4. Swizzle here.
if (is_legacy() && is_depth_image(imgtype, img))
// texture(samplerXShadow) returns float. shadowX() returns vec4, but only in desktop GLSL. Swizzle here.
if (is_legacy() && !options.es && is_depth_image(imgtype, img))
expr += ".r";
// Sampling from a texture which was deduced to be a depth image, might actually return 1 component here.
@ -7300,10 +7304,29 @@ string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool
// Create a composite which merges coord/dref into a single vector.
auto type = expression_type(args.coord);
type.vecsize = args.coord_components + 1;
if (imgtype.image.dim == Dim1D && options.es)
type.vecsize++;
farg_str += ", ";
farg_str += type_to_glsl_constructor(type);
farg_str += "(";
farg_str += coord_expr;
if (imgtype.image.dim == Dim1D && options.es)
{
if (imgtype.image.arrayed)
{
farg_str += enclose_expression(coord_expr) + ".x";
farg_str += ", 0.0, ";
farg_str += enclose_expression(coord_expr) + ".y";
}
else
{
farg_str += coord_expr;
farg_str += ", 0.0";
}
}
else
farg_str += coord_expr;
farg_str += ", ";
farg_str += to_expression(args.dref);
farg_str += ")";
@ -7311,6 +7334,33 @@ string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool
}
else
{
if (imgtype.image.dim == Dim1D && options.es)
{
// Have to fake a second coordinate.
if (type_is_floating_point(coord_type))
{
// Cannot mix proj and array.
if (imgtype.image.arrayed || args.base.is_proj)
{
coord_expr = join("vec3(", enclose_expression(coord_expr), ".x, 0.0, ",
enclose_expression(coord_expr), ".y)");
}
else
coord_expr = join("vec2(", coord_expr, ", 0.0)");
}
else
{
if (imgtype.image.arrayed)
{
coord_expr = join("ivec3(", enclose_expression(coord_expr),
".x, 0, ",
enclose_expression(coord_expr), ".y)");
}
else
coord_expr = join("ivec2(", coord_expr, ", 0)");
}
}
farg_str += ", ";
farg_str += coord_expr;
}
@ -12484,6 +12534,10 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
target_coord_type.basetype = SPIRType::Int;
coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr);
// ES needs to emulate 1D images as 2D.
if (type.image.dim == Dim1D && options.es)
coord_expr = join("ivec2(", coord_expr, ", 0)");
// Plain image load/store.
if (sparse)
{
@ -12596,6 +12650,10 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
target_coord_type.basetype = SPIRType::Int;
coord_expr = bitcast_expression(target_coord_type, expression_type(ops[1]).basetype, coord_expr);
// ES needs to emulate 1D images as 2D.
if (type.image.dim == Dim1D && options.es)
coord_expr = join("ivec2(", coord_expr, ", 0)");
if (type.image.ms)
{
uint32_t operands = ops[3];
@ -13956,7 +14014,8 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id)
switch (type.image.dim)
{
case Dim1D:
res += "1D";
// ES doesn't support 1D. Fake it with 2D.
res += options.es ? "2D" : "1D";
break;
case Dim2D:
res += "2D";

View File

@ -537,7 +537,7 @@ def validate_shader(shader, vulkan, paths):
else:
subprocess.check_call([paths.glslang, shader])
def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, opt, push_ubo, iterations, paths):
def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, force_es, flatten_ubo, sso, flatten_dim, opt, push_ubo, iterations, paths):
spirv_path = create_temporary()
glsl_path = create_temporary(os.path.basename(shader))
@ -576,6 +576,8 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl
extra_args += ['--remove-unused-variables']
if is_legacy:
extra_args += ['--version', '100', '--es']
if force_es:
extra_args += ['--version', '310', '--es']
if flatten_ubo:
extra_args += ['--flatten-ubo']
if sso:
@ -768,6 +770,9 @@ def shader_is_invalid_spirv(shader):
def shader_is_legacy(shader):
return '.legacy.' in shader
def shader_is_force_es(shader):
return '.es.' in shader
def shader_is_flatten_ubo(shader):
return '.flatten.' in shader
@ -791,6 +796,7 @@ def test_shader(stats, shader, args, paths):
is_spirv = shader_is_spirv(shader[1])
invalid_spirv = shader_is_invalid_spirv(shader[1])
is_legacy = shader_is_legacy(shader[1])
force_es = shader_is_force_es(shader[1])
flatten_ubo = shader_is_flatten_ubo(shader[1])
sso = shader_is_sso(shader[1])
flatten_dim = shader_is_flatten_dimensions(shader[1])
@ -798,7 +804,7 @@ def test_shader(stats, shader, args, paths):
push_ubo = shader_is_push_ubo(shader[1])
print('Testing shader:', joined_path)
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, is_spirv, invalid_spirv, eliminate, is_legacy, flatten_ubo, sso, flatten_dim, args.opt and (not noopt), push_ubo, args.iterations, paths)
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, is_spirv, invalid_spirv, eliminate, is_legacy, force_es, flatten_ubo, sso, flatten_dim, args.opt and (not noopt), push_ubo, args.iterations, paths)
# Only test GLSL stats if we have a shader following GL semantics.
if stats and (not vulkan) and (not is_spirv) and (not desktop):