Commit 77637f2d by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Generate xfb support code in SPIR-V for emulation path

This change moves the code generation at link time from source code to SPIR-V. As a result, transform feedback extension and emulation paths are more similarly handled before SPIR-V transformation (they both store information identically in the ShaderInterfaceVariableInfoMap). This change gets rid of the @@ XFB-OUT @@ marker. With no source code generation at link time, shader compilation can be moved to glCompileShader time. Bug: angleproject:4888 Change-Id: I8cdb89c22b57ce48cf5d226b8e41622d9d550d46 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2713269 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent b3fb450c
...@@ -892,6 +892,7 @@ extern const char kLineRasterEmulationPosition[]; ...@@ -892,6 +892,7 @@ extern const char kLineRasterEmulationPosition[];
// Transform feedback emulation support // Transform feedback emulation support
extern const char kXfbEmulationGetOffsetsFunctionName[]; extern const char kXfbEmulationGetOffsetsFunctionName[];
extern const char kXfbEmulationCaptureFunctionName[];
extern const char kXfbEmulationBufferBlockName[]; extern const char kXfbEmulationBufferBlockName[];
extern const char kXfbEmulationBufferName[]; extern const char kXfbEmulationBufferName[];
extern const char kXfbEmulationBufferFieldName[]; extern const char kXfbEmulationBufferFieldName[];
......
{ {
"src/common/gen_uniform_type_table.py": "src/common/gen_uniform_type_table.py":
"f1f6e52f3897773667c714c8da626122", "714cdb13f7c30af4890922a856456ddb",
"src/common/uniform_type_info_autogen.cpp": "src/common/uniform_type_info_autogen.cpp":
"4903e2a4c6c34e65b0f0c0d6eb2b470d" "85b351f2d5525d1af422a880e361a2bd"
} }
\ No newline at end of file
...@@ -101,7 +101,7 @@ const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType) ...@@ -101,7 +101,7 @@ const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType)
}} // namespace gl }} // namespace gl
""" """
type_info_data_template = """{{{type}, {component_type}, {texture_type}, {transposed_type}, {bool_type}, {sampler_format}, {rows}, {columns}, {components}, {component_size}, {internal_size}, {external_size}, {is_sampler}, {is_matrix}, {is_image}, {glsl_asfloat} }}""" type_info_data_template = """{{{type}, {component_type}, {texture_type}, {transposed_type}, {bool_type}, {sampler_format}, {rows}, {columns}, {components}, {component_size}, {internal_size}, {external_size}, {is_sampler}, {is_matrix}, {is_image} }}"""
type_index_case_template = """case {enum_value}: return {index_value};""" type_index_case_template = """case {enum_value}: return {index_value};"""
...@@ -224,22 +224,6 @@ def get_is_image(uniform_type): ...@@ -224,22 +224,6 @@ def get_is_image(uniform_type):
return cpp_bool("_VIDEO_" not in uniform_type and "_IMAGE_" in uniform_type) return cpp_bool("_VIDEO_" not in uniform_type and "_IMAGE_" in uniform_type)
def get_glsl_asfloat(uniform_type):
component_type = get_component_type(uniform_type)
if component_type == "GL_BOOL":
return '""'
elif component_type == "GL_FLOAT":
return '""'
elif component_type == "GL_INT":
return '"intBitsToFloat"'
elif component_type == "GL_UNSIGNED_INT":
return '"uintBitsToFloat"'
elif component_type == "GL_NONE":
return '""'
else:
raise "Invalid component type: " + component_type
def gen_type_info(uniform_type): def gen_type_info(uniform_type):
return type_info_data_template.format( return type_info_data_template.format(
type=uniform_type, type=uniform_type,
...@@ -256,8 +240,7 @@ def gen_type_info(uniform_type): ...@@ -256,8 +240,7 @@ def gen_type_info(uniform_type):
external_size=get_external_size(uniform_type), external_size=get_external_size(uniform_type),
is_sampler=get_is_sampler(uniform_type), is_sampler=get_is_sampler(uniform_type),
is_matrix=get_is_matrix(uniform_type), is_matrix=get_is_matrix(uniform_type),
is_image=get_is_image(uniform_type), is_image=get_is_image(uniform_type))
glsl_asfloat=get_glsl_asfloat(uniform_type))
def gen_type_index_case(index, uniform_type): def gen_type_index_case(index, uniform_type):
......
...@@ -20,203 +20,189 @@ namespace ...@@ -20,203 +20,189 @@ namespace
{ {
constexpr std::array<UniformTypeInfo, 77> kInfoTable = { constexpr std::array<UniformTypeInfo, 77> kInfoTable = {
{{GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 0, 0, 0, 0, 0 * 0, {{GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 0, 0, 0, 0, 0 * 0,
0 * 0, false, false, false, ""}, 0 * 0, false, false, false},
{GL_BOOL, GL_BOOL, GL_NONE, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1, 1, 1, {GL_BOOL, GL_BOOL, GL_NONE, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1, 1, 1,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, false, ""}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, false},
{GL_BOOL_VEC2, GL_BOOL, GL_NONE, GL_NONE, GL_BOOL_VEC2, SamplerFormat::InvalidEnum, 1, 2, 2, {GL_BOOL_VEC2, GL_BOOL, GL_NONE, GL_NONE, GL_BOOL_VEC2, SamplerFormat::InvalidEnum, 1, 2, 2,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 2, false, false, false, ""}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 2, false, false, false},
{GL_BOOL_VEC3, GL_BOOL, GL_NONE, GL_NONE, GL_BOOL_VEC3, SamplerFormat::InvalidEnum, 1, 3, 3, {GL_BOOL_VEC3, GL_BOOL, GL_NONE, GL_NONE, GL_BOOL_VEC3, SamplerFormat::InvalidEnum, 1, 3, 3,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 3, false, false, false, ""}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 3, false, false, false},
{GL_BOOL_VEC4, GL_BOOL, GL_NONE, GL_NONE, GL_BOOL_VEC4, SamplerFormat::InvalidEnum, 1, 4, 4, {GL_BOOL_VEC4, GL_BOOL, GL_NONE, GL_NONE, GL_BOOL_VEC4, SamplerFormat::InvalidEnum, 1, 4, 4,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 4, false, false, false, ""}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 4, false, false, false},
{GL_FLOAT, GL_FLOAT, GL_NONE, GL_NONE, GL_BOOL, SamplerFormat::InvalidEnum, 1, 1, 1, {GL_FLOAT, GL_FLOAT, GL_NONE, GL_NONE, GL_BOOL, SamplerFormat::InvalidEnum, 1, 1, 1,
sizeof(GLfloat), sizeof(GLfloat) * 4, sizeof(GLfloat) * 1, false, false, false, ""}, sizeof(GLfloat), sizeof(GLfloat) * 4, sizeof(GLfloat) * 1, false, false, false},
{GL_FLOAT_MAT2, GL_FLOAT, GL_NONE, GL_FLOAT_MAT2, GL_NONE, SamplerFormat::InvalidEnum, 2, 2, 4, {GL_FLOAT_MAT2, GL_FLOAT, GL_NONE, GL_FLOAT_MAT2, GL_NONE, SamplerFormat::InvalidEnum, 2, 2, 4,
sizeof(GLfloat), sizeof(GLfloat) * 8, sizeof(GLfloat) * 4, false, true, false, ""}, sizeof(GLfloat), sizeof(GLfloat) * 8, sizeof(GLfloat) * 4, false, true, false},
{GL_FLOAT_MAT2x3, GL_FLOAT, GL_NONE, GL_FLOAT_MAT3x2, GL_NONE, SamplerFormat::InvalidEnum, 3, {GL_FLOAT_MAT2x3, GL_FLOAT, GL_NONE, GL_FLOAT_MAT3x2, GL_NONE, SamplerFormat::InvalidEnum, 3,
2, 6, sizeof(GLfloat), sizeof(GLfloat) * 12, sizeof(GLfloat) * 6, false, true, false, ""}, 2, 6, sizeof(GLfloat), sizeof(GLfloat) * 12, sizeof(GLfloat) * 6, false, true, false},
{GL_FLOAT_MAT2x4, GL_FLOAT, GL_NONE, GL_FLOAT_MAT4x2, GL_NONE, SamplerFormat::InvalidEnum, 4, {GL_FLOAT_MAT2x4, GL_FLOAT, GL_NONE, GL_FLOAT_MAT4x2, GL_NONE, SamplerFormat::InvalidEnum, 4,
2, 8, sizeof(GLfloat), sizeof(GLfloat) * 16, sizeof(GLfloat) * 8, false, true, false, ""}, 2, 8, sizeof(GLfloat), sizeof(GLfloat) * 16, sizeof(GLfloat) * 8, false, true, false},
{GL_FLOAT_MAT3, GL_FLOAT, GL_NONE, GL_FLOAT_MAT3, GL_NONE, SamplerFormat::InvalidEnum, 3, 3, 9, {GL_FLOAT_MAT3, GL_FLOAT, GL_NONE, GL_FLOAT_MAT3, GL_NONE, SamplerFormat::InvalidEnum, 3, 3, 9,
sizeof(GLfloat), sizeof(GLfloat) * 12, sizeof(GLfloat) * 9, false, true, false, ""}, sizeof(GLfloat), sizeof(GLfloat) * 12, sizeof(GLfloat) * 9, false, true, false},
{GL_FLOAT_MAT3x2, GL_FLOAT, GL_NONE, GL_FLOAT_MAT2x3, GL_NONE, SamplerFormat::InvalidEnum, 2, {GL_FLOAT_MAT3x2, GL_FLOAT, GL_NONE, GL_FLOAT_MAT2x3, GL_NONE, SamplerFormat::InvalidEnum, 2,
3, 6, sizeof(GLfloat), sizeof(GLfloat) * 8, sizeof(GLfloat) * 6, false, true, false, ""}, 3, 6, sizeof(GLfloat), sizeof(GLfloat) * 8, sizeof(GLfloat) * 6, false, true, false},
{GL_FLOAT_MAT3x4, GL_FLOAT, GL_NONE, GL_FLOAT_MAT4x3, GL_NONE, SamplerFormat::InvalidEnum, 4, {GL_FLOAT_MAT3x4, GL_FLOAT, GL_NONE, GL_FLOAT_MAT4x3, GL_NONE, SamplerFormat::InvalidEnum, 4,
3, 12, sizeof(GLfloat), sizeof(GLfloat) * 16, sizeof(GLfloat) * 12, false, true, false, ""}, 3, 12, sizeof(GLfloat), sizeof(GLfloat) * 16, sizeof(GLfloat) * 12, false, true, false},
{GL_FLOAT_MAT4, GL_FLOAT, GL_NONE, GL_FLOAT_MAT4, GL_NONE, SamplerFormat::InvalidEnum, 4, 4, {GL_FLOAT_MAT4, GL_FLOAT, GL_NONE, GL_FLOAT_MAT4, GL_NONE, SamplerFormat::InvalidEnum, 4, 4,
16, sizeof(GLfloat), sizeof(GLfloat) * 16, sizeof(GLfloat) * 16, false, true, false, ""}, 16, sizeof(GLfloat), sizeof(GLfloat) * 16, sizeof(GLfloat) * 16, false, true, false},
{GL_FLOAT_MAT4x2, GL_FLOAT, GL_NONE, GL_FLOAT_MAT2x4, GL_NONE, SamplerFormat::InvalidEnum, 2, {GL_FLOAT_MAT4x2, GL_FLOAT, GL_NONE, GL_FLOAT_MAT2x4, GL_NONE, SamplerFormat::InvalidEnum, 2,
4, 8, sizeof(GLfloat), sizeof(GLfloat) * 8, sizeof(GLfloat) * 8, false, true, false, ""}, 4, 8, sizeof(GLfloat), sizeof(GLfloat) * 8, sizeof(GLfloat) * 8, false, true, false},
{GL_FLOAT_MAT4x3, GL_FLOAT, GL_NONE, GL_FLOAT_MAT3x4, GL_NONE, SamplerFormat::InvalidEnum, 3, {GL_FLOAT_MAT4x3, GL_FLOAT, GL_NONE, GL_FLOAT_MAT3x4, GL_NONE, SamplerFormat::InvalidEnum, 3,
4, 12, sizeof(GLfloat), sizeof(GLfloat) * 12, sizeof(GLfloat) * 12, false, true, false, ""}, 4, 12, sizeof(GLfloat), sizeof(GLfloat) * 12, sizeof(GLfloat) * 12, false, true, false},
{GL_FLOAT_VEC2, GL_FLOAT, GL_NONE, GL_NONE, GL_BOOL_VEC2, SamplerFormat::InvalidEnum, 1, 2, 2, {GL_FLOAT_VEC2, GL_FLOAT, GL_NONE, GL_NONE, GL_BOOL_VEC2, SamplerFormat::InvalidEnum, 1, 2, 2,
sizeof(GLfloat), sizeof(GLfloat) * 4, sizeof(GLfloat) * 2, false, false, false, ""}, sizeof(GLfloat), sizeof(GLfloat) * 4, sizeof(GLfloat) * 2, false, false, false},
{GL_FLOAT_VEC3, GL_FLOAT, GL_NONE, GL_NONE, GL_BOOL_VEC3, SamplerFormat::InvalidEnum, 1, 3, 3, {GL_FLOAT_VEC3, GL_FLOAT, GL_NONE, GL_NONE, GL_BOOL_VEC3, SamplerFormat::InvalidEnum, 1, 3, 3,
sizeof(GLfloat), sizeof(GLfloat) * 4, sizeof(GLfloat) * 3, false, false, false, ""}, sizeof(GLfloat), sizeof(GLfloat) * 4, sizeof(GLfloat) * 3, false, false, false},
{GL_FLOAT_VEC4, GL_FLOAT, GL_NONE, GL_NONE, GL_BOOL_VEC4, SamplerFormat::InvalidEnum, 1, 4, 4, {GL_FLOAT_VEC4, GL_FLOAT, GL_NONE, GL_NONE, GL_BOOL_VEC4, SamplerFormat::InvalidEnum, 1, 4, 4,
sizeof(GLfloat), sizeof(GLfloat) * 4, sizeof(GLfloat) * 4, false, false, false, ""}, sizeof(GLfloat), sizeof(GLfloat) * 4, sizeof(GLfloat) * 4, false, false, false},
{GL_IMAGE_2D, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1, 1, 1, {GL_IMAGE_2D, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1, 1, 1,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true},
{GL_IMAGE_2D_ARRAY, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, {GL_IMAGE_2D_ARRAY, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum,
1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true},
"intBitsToFloat"},
{GL_IMAGE_3D, GL_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1, 1, 1, {GL_IMAGE_3D, GL_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1, 1, 1,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true},
{GL_IMAGE_CUBE, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1, {GL_IMAGE_CUBE, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1,
1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true},
"intBitsToFloat"},
{GL_IMAGE_CUBE_MAP_ARRAY, GL_INT, GL_TEXTURE_CUBE_MAP_ARRAY, GL_NONE, GL_NONE, {GL_IMAGE_CUBE_MAP_ARRAY, GL_INT, GL_TEXTURE_CUBE_MAP_ARRAY, GL_NONE, GL_NONE,
SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1,
false, false, true, "intBitsToFloat"}, false, false, true},
{GL_IMAGE_BUFFER, GL_INT, GL_TEXTURE_BUFFER, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1, {GL_IMAGE_BUFFER, GL_INT, GL_TEXTURE_BUFFER, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1,
1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true},
"intBitsToFloat"},
{GL_INT, GL_INT, GL_NONE, GL_NONE, GL_BOOL, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLint), {GL_INT, GL_INT, GL_NONE, GL_NONE, GL_BOOL, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLint),
sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, false, "intBitsToFloat"}, sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, false},
{GL_INT_IMAGE_2D, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1, 1, 1, {GL_INT_IMAGE_2D, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1, 1, 1,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true},
{GL_INT_IMAGE_2D_ARRAY, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, {GL_INT_IMAGE_2D_ARRAY, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE,
SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1,
false, false, true, "intBitsToFloat"}, false, false, true},
{GL_INT_IMAGE_3D, GL_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1, 1, 1, {GL_INT_IMAGE_3D, GL_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, 1, 1, 1,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true},
{GL_INT_IMAGE_CUBE, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, {GL_INT_IMAGE_CUBE, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum,
1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true},
"intBitsToFloat"},
{GL_INT_IMAGE_CUBE_MAP_ARRAY, GL_INT, GL_TEXTURE_CUBE_MAP_ARRAY, GL_NONE, GL_NONE, {GL_INT_IMAGE_CUBE_MAP_ARRAY, GL_INT, GL_TEXTURE_CUBE_MAP_ARRAY, GL_NONE, GL_NONE,
SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1,
false, false, true, "intBitsToFloat"}, false, false, true},
{GL_INT_IMAGE_BUFFER, GL_INT, GL_TEXTURE_BUFFER, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum, {GL_INT_IMAGE_BUFFER, GL_INT, GL_TEXTURE_BUFFER, GL_NONE, GL_NONE, SamplerFormat::InvalidEnum,
1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true},
"intBitsToFloat"},
{GL_INT_SAMPLER_2D, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, SamplerFormat::Signed, 1, 1, 1, {GL_INT_SAMPLER_2D, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, SamplerFormat::Signed, 1, 1, 1,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
{GL_INT_SAMPLER_2D_ARRAY, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, SamplerFormat::Signed, {GL_INT_SAMPLER_2D_ARRAY, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, SamplerFormat::Signed,
1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
"intBitsToFloat"},
{GL_INT_SAMPLER_2D_MULTISAMPLE, GL_INT, GL_TEXTURE_2D_MULTISAMPLE, GL_NONE, GL_NONE, {GL_INT_SAMPLER_2D_MULTISAMPLE, GL_INT, GL_TEXTURE_2D_MULTISAMPLE, GL_NONE, GL_NONE,
SamplerFormat::Signed, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, SamplerFormat::Signed, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true,
false, false, "intBitsToFloat"}, false, false},
{GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, GL_INT, GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_NONE, {GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, GL_INT, GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_NONE,
GL_NONE, SamplerFormat::Signed, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, GL_NONE, SamplerFormat::Signed, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1,
true, false, false, "intBitsToFloat"}, true, false, false},
{GL_INT_SAMPLER_3D, GL_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, SamplerFormat::Signed, 1, 1, 1, {GL_INT_SAMPLER_3D, GL_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, SamplerFormat::Signed, 1, 1, 1,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
{GL_INT_SAMPLER_CUBE, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, SamplerFormat::Signed, 1, {GL_INT_SAMPLER_CUBE, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, SamplerFormat::Signed, 1,
1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
"intBitsToFloat"},
{GL_INT_SAMPLER_CUBE_MAP_ARRAY, GL_INT, GL_TEXTURE_CUBE_MAP_ARRAY, GL_NONE, GL_NONE, {GL_INT_SAMPLER_CUBE_MAP_ARRAY, GL_INT, GL_TEXTURE_CUBE_MAP_ARRAY, GL_NONE, GL_NONE,
SamplerFormat::Signed, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, SamplerFormat::Signed, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true,
false, false, "intBitsToFloat"}, false, false},
{GL_INT_SAMPLER_BUFFER, GL_INT, GL_TEXTURE_BUFFER, GL_NONE, GL_NONE, SamplerFormat::Signed, 1, {GL_INT_SAMPLER_BUFFER, GL_INT, GL_TEXTURE_BUFFER, GL_NONE, GL_NONE, SamplerFormat::Signed, 1,
1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
"intBitsToFloat"},
{GL_INT_VEC2, GL_INT, GL_NONE, GL_NONE, GL_BOOL_VEC2, SamplerFormat::InvalidEnum, 1, 2, 2, {GL_INT_VEC2, GL_INT, GL_NONE, GL_NONE, GL_BOOL_VEC2, SamplerFormat::InvalidEnum, 1, 2, 2,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 2, false, false, false, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 2, false, false, false},
{GL_INT_VEC3, GL_INT, GL_NONE, GL_NONE, GL_BOOL_VEC3, SamplerFormat::InvalidEnum, 1, 3, 3, {GL_INT_VEC3, GL_INT, GL_NONE, GL_NONE, GL_BOOL_VEC3, SamplerFormat::InvalidEnum, 1, 3, 3,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 3, false, false, false, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 3, false, false, false},
{GL_INT_VEC4, GL_INT, GL_NONE, GL_NONE, GL_BOOL_VEC4, SamplerFormat::InvalidEnum, 1, 4, 4, {GL_INT_VEC4, GL_INT, GL_NONE, GL_NONE, GL_BOOL_VEC4, SamplerFormat::InvalidEnum, 1, 4, 4,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 4, false, false, false, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 4, false, false, false},
{GL_SAMPLER_2D, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, SamplerFormat::Float, 1, 1, 1, {GL_SAMPLER_2D, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, SamplerFormat::Float, 1, 1, 1,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
{GL_SAMPLER_2D_ARRAY, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, SamplerFormat::Float, 1, {GL_SAMPLER_2D_ARRAY, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, SamplerFormat::Float, 1,
1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
"intBitsToFloat"},
{GL_SAMPLER_2D_ARRAY_SHADOW, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, {GL_SAMPLER_2D_ARRAY_SHADOW, GL_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE,
SamplerFormat::Shadow, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, SamplerFormat::Shadow, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true,
false, false, "intBitsToFloat"}, false, false},
{GL_SAMPLER_2D_MULTISAMPLE, GL_INT, GL_TEXTURE_2D_MULTISAMPLE, GL_NONE, GL_NONE, {GL_SAMPLER_2D_MULTISAMPLE, GL_INT, GL_TEXTURE_2D_MULTISAMPLE, GL_NONE, GL_NONE,
SamplerFormat::Float, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, SamplerFormat::Float, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true,
false, false, "intBitsToFloat"}, false, false},
{GL_SAMPLER_2D_MULTISAMPLE_ARRAY, GL_INT, GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_NONE, GL_NONE, {GL_SAMPLER_2D_MULTISAMPLE_ARRAY, GL_INT, GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_NONE, GL_NONE,
SamplerFormat::Float, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, SamplerFormat::Float, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true,
false, false, "intBitsToFloat"}, false, false},
{GL_SAMPLER_2D_RECT_ANGLE, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, SamplerFormat::Float, 1, 1, {GL_SAMPLER_2D_RECT_ANGLE, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, SamplerFormat::Float, 1, 1,
1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"}, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
{GL_SAMPLER_2D_SHADOW, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, SamplerFormat::Shadow, 1, 1, 1, {GL_SAMPLER_2D_SHADOW, GL_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, SamplerFormat::Shadow, 1, 1, 1,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
{GL_SAMPLER_3D, GL_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, SamplerFormat::Float, 1, 1, 1, {GL_SAMPLER_3D, GL_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, SamplerFormat::Float, 1, 1, 1,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
{GL_SAMPLER_CUBE, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, SamplerFormat::Float, 1, 1, 1, {GL_SAMPLER_CUBE, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, SamplerFormat::Float, 1, 1, 1,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
{GL_SAMPLER_CUBE_MAP_ARRAY, GL_INT, GL_TEXTURE_CUBE_MAP_ARRAY, GL_NONE, GL_NONE, {GL_SAMPLER_CUBE_MAP_ARRAY, GL_INT, GL_TEXTURE_CUBE_MAP_ARRAY, GL_NONE, GL_NONE,
SamplerFormat::Float, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, SamplerFormat::Float, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true,
false, false, "intBitsToFloat"}, false, false},
{GL_SAMPLER_BUFFER, GL_INT, GL_TEXTURE_BUFFER, GL_NONE, GL_NONE, SamplerFormat::Float, 1, 1, 1, {GL_SAMPLER_BUFFER, GL_INT, GL_TEXTURE_BUFFER, GL_NONE, GL_NONE, SamplerFormat::Float, 1, 1, 1,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"}, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
{GL_SAMPLER_CUBE_SHADOW, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, SamplerFormat::Shadow, {GL_SAMPLER_CUBE_SHADOW, GL_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, SamplerFormat::Shadow,
1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
"intBitsToFloat"},
{GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW, GL_INT, GL_NONE, GL_NONE, GL_NONE, SamplerFormat::Shadow, 1, {GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW, GL_INT, GL_NONE, GL_NONE, GL_NONE, SamplerFormat::Shadow, 1,
1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false},
"intBitsToFloat"},
{GL_SAMPLER_EXTERNAL_OES, GL_INT, GL_TEXTURE_EXTERNAL_OES, GL_NONE, GL_NONE, {GL_SAMPLER_EXTERNAL_OES, GL_INT, GL_TEXTURE_EXTERNAL_OES, GL_NONE, GL_NONE,
SamplerFormat::Float, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, SamplerFormat::Float, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true,
false, false, "intBitsToFloat"}, false, false},
{GL_UNSIGNED_INT, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_BOOL, SamplerFormat::InvalidEnum, 1, 1, {GL_UNSIGNED_INT, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_BOOL, SamplerFormat::InvalidEnum, 1, 1,
1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, false, false, false, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, false, false, false},
"uintBitsToFloat"},
{GL_UNSIGNED_INT_ATOMIC_COUNTER, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_NONE, {GL_UNSIGNED_INT_ATOMIC_COUNTER, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_NONE,
SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
false, false, false, "uintBitsToFloat"}, false, false, false},
{GL_UNSIGNED_INT_IMAGE_2D, GL_UNSIGNED_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, {GL_UNSIGNED_INT_IMAGE_2D, GL_UNSIGNED_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE,
SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
false, false, true, "uintBitsToFloat"}, false, false, true},
{GL_UNSIGNED_INT_IMAGE_2D_ARRAY, GL_UNSIGNED_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, {GL_UNSIGNED_INT_IMAGE_2D_ARRAY, GL_UNSIGNED_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE,
SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
false, false, true, "uintBitsToFloat"}, false, false, true},
{GL_UNSIGNED_INT_IMAGE_3D, GL_UNSIGNED_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, {GL_UNSIGNED_INT_IMAGE_3D, GL_UNSIGNED_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE,
SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
false, false, true, "uintBitsToFloat"}, false, false, true},
{GL_UNSIGNED_INT_IMAGE_CUBE, GL_UNSIGNED_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, {GL_UNSIGNED_INT_IMAGE_CUBE, GL_UNSIGNED_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE,
SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
false, false, true, "uintBitsToFloat"}, false, false, true},
{GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY, GL_UNSIGNED_INT, GL_TEXTURE_CUBE_MAP_ARRAY, GL_NONE, {GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY, GL_UNSIGNED_INT, GL_TEXTURE_CUBE_MAP_ARRAY, GL_NONE,
GL_NONE, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, GL_NONE, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4,
sizeof(GLuint) * 1, false, false, true, "uintBitsToFloat"}, sizeof(GLuint) * 1, false, false, true},
{GL_UNSIGNED_INT_IMAGE_BUFFER, GL_UNSIGNED_INT, GL_TEXTURE_BUFFER, GL_NONE, GL_NONE, {GL_UNSIGNED_INT_IMAGE_BUFFER, GL_UNSIGNED_INT, GL_TEXTURE_BUFFER, GL_NONE, GL_NONE,
SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
false, false, true, "uintBitsToFloat"}, false, false, true},
{GL_UNSIGNED_INT_SAMPLER_2D, GL_UNSIGNED_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE, {GL_UNSIGNED_INT_SAMPLER_2D, GL_UNSIGNED_INT, GL_TEXTURE_2D, GL_NONE, GL_NONE,
SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
true, false, false, "uintBitsToFloat"}, true, false, false},
{GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, GL_UNSIGNED_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE, {GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, GL_UNSIGNED_INT, GL_TEXTURE_2D_ARRAY, GL_NONE, GL_NONE,
SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
true, false, false, "uintBitsToFloat"}, true, false, false},
{GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, GL_UNSIGNED_INT, GL_TEXTURE_2D_MULTISAMPLE, GL_NONE, {GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, GL_UNSIGNED_INT, GL_TEXTURE_2D_MULTISAMPLE, GL_NONE,
GL_NONE, SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, GL_NONE, SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4,
sizeof(GLuint) * 1, true, false, false, "uintBitsToFloat"}, sizeof(GLuint) * 1, true, false, false},
{GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, GL_UNSIGNED_INT, {GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, GL_UNSIGNED_INT,
GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_NONE, GL_NONE, SamplerFormat::Unsigned, 1, 1, 1, GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_NONE, GL_NONE, SamplerFormat::Unsigned, 1, 1, 1,
sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, true, false, false, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, true, false, false},
"uintBitsToFloat"},
{GL_UNSIGNED_INT_SAMPLER_3D, GL_UNSIGNED_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE, {GL_UNSIGNED_INT_SAMPLER_3D, GL_UNSIGNED_INT, GL_TEXTURE_3D, GL_NONE, GL_NONE,
SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
true, false, false, "uintBitsToFloat"}, true, false, false},
{GL_UNSIGNED_INT_SAMPLER_CUBE, GL_UNSIGNED_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE, {GL_UNSIGNED_INT_SAMPLER_CUBE, GL_UNSIGNED_INT, GL_TEXTURE_CUBE_MAP, GL_NONE, GL_NONE,
SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
true, false, false, "uintBitsToFloat"}, true, false, false},
{GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY, GL_UNSIGNED_INT, GL_TEXTURE_CUBE_MAP_ARRAY, GL_NONE, {GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY, GL_UNSIGNED_INT, GL_TEXTURE_CUBE_MAP_ARRAY, GL_NONE,
GL_NONE, SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, GL_NONE, SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4,
sizeof(GLuint) * 1, true, false, false, "uintBitsToFloat"}, sizeof(GLuint) * 1, true, false, false},
{GL_UNSIGNED_INT_SAMPLER_BUFFER, GL_UNSIGNED_INT, GL_TEXTURE_BUFFER, GL_NONE, GL_NONE, {GL_UNSIGNED_INT_SAMPLER_BUFFER, GL_UNSIGNED_INT, GL_TEXTURE_BUFFER, GL_NONE, GL_NONE,
SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1, SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
true, false, false, "uintBitsToFloat"}, true, false, false},
{GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_BOOL_VEC2, {GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_BOOL_VEC2,
SamplerFormat::InvalidEnum, 1, 2, 2, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 2, SamplerFormat::InvalidEnum, 1, 2, 2, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 2,
false, false, false, "uintBitsToFloat"}, false, false, false},
{GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_BOOL_VEC3, {GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_BOOL_VEC3,
SamplerFormat::InvalidEnum, 1, 3, 3, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 3, SamplerFormat::InvalidEnum, 1, 3, 3, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 3,
false, false, false, "uintBitsToFloat"}, false, false, false},
{GL_UNSIGNED_INT_VEC4, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_BOOL_VEC4, {GL_UNSIGNED_INT_VEC4, GL_UNSIGNED_INT, GL_NONE, GL_NONE, GL_BOOL_VEC4,
SamplerFormat::InvalidEnum, 1, 4, 4, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 4, SamplerFormat::InvalidEnum, 1, 4, 4, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 4,
false, false, false, "uintBitsToFloat"}, false, false, false},
{GL_SAMPLER_VIDEO_IMAGE_WEBGL, GL_INT, GL_TEXTURE_VIDEO_IMAGE_WEBGL, GL_NONE, GL_NONE, {GL_SAMPLER_VIDEO_IMAGE_WEBGL, GL_INT, GL_TEXTURE_VIDEO_IMAGE_WEBGL, GL_NONE, GL_NONE,
SamplerFormat::Float, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, SamplerFormat::Float, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true,
false, false, "intBitsToFloat"}, false, false},
{GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT, GL_INT, GL_NONE, GL_NONE, GL_NONE, SamplerFormat::Float, 1, 1, {GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT, GL_INT, GL_NONE, GL_NONE, GL_NONE, SamplerFormat::Float, 1, 1,
1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false}}};
"intBitsToFloat"}}};
size_t GetTypeInfoIndex(GLenum uniformType) size_t GetTypeInfoIndex(GLenum uniformType)
{ {
......
...@@ -148,8 +148,7 @@ struct UniformTypeInfo final : angle::NonCopyable ...@@ -148,8 +148,7 @@ struct UniformTypeInfo final : angle::NonCopyable
size_t externalSize, size_t externalSize,
bool isSampler, bool isSampler,
bool isMatrixType, bool isMatrixType,
bool isImageType, bool isImageType);
const char *glslAsFloat);
GLenum type; GLenum type;
GLenum componentType; GLenum componentType;
...@@ -166,7 +165,6 @@ struct UniformTypeInfo final : angle::NonCopyable ...@@ -166,7 +165,6 @@ struct UniformTypeInfo final : angle::NonCopyable
bool isSampler; bool isSampler;
bool isMatrixType; bool isMatrixType;
bool isImageType; bool isImageType;
const char *glslAsFloat;
}; };
inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type, inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
...@@ -183,8 +181,7 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type, ...@@ -183,8 +181,7 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
size_t externalSize, size_t externalSize,
bool isSampler, bool isSampler,
bool isMatrixType, bool isMatrixType,
bool isImageType, bool isImageType)
const char *glslAsFloat)
: type(type), : type(type),
componentType(componentType), componentType(componentType),
textureType(textureType), textureType(textureType),
...@@ -199,8 +196,7 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type, ...@@ -199,8 +196,7 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
externalSize(externalSize), externalSize(externalSize),
isSampler(isSampler), isSampler(isSampler),
isMatrixType(isMatrixType), isMatrixType(isMatrixType),
isImageType(isImageType), isImageType(isImageType)
glslAsFloat(glslAsFloat)
{} {}
const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType); const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType);
......
...@@ -927,6 +927,7 @@ const char kAtomicCountersBlockName[] = "ANGLEAtomicCounters"; ...@@ -927,6 +927,7 @@ const char kAtomicCountersBlockName[] = "ANGLEAtomicCounters";
const char kLineRasterEmulationPosition[] = "ANGLEPosition"; const char kLineRasterEmulationPosition[] = "ANGLEPosition";
const char kXfbEmulationGetOffsetsFunctionName[] = "ANGLEGetXfbOffsets"; const char kXfbEmulationGetOffsetsFunctionName[] = "ANGLEGetXfbOffsets";
const char kXfbEmulationCaptureFunctionName[] = "ANGLECaptureXfb";
const char kXfbEmulationBufferBlockName[] = "ANGLEXfbBuffer"; const char kXfbEmulationBufferBlockName[] = "ANGLEXfbBuffer";
const char kXfbEmulationBufferName[] = "ANGLEXfb"; const char kXfbEmulationBufferName[] = "ANGLEXfb";
const char kXfbEmulationBufferFieldName[] = "xfbOut"; const char kXfbEmulationBufferFieldName[] = "xfbOut";
......
...@@ -271,17 +271,6 @@ ANGLE_NO_DISCARD bool ReplaceGLDepthRangeWithDriverUniform(TCompiler *compiler, ...@@ -271,17 +271,6 @@ ANGLE_NO_DISCARD bool ReplaceGLDepthRangeWithDriverUniform(TCompiler *compiler,
return ReplaceVariableWithTyped(compiler, root, depthRangeVar, angleEmulatedDepthRangeRef); return ReplaceVariableWithTyped(compiler, root, depthRangeVar, angleEmulatedDepthRangeRef);
} }
ANGLE_NO_DISCARD bool AppendTransformFeedbackOutputToMain(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable)
{
TVariable *xfbPlaceholder = new TVariable(symbolTable, ImmutableString("@@ XFB-OUT @@"),
new TType(), SymbolType::AngleInternal);
// Append the assignment as a statement at the end of the shader.
return RunAtTheEndOfShader(compiler, root, new TIntermSymbol(xfbPlaceholder), symbolTable);
}
TVariable *AddANGLEPositionVaryingDeclaration(TIntermBlock *root, TVariable *AddANGLEPositionVaryingDeclaration(TIntermBlock *root,
TSymbolTable *symbolTable, TSymbolTable *symbolTable,
TQualifier qualifier) TQualifier qualifier)
...@@ -442,6 +431,67 @@ ANGLE_NO_DISCARD bool AddXfbEmulationSupport(TCompiler *compiler, ...@@ -442,6 +431,67 @@ ANGLE_NO_DISCARD bool AddXfbEmulationSupport(TCompiler *compiler,
const size_t mainIndex = FindMainIndex(root); const size_t mainIndex = FindMainIndex(root);
root->insertChildNodes(mainIndex, {functionDef}); root->insertChildNodes(mainIndex, {functionDef});
// Generate the following function and place it before main(). This function will be filled
// with transform feedback capture code at link time.
//
// void ANGLECaptureXfb()
// {
// }
const TType *voidType = StaticType::GetBasic<EbtVoid>();
// Create the function body, which is empty.
body = new TIntermBlock;
// Declare the function
TFunction *xfbCaptureFunction =
new TFunction(symbolTable, ImmutableString(vk::kXfbEmulationCaptureFunctionName),
SymbolType::AngleInternal, voidType, false);
// Insert the function declaration before main().
root->insertChildNodes(mainIndex,
{CreateInternalFunctionDefinitionNode(*xfbCaptureFunction, body)});
// Create the following logic and add it at the end of main():
//
// if (ANGLEUniforms.xfbActiveUnpaused)
// {
// ANGLECaptureXfb();
// }
//
// Create a reference ANGLEUniforms.xfbActiveUnpaused
TIntermBinary *xfbActiveUnpaused = driverUniforms->getXfbActiveUnpaused();
// ANGLEUniforms.xfbActiveUnpaused != 0
TIntermBinary *isXfbActiveUnpaused =
new TIntermBinary(EOpNotEqual, xfbActiveUnpaused, CreateUIntNode(0));
// Create the function call
TIntermAggregate *captureXfbCall =
TIntermAggregate::CreateFunctionCall(*xfbCaptureFunction, {});
TIntermBlock *captureXfbBlock = new TIntermBlock;
captureXfbBlock->appendStatement(captureXfbCall);
// Create a call to ANGLEGetXfbOffsets too, for the sole purpose of preventing it from being
// culled as unused by glslang.
TIntermSequence zero;
zero.push_back(CreateIndexNode(0));
TIntermSequence ivec4Zero;
ivec4Zero.push_back(TIntermAggregate::CreateConstructor(*ivec4Type, &zero));
TIntermAggregate *getOffsetsCall =
TIntermAggregate::CreateFunctionCall(*getOffsetsFunction, &ivec4Zero);
captureXfbBlock->appendStatement(getOffsetsCall);
// Create the if
TIntermIfElse *captureXfb = new TIntermIfElse(isXfbActiveUnpaused, captureXfbBlock, nullptr);
// Run it at the end of the shader.
if (!RunAtTheEndOfShader(compiler, root, captureXfb, symbolTable))
{
return false;
}
// Additionally, generate the following storage buffer declarations used to capture transform // Additionally, generate the following storage buffer declarations used to capture transform
// feedback output. Again, there's a maximum of four buffers. // feedback output. Again, there's a maximum of four buffers.
// //
...@@ -951,15 +1001,6 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root, ...@@ -951,15 +1001,6 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
return false; return false;
} }
} }
// Append a macro for transform feedback substitution prior to modifying depth.
if ((compileOptions & SH_ADD_VULKAN_XFB_EMULATION_SUPPORT_CODE) != 0)
{
if (!AppendTransformFeedbackOutputToMain(this, root, &getSymbolTable()))
{
return false;
}
}
} }
switch (packedShaderType) switch (packedShaderType)
......
...@@ -178,6 +178,11 @@ TIntermBinary *DriverUniform::getAbcBufferOffsets() const ...@@ -178,6 +178,11 @@ TIntermBinary *DriverUniform::getAbcBufferOffsets() const
return createDriverUniformRef(kAcbBufferOffsets); return createDriverUniformRef(kAcbBufferOffsets);
} }
TIntermBinary *DriverUniform::getXfbActiveUnpaused() const
{
return createDriverUniformRef(kXfbActiveUnpaused);
}
TIntermBinary *DriverUniform::getXfbVerticesPerInstance() const TIntermBinary *DriverUniform::getXfbVerticesPerInstance() const
{ {
return createDriverUniformRef(kXfbVerticesPerInstance); return createDriverUniformRef(kXfbVerticesPerInstance);
......
...@@ -34,6 +34,7 @@ class DriverUniform ...@@ -34,6 +34,7 @@ class DriverUniform
TIntermBinary *getViewportRef() const; TIntermBinary *getViewportRef() const;
TIntermBinary *getAbcBufferOffsets() const; TIntermBinary *getAbcBufferOffsets() const;
TIntermBinary *getXfbActiveUnpaused() const;
TIntermBinary *getXfbVerticesPerInstance() const; TIntermBinary *getXfbVerticesPerInstance() const;
TIntermBinary *getXfbBufferOffsets() const; TIntermBinary *getXfbBufferOffsets() const;
TIntermBinary *getClipDistancesEnabled() const; TIntermBinary *getClipDistancesEnabled() const;
......
...@@ -60,8 +60,6 @@ namespace rx ...@@ -60,8 +60,6 @@ namespace rx
{ {
namespace namespace
{ {
constexpr char kXfbOutMarker[] = "@@ XFB-OUT @@;";
template <size_t N> template <size_t N>
constexpr size_t ConstStrLen(const char (&)[N]) constexpr size_t ConstStrLen(const char (&)[N])
{ {
...@@ -263,7 +261,12 @@ ShaderInterfaceVariableInfo *SetXfbInfo(ShaderInterfaceVariableInfoMap *infoMap, ...@@ -263,7 +261,12 @@ ShaderInterfaceVariableInfo *SetXfbInfo(ShaderInterfaceVariableInfoMap *infoMap,
int fieldIndex, int fieldIndex,
uint32_t xfbBuffer, uint32_t xfbBuffer,
uint32_t xfbOffset, uint32_t xfbOffset,
uint32_t xfbStride) uint32_t xfbStride,
uint32_t arraySize,
uint32_t columnCount,
uint32_t rowCount,
uint32_t arrayIndex,
GLenum componentType)
{ {
ShaderInterfaceVariableInfo &info = infoMap->get(shaderType, varName); ShaderInterfaceVariableInfo &info = infoMap->get(shaderType, varName);
ShaderInterfaceVariableXfbInfo *xfb = &info.xfb; ShaderInterfaceVariableXfbInfo *xfb = &info.xfb;
...@@ -281,75 +284,22 @@ ShaderInterfaceVariableInfo *SetXfbInfo(ShaderInterfaceVariableInfoMap *infoMap, ...@@ -281,75 +284,22 @@ ShaderInterfaceVariableInfo *SetXfbInfo(ShaderInterfaceVariableInfoMap *infoMap,
ASSERT(xfb->offset == ShaderInterfaceVariableXfbInfo::kInvalid); ASSERT(xfb->offset == ShaderInterfaceVariableXfbInfo::kInvalid);
ASSERT(xfb->stride == ShaderInterfaceVariableXfbInfo::kInvalid); ASSERT(xfb->stride == ShaderInterfaceVariableXfbInfo::kInvalid);
xfb->buffer = xfbBuffer; if (arrayIndex != ShaderInterfaceVariableXfbInfo::kInvalid)
xfb->offset = xfbOffset;
xfb->stride = xfbStride;
return &info;
}
std::string SubstituteTransformFeedbackMarkers(const std::string &originalSource,
const std::string &xfbOut)
{
const size_t xfbOutMarkerStart = originalSource.find(kXfbOutMarker);
const size_t xfbOutMarkerEnd = xfbOutMarkerStart + ConstStrLen(kXfbOutMarker);
// The shader is the following form:
//
// ..part1..
// @@ XFB-OUT @@;
// ..part2..
//
// Construct the string by concatenating these three pieces, replacing the marker with the given
// value.
std::string result;
result.append(&originalSource[0], &originalSource[xfbOutMarkerStart]);
result.append(xfbOut);
result.append(&originalSource[xfbOutMarkerEnd], &originalSource[originalSource.size()]);
return result;
}
void GenerateTransformFeedbackVaryingOutput(const gl::TransformFeedbackVarying &varying,
const gl::UniformTypeInfo &info,
size_t offset,
const std::string &bufferIndex,
std::ostringstream *xfbOut)
{
const size_t arrayIndexStart = varying.arrayIndex == GL_INVALID_INDEX ? 0 : varying.arrayIndex;
const size_t arrayIndexEnd = arrayIndexStart + varying.size();
for (size_t arrayIndex = arrayIndexStart; arrayIndex < arrayIndexEnd; ++arrayIndex)
{ {
for (int col = 0; col < info.columnCount; ++col) xfb->arrayElements.emplace_back();
{ xfb = &xfb->arrayElements.back();
for (int row = 0; row < info.rowCount; ++row) }
{
*xfbOut << sh::vk::kXfbEmulationBufferName << bufferIndex << "."
<< sh::vk::kXfbEmulationBufferFieldName << "[xfbOffsets[" << bufferIndex
<< "] + " << offset << "] = " << info.glslAsFloat << "("
<< varying.mappedName;
if (varying.isArray())
{
*xfbOut << "[" << arrayIndex << "]";
}
if (info.columnCount > 1)
{
*xfbOut << "[" << col << "]";
}
if (info.rowCount > 1) xfb->buffer = xfbBuffer;
{ xfb->offset = xfbOffset;
*xfbOut << "[" << row << "]"; xfb->stride = xfbStride;
} xfb->arraySize = arraySize;
xfb->columnCount = columnCount;
xfb->rowCount = rowCount;
xfb->arrayIndex = arrayIndex;
xfb->componentType = componentType;
*xfbOut << ");\n"; return &info;
++offset;
}
}
}
} }
void AssignTransformFeedbackEmulationBindings(gl::ShaderType shaderType, void AssignTransformFeedbackEmulationBindings(gl::ShaderType shaderType,
...@@ -429,65 +379,6 @@ void AssignTransformFeedbackExtensionLocations(gl::ShaderType shaderType, ...@@ -429,65 +379,6 @@ void AssignTransformFeedbackExtensionLocations(gl::ShaderType shaderType,
} }
} }
void GenerateTransformFeedbackEmulationOutputs(const GlslangSourceOptions &options,
gl::ShaderType shaderType,
const gl::ProgramState &programState,
GlslangProgramInterfaceInfo *programInterfaceInfo,
std::string *vertexShader,
ShaderInterfaceVariableInfoMap *variableInfoMapOut)
{
const std::vector<gl::TransformFeedbackVarying> &varyings =
programState.getLinkedTransformFeedbackVaryings();
const std::vector<GLsizei> &bufferStrides = programState.getTransformFeedbackStrides();
const bool isInterleaved =
programState.getTransformFeedbackBufferMode() == GL_INTERLEAVED_ATTRIBS;
const size_t bufferCount = isInterleaved ? 1 : varyings.size();
ASSERT(bufferCount > 0);
const std::string xfbSet = Str(programInterfaceInfo->uniformsAndXfbDescriptorSetIndex);
const std::string driverUniforms = std::string(sh::vk::kDriverUniformsVarName);
std::ostringstream xfbOut;
xfbOut << "if (" << driverUniforms << ".xfbActiveUnpaused != 0)\n{\nivec4 xfbOffsets = "
<< sh::vk::kXfbEmulationGetOffsetsFunctionName << "(ivec4(";
for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
{
if (bufferIndex > 0)
{
xfbOut << ", ";
}
ASSERT(bufferStrides[bufferIndex] % 4 == 0);
xfbOut << bufferStrides[bufferIndex] / 4;
}
for (size_t bufferIndex = bufferCount; bufferIndex < 4; ++bufferIndex)
{
xfbOut << ", 0";
}
xfbOut << "));\n";
size_t outputOffset = 0;
for (size_t varyingIndex = 0; varyingIndex < varyings.size(); ++varyingIndex)
{
const size_t bufferIndex = isInterleaved ? 0 : varyingIndex;
const gl::TransformFeedbackVarying &varying = varyings[varyingIndex];
// For every varying, output to the respective buffer packed. If interleaved, the output is
// always to the same buffer, but at different offsets.
const gl::UniformTypeInfo &info = gl::GetUniformTypeInfo(varying.type);
GenerateTransformFeedbackVaryingOutput(varying, info, outputOffset, Str(bufferIndex),
&xfbOut);
if (isInterleaved)
{
outputOffset += info.columnCount * info.rowCount * varying.size();
}
}
xfbOut << "}\n";
*vertexShader = SubstituteTransformFeedbackMarkers(*vertexShader, xfbOut.str());
}
bool IsFirstRegisterOfVarying(const gl::PackedVaryingRegister &varyingReg, bool allowFields) bool IsFirstRegisterOfVarying(const gl::PackedVaryingRegister &varyingReg, bool allowFields)
{ {
const gl::PackedVarying &varying = *varyingReg.packedVarying; const gl::PackedVarying &varying = *varyingReg.packedVarying;
...@@ -757,10 +648,11 @@ void AssignVaryingLocations(const GlslangSourceOptions &options, ...@@ -757,10 +648,11 @@ void AssignVaryingLocations(const GlslangSourceOptions &options,
// Calculates XFB layout qualifier arguments for each tranform feedback varying. Stores calculated // Calculates XFB layout qualifier arguments for each tranform feedback varying. Stores calculated
// values for the SPIR-V transformation. // values for the SPIR-V transformation.
void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &programExecutable, void AssignTransformFeedbackQualifiers(const gl::ProgramExecutable &programExecutable,
const gl::VaryingPacking &varyingPacking, const gl::VaryingPacking &varyingPacking,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
ShaderInterfaceVariableInfoMap *variableInfoMapOut) bool usesExtension,
ShaderInterfaceVariableInfoMap *variableInfoMapOut)
{ {
const std::vector<gl::TransformFeedbackVarying> &tfVaryings = const std::vector<gl::TransformFeedbackVarying> &tfVaryings =
programExecutable.getLinkedTransformFeedbackVaryings(); programExecutable.getLinkedTransformFeedbackVaryings();
...@@ -792,13 +684,19 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &pro ...@@ -792,13 +684,19 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &pro
} }
const gl::TransformFeedbackVarying &tfVarying = tfVaryings[varyingIndex]; const gl::TransformFeedbackVarying &tfVarying = tfVaryings[varyingIndex];
const gl::UniformTypeInfo &uniformInfo = gl::GetUniformTypeInfo(tfVarying.type);
const uint32_t varyingSize =
tfVarying.isArray() ? tfVarying.size() : ShaderInterfaceVariableXfbInfo::kInvalid;
if (tfVarying.isBuiltIn()) if (tfVarying.isBuiltIn())
{ {
if (tfVarying.name == "gl_Position") if (usesExtension && tfVarying.name == "gl_Position")
{ {
// With the extension, gl_Position is captured via a special varying.
SetXfbInfo(variableInfoMapOut, shaderType, sh::vk::kXfbExtensionPositionOutName, -1, SetXfbInfo(variableInfoMapOut, shaderType, sh::vk::kXfbExtensionPositionOutName, -1,
bufferIndex, currentOffset, currentStride); bufferIndex, currentOffset, currentStride, varyingSize,
uniformInfo.columnCount, uniformInfo.rowCount,
ShaderInterfaceVariableXfbInfo::kInvalid, uniformInfo.componentType);
} }
else else
{ {
...@@ -809,8 +707,8 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &pro ...@@ -809,8 +707,8 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &pro
// Field 2: gl_ClipDistance // Field 2: gl_ClipDistance
// Field 3: gl_CullDistance // Field 3: gl_CullDistance
// //
// All fields except gl_Position can be captured directly by decorating gl_PerVertex // With the extension, all fields except gl_Position can be captured directly by
// fields. // decorating gl_PerVertex fields.
int fieldIndex = -1; int fieldIndex = -1;
constexpr int kPerVertexMemberCount = 4; constexpr int kPerVertexMemberCount = 4;
constexpr std::array<const char *, kPerVertexMemberCount> kPerVertexMembers = { constexpr std::array<const char *, kPerVertexMemberCount> kPerVertexMembers = {
...@@ -819,7 +717,7 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &pro ...@@ -819,7 +717,7 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &pro
"gl_ClipDistance", "gl_ClipDistance",
"gl_CullDistance", "gl_CullDistance",
}; };
for (int index = 1; index < kPerVertexMemberCount; ++index) for (int index = 0; index < kPerVertexMemberCount; ++index)
{ {
if (tfVarying.name == kPerVertexMembers[index]) if (tfVarying.name == kPerVertexMembers[index])
{ {
...@@ -828,71 +726,80 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &pro ...@@ -828,71 +726,80 @@ void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &pro
} }
} }
ASSERT(fieldIndex != -1); ASSERT(fieldIndex != -1);
ASSERT(!usesExtension || fieldIndex > 0);
SetXfbInfo(variableInfoMapOut, shaderType, "gl_PerVertex", fieldIndex, bufferIndex, SetXfbInfo(variableInfoMapOut, shaderType, "gl_PerVertex", fieldIndex, bufferIndex,
currentOffset, currentStride); currentOffset, currentStride, varyingSize, uniformInfo.columnCount,
uniformInfo.rowCount, ShaderInterfaceVariableXfbInfo::kInvalid,
uniformInfo.componentType);
} }
continue;
} }
else if (!tfVarying.isArray() || tfVarying.arrayIndex == GL_INVALID_INDEX) // Note: capturing individual array elements using the Vulkan transform feedback extension
// is currently not supported due to limitations in the extension.
// ANGLE supports capturing the whole array.
// http://anglebug.com/4140
if (usesExtension && tfVarying.isArray() && tfVarying.arrayIndex != GL_INVALID_INDEX)
{ {
// Note: capturing individual array elements using the Vulkan transform feedback continue;
// extension is not supported, and is unlikely to be ever supported (on the contrary, it }
// may be removed from the GLES spec). http://anglebug.com/4140
// ANGLE should support capturing the whole array. // Find the varying with this name. If a struct is captured, we would be iterating over its
// fields, and the name of the varying is found through parentStructMappedName. This should
// Find the varying with this name. If a struct is captured, we would be iterating over // only be done for the first field of the struct. For I/O blocks on the other hand, we
// its fields, and the name of the varying is found through parentStructMappedName. // need to decorate the exact member that is captured (as whole-block capture is not
// This should only be done for the first field of the struct. For I/O blocks on the // supported).
// other hand, we need to decorate the exact member that is captured (as whole-block const gl::PackedVarying *originalVarying = nullptr;
// capture is not supported). for (const gl::PackedVaryingRegister &varyingReg : varyingPacking.getRegisterList())
const gl::PackedVarying *originalVarying = nullptr; {
for (const gl::PackedVaryingRegister &varyingReg : varyingPacking.getRegisterList()) if (!IsFirstRegisterOfVarying(varyingReg, tfVarying.isShaderIOBlock))
{ {
if (!IsFirstRegisterOfVarying(varyingReg, tfVarying.isShaderIOBlock)) continue;
{ }
continue;
}
const gl::PackedVarying *varying = varyingReg.packedVarying; const gl::PackedVarying *varying = varyingReg.packedVarying;
if (tfVarying.isShaderIOBlock) if (tfVarying.isShaderIOBlock)
{
if (varying->frontVarying.parentStructName == tfVarying.structOrBlockName)
{ {
if (varying->frontVarying.parentStructName == tfVarying.structOrBlockName) size_t pos = tfVarying.name.find_first_of(".");
std::string fieldName =
pos == std::string::npos ? tfVarying.name : tfVarying.name.substr(pos + 1);
if (fieldName == varying->frontVarying.varying->name.c_str())
{ {
size_t pos = tfVarying.name.find_first_of("."); originalVarying = varying;
std::string fieldName = pos == std::string::npos break;
? tfVarying.name
: tfVarying.name.substr(pos + 1);
if (fieldName == varying->frontVarying.varying->name.c_str())
{
originalVarying = varying;
break;
}
} }
} }
else if (varying->frontVarying.varying->name == tfVarying.name)
{
originalVarying = varying;
break;
}
} }
else if (varying->frontVarying.varying->name == tfVarying.name)
if (originalVarying)
{ {
const std::string &mappedName = originalVarying = varying;
originalVarying->isStructField() break;
? originalVarying->frontVarying.parentStructMappedName
: originalVarying->frontVarying.varying->mappedName;
const int fieldIndex = tfVarying.isShaderIOBlock ? originalVarying->fieldIndex : -1;
// Set xfb info for this varying. AssignVaryingLocations should have already added
// location information for these varyings.
SetXfbInfo(variableInfoMapOut, shaderType, mappedName, fieldIndex, bufferIndex,
currentOffset, currentStride);
} }
} }
if (originalVarying)
{
const std::string &mappedName =
originalVarying->isStructField()
? originalVarying->frontVarying.parentStructMappedName
: originalVarying->frontVarying.varying->mappedName;
const int fieldIndex = tfVarying.isShaderIOBlock ? originalVarying->fieldIndex : -1;
const uint32_t arrayIndex = tfVarying.arrayIndex == GL_INVALID_INDEX
? ShaderInterfaceVariableXfbInfo::kInvalid
: tfVarying.arrayIndex;
// Set xfb info for this varying. AssignVaryingLocations should have already added
// location information for these varyings.
SetXfbInfo(variableInfoMapOut, shaderType, mappedName, fieldIndex, bufferIndex,
currentOffset, currentStride, varyingSize, uniformInfo.columnCount,
uniformInfo.rowCount, arrayIndex, uniformInfo.componentType);
}
} }
} }
...@@ -1367,6 +1274,7 @@ class SpirvIDDiscoverer final : angle::NonCopyable ...@@ -1367,6 +1274,7 @@ class SpirvIDDiscoverer final : angle::NonCopyable
spirv::IdRef vec4Id() const { return mVec4Id; } spirv::IdRef vec4Id() const { return mVec4Id; }
spirv::IdRef vec4OutTypePointerId() const { return mVec4OutTypePointerId; } spirv::IdRef vec4OutTypePointerId() const { return mVec4OutTypePointerId; }
spirv::IdRef intId() const { return mIntId; } spirv::IdRef intId() const { return mIntId; }
spirv::IdRef uintId() const { return mUintId; }
spirv::IdRef int0Id() const { return mInt0Id; } spirv::IdRef int0Id() const { return mInt0Id; }
spirv::IdRef floatHalfId() const { return mFloatHalfId; } spirv::IdRef floatHalfId() const { return mFloatHalfId; }
spirv::IdRef outputPerVertexTypePointerId() const { return mOutputPerVertexTypePointerId; } spirv::IdRef outputPerVertexTypePointerId() const { return mOutputPerVertexTypePointerId; }
...@@ -1405,6 +1313,7 @@ class SpirvIDDiscoverer final : angle::NonCopyable ...@@ -1405,6 +1313,7 @@ class SpirvIDDiscoverer final : angle::NonCopyable
// - mVec4Id: id of OpTypeVector %mFloatID 4 // - mVec4Id: id of OpTypeVector %mFloatID 4
// - mVec4OutTypePointerId: id of OpTypePointer Output %mVec4ID // - mVec4OutTypePointerId: id of OpTypePointer Output %mVec4ID
// - mIntId: id of OpTypeInt 32 1 // - mIntId: id of OpTypeInt 32 1
// - mUintId: id of OpTypeInt 32 0
// - mInt0Id: id of OpConstant %mIntID 0 // - mInt0Id: id of OpConstant %mIntID 0
// - mFloatHalfId: id of OpConstant %mFloatId 0.5f // - mFloatHalfId: id of OpConstant %mFloatId 0.5f
// - mOutputPerVertexTypePointerId: id of OpTypePointer Output %mOutputPerVertex.typeId // - mOutputPerVertexTypePointerId: id of OpTypePointer Output %mOutputPerVertex.typeId
...@@ -1414,6 +1323,7 @@ class SpirvIDDiscoverer final : angle::NonCopyable ...@@ -1414,6 +1323,7 @@ class SpirvIDDiscoverer final : angle::NonCopyable
spirv::IdRef mVec4Id; spirv::IdRef mVec4Id;
spirv::IdRef mVec4OutTypePointerId; spirv::IdRef mVec4OutTypePointerId;
spirv::IdRef mIntId; spirv::IdRef mIntId;
spirv::IdRef mUintId;
spirv::IdRef mInt0Id; spirv::IdRef mInt0Id;
spirv::IdRef mFloatHalfId; spirv::IdRef mFloatHalfId;
spirv::IdRef mOutputPerVertexTypePointerId; spirv::IdRef mOutputPerVertexTypePointerId;
...@@ -1530,8 +1440,18 @@ void SpirvIDDiscoverer::visitTypeInt(spirv::IdResult id, ...@@ -1530,8 +1440,18 @@ void SpirvIDDiscoverer::visitTypeInt(spirv::IdResult id,
spirv::LiteralInteger width, spirv::LiteralInteger width,
spirv::LiteralInteger signedness) spirv::LiteralInteger signedness)
{ {
// Only interested in OpTypeInt 32 1. // Only interested in OpTypeInt 32 *.
if (width == 32 && signedness == 1) if (width != 32)
{
return;
}
if (signedness == 0)
{
ASSERT(!mUintId.valid());
mUintId = id;
}
else
{ {
ASSERT(!mIntId.valid()); ASSERT(!mIntId.valid());
mIntId = id; mIntId = id;
...@@ -1932,6 +1852,7 @@ class SpirvVaryingPrecisionFixer final : angle::NonCopyable ...@@ -1932,6 +1852,7 @@ class SpirvVaryingPrecisionFixer final : angle::NonCopyable
gl::ShaderType shaderType, gl::ShaderType shaderType,
SpirvBlob *blobOut); SpirvBlob *blobOut);
bool isReplaced(spirv::IdRef id) const { return mFixedVaryingId[id].valid(); }
spirv::IdRef getReplacementId(spirv::IdRef id) const spirv::IdRef getReplacementId(spirv::IdRef id) const
{ {
return mFixedVaryingId[id].valid() ? mFixedVaryingId[id] : id; return mFixedVaryingId[id].valid() ? mFixedVaryingId[id] : id;
...@@ -2078,8 +1999,16 @@ void SpirvVaryingPrecisionFixer::writeOutputPrologue( ...@@ -2078,8 +1999,16 @@ void SpirvVaryingPrecisionFixer::writeOutputPrologue(
class SpirvTransformFeedbackCodeGenerator final : angle::NonCopyable class SpirvTransformFeedbackCodeGenerator final : angle::NonCopyable
{ {
public: public:
SpirvTransformFeedbackCodeGenerator() : mHasTransformFeedbackOutput(false) {} SpirvTransformFeedbackCodeGenerator(bool isEmulated)
: mIsEmulated(isEmulated), mHasTransformFeedbackOutput(false)
{}
void visitName(spirv::IdRef id, const spirv::LiteralString &name);
void visitTypeVector(const SpirvIDDiscoverer &ids,
spirv::IdResult id,
spirv::IdRef componentId,
spirv::LiteralInteger componentCount);
void visitTypePointer(spirv::IdResult id, spv::StorageClass storageClass, spirv::IdRef typeId);
void visitVariable(const ShaderInterfaceVariableInfo &info, void visitVariable(const ShaderInterfaceVariableInfo &info,
gl::ShaderType shaderType, gl::ShaderType shaderType,
const spirv::LiteralString &name, const spirv::LiteralString &name,
...@@ -2096,7 +2025,18 @@ class SpirvTransformFeedbackCodeGenerator final : angle::NonCopyable ...@@ -2096,7 +2025,18 @@ class SpirvTransformFeedbackCodeGenerator final : angle::NonCopyable
spirv::IdResult id, spirv::IdResult id,
spv::StorageClass storageClass); spv::StorageClass storageClass);
void writeTransformFeedbackOutput(spirv::IdRef positionId, SpirvBlob *blobOut); void writePendingDeclarations(
const std::vector<const ShaderInterfaceVariableInfo *> &variableInfoById,
const SpirvIDDiscoverer &ids,
SpirvBlob *blobOut);
void writeTransformFeedbackExtensionOutput(const SpirvIDDiscoverer &ids,
spirv::IdRef positionId,
SpirvBlob *blobOut);
void writeTransformFeedbackEmulationOutput(
const SpirvIDDiscoverer &ids,
const SpirvVaryingPrecisionFixer &varyingPrecisionFixer,
spirv::IdRef currentFunctionId,
SpirvBlob *blobOut);
void addExecutionMode(spirv::IdRef entryPointId, SpirvBlob *blobOut); void addExecutionMode(spirv::IdRef entryPointId, SpirvBlob *blobOut);
void addMemberDecorate(const ShaderInterfaceVariableInfo &info, void addMemberDecorate(const ShaderInterfaceVariableInfo &info,
spirv::IdRef id, spirv::IdRef id,
...@@ -2104,6 +2044,30 @@ class SpirvTransformFeedbackCodeGenerator final : angle::NonCopyable ...@@ -2104,6 +2044,30 @@ class SpirvTransformFeedbackCodeGenerator final : angle::NonCopyable
void addDecorate(const ShaderInterfaceVariableInfo &info, spirv::IdRef id, SpirvBlob *blobOut); void addDecorate(const ShaderInterfaceVariableInfo &info, spirv::IdRef id, SpirvBlob *blobOut);
private: private:
void gatherXfbVaryings(const ShaderInterfaceVariableInfo &info, spirv::IdRef id);
void visitXfbVarying(const ShaderInterfaceVariableXfbInfo &xfb,
spirv::IdRef baseId,
uint32_t fieldIndex);
void writeIntConstant(const SpirvIDDiscoverer &ids,
uint32_t value,
spirv::IdRef intId,
SpirvBlob *blobOut);
void getVaryingTypeIds(const SpirvIDDiscoverer &ids,
GLenum componentType,
bool isPrivate,
spirv::IdRef *typeIdOut,
spirv::IdRef *typePtrOut);
void writeGetOffsetsCall(spirv::IdRef xfbOffsets, SpirvBlob *blobOut);
void writeComponentCapture(const SpirvIDDiscoverer &ids,
uint32_t bufferIndex,
spirv::IdRef xfbOffset,
spirv::IdRef varyingTypeId,
spirv::IdRef varyingTypePtr,
spirv::IdRef varyingBaseId,
const spirv::IdRefList &accessChainIndices,
GLenum componentType,
SpirvBlob *blobOut);
static constexpr size_t kXfbDecorationCount = 3; static constexpr size_t kXfbDecorationCount = 3;
static constexpr spv::Decoration kXfbDecorations[kXfbDecorationCount] = { static constexpr spv::Decoration kXfbDecorations[kXfbDecorationCount] = {
spv::DecorationXfbBuffer, spv::DecorationXfbBuffer,
...@@ -2111,12 +2075,113 @@ class SpirvTransformFeedbackCodeGenerator final : angle::NonCopyable ...@@ -2111,12 +2075,113 @@ class SpirvTransformFeedbackCodeGenerator final : angle::NonCopyable
spv::DecorationOffset, spv::DecorationOffset,
}; };
bool mIsEmulated;
bool mHasTransformFeedbackOutput; bool mHasTransformFeedbackOutput;
// Ids needed to generate transform feedback support code. // Ids needed to generate transform feedback support code.
spirv::IdRef mTransformFeedbackExtensionPositionId; spirv::IdRef mTransformFeedbackExtensionPositionId;
spirv::IdRef mGetXfbOffsetsFuncId;
spirv::IdRef mXfbCaptureFuncId;
gl::TransformFeedbackBuffersArray<spirv::IdRef> mXfbBuffers;
gl::TransformFeedbackBuffersArray<spirv::IdRef> mBufferStrides;
spirv::IdRef mBufferStridesCompositeId;
// Type and constant ids:
//
// - mIVec4Id: id of OpTypeVector %mIntId 4
//
// - mFloatOutputPointerId: id of OpTypePointer Output %mFloatId
// - mIntOutputPointerId: id of OpTypePointer Output %mIntId
// - mUintOutputPointerId: id of OpTypePointer Output %mUintId
// - mFloatPrivatePointerId, mIntPrivatePointerId, mUintPrivatePointerId: identical to the
// above, but with the Private storage class. Used to load from varyings that have been
// replaced as part of precision mismatch fixup.
// - mFloatUniformPointerId: id of OpTypePointer Uniform %mFloatId
// - mIVec4FuncPointerId: id of OpTypePointer Function %mIVec4Id
//
// - mIntNIds[n]: id of OpConstant %mIntId n
spirv::IdRef mIVec4Id;
spirv::IdRef mFloatOutputPointerId;
spirv::IdRef mIntOutputPointerId;
spirv::IdRef mUintOutputPointerId;
spirv::IdRef mFloatPrivatePointerId;
spirv::IdRef mIntPrivatePointerId;
spirv::IdRef mUintPrivatePointerId;
spirv::IdRef mFloatUniformPointerId;
spirv::IdRef mIVec4FuncPointerId;
// Id of constants such as row, column and array index. Integers 0, 1, 2 and 3 are always
// defined due to the ubiquity of usage.
angle::FastVector<spirv::IdRef, 4> mIntNIds;
// For transform feedback emulation, the captured elements are gathered in a list and sorted.
// This allows the output generation code to always use offset += 1, thus relying on only one
// constant (1).
struct XfbVarying
{
// The varyings are sorted by info.offset.
const ShaderInterfaceVariableXfbInfo *info;
// Id of the base variable.
spirv::IdRef baseId;
// The field index, if a member of an I/O blocks
uint32_t fieldIndex;
};
gl::TransformFeedbackBuffersArray<std::vector<XfbVarying>> mXfbVaryings;
}; };
void SpirvTransformFeedbackCodeGenerator::visitName(spirv::IdRef id,
const spirv::LiteralString &name)
{
if (!mIsEmulated)
{
return;
}
const size_t bufferNameBaseLength = strlen(sh::vk::kXfbEmulationBufferName);
if (angle::BeginsWith(name, sh::vk::kXfbEmulationGetOffsetsFunctionName))
{
ASSERT(!mGetXfbOffsetsFuncId.valid());
mGetXfbOffsetsFuncId = id;
}
else if (angle::BeginsWith(name, sh::vk::kXfbEmulationCaptureFunctionName))
{
ASSERT(!mXfbCaptureFuncId.valid());
mXfbCaptureFuncId = id;
}
else if (angle::BeginsWith(name, sh::vk::kXfbEmulationBufferName) &&
std::isdigit(name[bufferNameBaseLength]))
{
static_assert(gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS < 10,
"Parsing the xfb buffer index below must be adjusted");
uint32_t xfbBuffer = name[bufferNameBaseLength] - '0';
mXfbBuffers[xfbBuffer] = id;
}
}
void SpirvTransformFeedbackCodeGenerator::visitTypeVector(const SpirvIDDiscoverer &ids,
spirv::IdResult id,
spirv::IdRef componentId,
spirv::LiteralInteger componentCount)
{
// Only interested in OpTypeVector %mIntId 4
if (componentId == ids.intId() && componentCount == 4)
{
ASSERT(!mIVec4Id.valid());
mIVec4Id = id;
}
}
void SpirvTransformFeedbackCodeGenerator::visitTypePointer(spirv::IdResult id,
spv::StorageClass storageClass,
spirv::IdRef typeId)
{
if (typeId == mIVec4Id && storageClass == spv::StorageClassFunction)
{
ASSERT(!mIVec4FuncPointerId.valid());
mIVec4FuncPointerId = id;
}
}
void SpirvTransformFeedbackCodeGenerator::visitVariable(const ShaderInterfaceVariableInfo &info, void SpirvTransformFeedbackCodeGenerator::visitVariable(const ShaderInterfaceVariableInfo &info,
gl::ShaderType shaderType, gl::ShaderType shaderType,
const spirv::LiteralString &name, const spirv::LiteralString &name,
...@@ -2124,6 +2189,12 @@ void SpirvTransformFeedbackCodeGenerator::visitVariable(const ShaderInterfaceVar ...@@ -2124,6 +2189,12 @@ void SpirvTransformFeedbackCodeGenerator::visitVariable(const ShaderInterfaceVar
spirv::IdResult id, spirv::IdResult id,
spv::StorageClass storageClass) spv::StorageClass storageClass)
{ {
if (mIsEmulated)
{
gatherXfbVaryings(info, id);
return;
}
// Note if the variable is captured by transform feedback. In that case, the TransformFeedback // Note if the variable is captured by transform feedback. In that case, the TransformFeedback
// capability needs to be added. // capability needs to be added.
if ((info.xfb.buffer != ShaderInterfaceVariableInfo::kInvalid || !info.fieldXfb.empty()) && if ((info.xfb.buffer != ShaderInterfaceVariableInfo::kInvalid || !info.fieldXfb.empty()) &&
...@@ -2144,7 +2215,7 @@ TransformationState SpirvTransformFeedbackCodeGenerator::transformCapability( ...@@ -2144,7 +2215,7 @@ TransformationState SpirvTransformFeedbackCodeGenerator::transformCapability(
spv::Capability capability, spv::Capability capability,
SpirvBlob *blobOut) SpirvBlob *blobOut)
{ {
if (!mHasTransformFeedbackOutput) if (!mHasTransformFeedbackOutput || mIsEmulated)
{ {
return TransformationState::Unchanged; return TransformationState::Unchanged;
} }
...@@ -2204,18 +2275,495 @@ TransformationState SpirvTransformFeedbackCodeGenerator::transformVariable( ...@@ -2204,18 +2275,495 @@ TransformationState SpirvTransformFeedbackCodeGenerator::transformVariable(
return TransformationState::Unchanged; return TransformationState::Unchanged;
} }
void SpirvTransformFeedbackCodeGenerator::writeTransformFeedbackOutput(spirv::IdRef positionId, void SpirvTransformFeedbackCodeGenerator::gatherXfbVaryings(const ShaderInterfaceVariableInfo &info,
SpirvBlob *blobOut) spirv::IdRef id)
{
visitXfbVarying(info.xfb, id, ShaderInterfaceVariableXfbInfo::kInvalid);
for (size_t fieldIndex = 0; fieldIndex < info.fieldXfb.size(); ++fieldIndex)
{
visitXfbVarying(info.fieldXfb[fieldIndex], id, static_cast<uint32_t>(fieldIndex));
}
}
void SpirvTransformFeedbackCodeGenerator::visitXfbVarying(const ShaderInterfaceVariableXfbInfo &xfb,
spirv::IdRef baseId,
uint32_t fieldIndex)
{
for (const ShaderInterfaceVariableXfbInfo &arrayElement : xfb.arrayElements)
{
visitXfbVarying(arrayElement, baseId, fieldIndex);
}
if (xfb.buffer == ShaderInterfaceVariableXfbInfo::kInvalid)
{
return;
}
// Varyings captured to the same buffer have the same stride.
ASSERT(mXfbVaryings[xfb.buffer].empty() ||
mXfbVaryings[xfb.buffer][0].info->stride == xfb.stride);
mXfbVaryings[xfb.buffer].push_back({&xfb, baseId, fieldIndex});
}
void SpirvTransformFeedbackCodeGenerator::writeIntConstant(const SpirvIDDiscoverer &ids,
uint32_t value,
spirv::IdRef intId,
SpirvBlob *blobOut)
{
if (value == ShaderInterfaceVariableXfbInfo::kInvalid)
{
return;
}
if (mIntNIds.size() <= value)
{
mIntNIds.resize(value + 1);
}
else if (mIntNIds[value].valid())
{
return;
}
mIntNIds[value] = SpirvTransformerBase::GetNewId(blobOut);
spirv::WriteConstant(blobOut, ids.intId(), mIntNIds[value],
spirv::LiteralContextDependentNumber(value));
}
void SpirvTransformFeedbackCodeGenerator::writePendingDeclarations(
const std::vector<const ShaderInterfaceVariableInfo *> &variableInfoById,
const SpirvIDDiscoverer &ids,
SpirvBlob *blobOut)
{
if (!mIsEmulated)
{
return;
}
ASSERT(mIVec4Id.valid());
mFloatOutputPointerId = SpirvTransformerBase::GetNewId(blobOut);
mFloatPrivatePointerId = SpirvTransformerBase::GetNewId(blobOut);
spirv::WriteTypePointer(blobOut, mFloatOutputPointerId, spv::StorageClassOutput, ids.floatId());
spirv::WriteTypePointer(blobOut, mFloatPrivatePointerId, spv::StorageClassPrivate,
ids.floatId());
if (ids.intId().valid())
{
mIntOutputPointerId = SpirvTransformerBase::GetNewId(blobOut);
mIntPrivatePointerId = SpirvTransformerBase::GetNewId(blobOut);
spirv::WriteTypePointer(blobOut, mIntOutputPointerId, spv::StorageClassOutput, ids.intId());
spirv::WriteTypePointer(blobOut, mIntPrivatePointerId, spv::StorageClassPrivate,
ids.intId());
}
if (ids.uintId().valid())
{
mUintOutputPointerId = SpirvTransformerBase::GetNewId(blobOut);
mUintPrivatePointerId = SpirvTransformerBase::GetNewId(blobOut);
spirv::WriteTypePointer(blobOut, mUintOutputPointerId, spv::StorageClassOutput,
ids.uintId());
spirv::WriteTypePointer(blobOut, mUintPrivatePointerId, spv::StorageClassPrivate,
ids.uintId());
}
mFloatUniformPointerId = SpirvTransformerBase::GetNewId(blobOut);
spirv::WriteTypePointer(blobOut, mFloatUniformPointerId, spv::StorageClassUniform,
ids.floatId());
mIntNIds.resize(4);
mIntNIds[0] = ids.int0Id();
for (int n = 1; n < 4; ++n)
{
writeIntConstant(ids, n, ids.intId(), blobOut);
}
spirv::IdRefList compositeIds;
for (const std::vector<XfbVarying> &varyings : mXfbVaryings)
{
if (varyings.empty())
{
compositeIds.push_back(ids.int0Id());
continue;
}
const ShaderInterfaceVariableXfbInfo *info0 = varyings[0].info;
// Define the buffer stride constant
ASSERT(info0->stride % sizeof(float) == 0);
uint32_t stride = info0->stride / sizeof(float);
mBufferStrides[info0->buffer] = SpirvTransformerBase::GetNewId(blobOut);
spirv::WriteConstant(blobOut, ids.intId(), mBufferStrides[info0->buffer],
spirv::LiteralContextDependentNumber(stride));
compositeIds.push_back(mBufferStrides[info0->buffer]);
// Define all the constants that would be necessary to load the components of the varying.
for (const XfbVarying &varying : varyings)
{
writeIntConstant(ids, varying.fieldIndex, ids.intId(), blobOut);
const ShaderInterfaceVariableXfbInfo *info = varying.info;
if (info->arraySize == ShaderInterfaceVariableXfbInfo::kInvalid)
{
continue;
}
uint32_t arrayIndexStart =
varying.info->arrayIndex != ShaderInterfaceVariableXfbInfo::kInvalid
? varying.info->arrayIndex
: 0;
uint32_t arrayIndexEnd = arrayIndexStart + info->arraySize;
for (uint32_t arrayIndex = arrayIndexStart; arrayIndex < arrayIndexEnd; ++arrayIndex)
{
writeIntConstant(ids, arrayIndex, ids.intId(), blobOut);
}
}
}
mBufferStridesCompositeId = SpirvTransformerBase::GetNewId(blobOut);
spirv::WriteConstantComposite(blobOut, mIVec4Id, mBufferStridesCompositeId, compositeIds);
}
void SpirvTransformFeedbackCodeGenerator::writeTransformFeedbackExtensionOutput(
const SpirvIDDiscoverer &ids,
spirv::IdRef positionId,
SpirvBlob *blobOut)
{ {
if (mIsEmulated)
{
return;
}
if (mTransformFeedbackExtensionPositionId.valid()) if (mTransformFeedbackExtensionPositionId.valid())
{ {
spirv::WriteStore(blobOut, mTransformFeedbackExtensionPositionId, positionId, nullptr); spirv::WriteStore(blobOut, mTransformFeedbackExtensionPositionId, positionId, nullptr);
} }
} }
class AccessChainIndexListAppend final : angle::NonCopyable
{
public:
AccessChainIndexListAppend(bool condition,
angle::FastVector<spirv::IdRef, 4> intNIds,
uint32_t index,
spirv::IdRefList *indexList)
: mCondition(condition), mIndexList(indexList)
{
if (mCondition)
{
mIndexList->push_back(intNIds[index]);
}
}
~AccessChainIndexListAppend()
{
if (mCondition)
{
mIndexList->pop_back();
}
}
private:
bool mCondition;
spirv::IdRefList *mIndexList;
};
void SpirvTransformFeedbackCodeGenerator::writeTransformFeedbackEmulationOutput(
const SpirvIDDiscoverer &ids,
const SpirvVaryingPrecisionFixer &varyingPrecisionFixer,
spirv::IdRef currentFunctionId,
SpirvBlob *blobOut)
{
if (!mIsEmulated || !mXfbCaptureFuncId.valid() || currentFunctionId != mXfbCaptureFuncId)
{
return;
}
// First, sort the varyings by offset, to simplify calculation of the output offset.
for (std::vector<XfbVarying> &varyings : mXfbVaryings)
{
std::sort(varyings.begin(), varyings.end(),
[](const XfbVarying &first, const XfbVarying &second) {
return first.info->offset < second.info->offset;
});
}
// The following code is generated for transform feedback emulation:
//
// ivec4 xfbOffsets = ANGLEGetXfbOffsets(ivec4(stride0, stride1, stride2, stride3));
// // For buffer N:
// int xfbOffset = xfbOffsets[N]
// ANGLEXfbN.xfbOut[xfbOffset] = tfVarying0.field[index][row][col]
// xfbOffset += 1;
// ANGLEXfbN.xfbOut[xfbOffset] = tfVarying0.field[index][row][col + 1]
// xfbOffset += 1;
// ...
//
// The following pieces of SPIR-V code are generated according to the above:
//
// - For the initial offsets calculation:
//
// %getOffsetsParam = OpVariable %mIVec4FuncPointerId Function %stridesComposite
// %xfbOffsetsResult = OpFunctionCall %ivec4 %ANGLEGetXfbOffsets %stridesComposite
// %xfbOffsetsVar = OpVariable %mIVec4FuncPointerId Function
// OpStore %xfbOffsetsVar %xfbOffsetsResult
// %xfbOffsets = OpLoad %ivec4 %xfbOffsetsVar
//
// - Initial code for each buffer N:
//
// %xfbOffset = OpCompositeExtract %int %xfbOffsets N
//
// - For each varying being captured:
//
// // Load the component
// %componentPtr = OpAccessChain %floatOutputPtr %baseId %field %arrayIndex %row %col
// %component = OpLoad %float %componentPtr
// // Store in xfb output
// %xfbOutPtr = OpAccessChain %floatUniformPtr %xfbBufferN %int0 %xfbOffset
// OpStore %xfbOutPtr %component
// // Increment offset
// %xfbOffset = OpIAdd %int %xfbOffset %int1
//
// Note that if the varying being captured is integer, the first two instructions above would
// use the intger equivalent types, and the following instruction would bitcast it to float
// for storage:
//
// %asFloat = OpBitcast %float %component
//
const spirv::IdRef xfbOffsets(SpirvTransformerBase::GetNewId(blobOut));
// ivec4 xfbOffsets = ANGLEGetXfbOffsets(ivec4(stride0, stride1, stride2, stride3));
writeGetOffsetsCall(xfbOffsets, blobOut);
// Go over the buffers one by one and capture the varyings.
for (uint32_t bufferIndex = 0; bufferIndex < mXfbVaryings.size(); ++bufferIndex)
{
spirv::IdRef xfbOffset(SpirvTransformerBase::GetNewId(blobOut));
// Get the offset corresponding to this buffer:
//
// int xfbOffset = xfbOffsets[N]
spirv::WriteCompositeExtract(blobOut, ids.intId(), xfbOffset, xfbOffsets,
{spirv::LiteralInteger(bufferIndex)});
// Track offsets for verification.
uint32_t offsetForVerification = 0;
// Go over the varyings of this buffer in order.
const std::vector<XfbVarying> &varyings = mXfbVaryings[bufferIndex];
for (size_t varyingIndex = 0; varyingIndex < varyings.size(); ++varyingIndex)
{
const XfbVarying &varying = varyings[varyingIndex];
const ShaderInterfaceVariableXfbInfo *info = varying.info;
ASSERT(info->buffer == bufferIndex);
// Each component of the varying being captured is loaded one by one. This uses the
// OpAccessChain instruction that takes a chain of "indices" to end up with the
// component starting from the base variable. For example:
//
// var.member[3][2][0]
//
// where member is field number 4 in var and is a mat4, the access chain would be:
//
// 4 3 2 0
// ^ ^ ^ ^
// | | | |
// | | | row 0
// | | column 2
// | array element 3
// field 4
//
// The following tracks the access chain as the field, array elements, columns and rows
// are looped over.
spirv::IdRefList indexList;
AccessChainIndexListAppend appendField(
varying.fieldIndex != ShaderInterfaceVariableXfbInfo::kInvalid, mIntNIds,
varying.fieldIndex, &indexList);
// The varying being captured is either:
//
// - Not an array: In this case, no entry is added in the access chain
// - An element of the array
// - The whole array
//
uint32_t arrayIndexStart = 0;
uint32_t arrayIndexEnd = info->arraySize;
const bool isArray = info->arraySize != ShaderInterfaceVariableXfbInfo::kInvalid;
if (varying.info->arrayIndex != ShaderInterfaceVariableXfbInfo::kInvalid)
{
// Capturing a single element.
arrayIndexStart = varying.info->arrayIndex;
arrayIndexEnd = arrayIndexStart + 1;
}
else if (!isArray)
{
// Not an array.
arrayIndexEnd = 1;
}
// Sorting the varyings should have ensured that offsets are in order and that writing
// to the output buffer sequentially ends up using the correct offsets.
ASSERT(info->offset == offsetForVerification);
offsetForVerification += (arrayIndexEnd - arrayIndexStart) * info->rowCount *
info->columnCount * sizeof(float);
// Determine the type of the component being captured. OpBitcast is used (the
// implementation of intBitsToFloat() and uintBitsToFloat() for non-float types).
spirv::IdRef varyingTypeId;
spirv::IdRef varyingTypePtr;
const bool isPrivate = varyingPrecisionFixer.isReplaced(varying.baseId);
getVaryingTypeIds(ids, info->componentType, isPrivate, &varyingTypeId, &varyingTypePtr);
for (uint32_t arrayIndex = arrayIndexStart; arrayIndex < arrayIndexEnd; ++arrayIndex)
{
AccessChainIndexListAppend appendArrayIndex(isArray, mIntNIds, arrayIndex,
&indexList);
for (uint32_t col = 0; col < info->columnCount; ++col)
{
AccessChainIndexListAppend appendColumn(info->columnCount > 1, mIntNIds, col,
&indexList);
for (uint32_t row = 0; row < info->rowCount; ++row)
{
AccessChainIndexListAppend appendRow(info->rowCount > 1, mIntNIds, row,
&indexList);
// Generate the code to capture a single component of the varying:
//
// ANGLEXfbN.xfbOut[xfbOffset] = tfVarying0.field[index][row][col]
writeComponentCapture(ids, bufferIndex, xfbOffset, varyingTypeId,
varyingTypePtr, varying.baseId, indexList,
info->componentType, blobOut);
// Increment the offset:
//
// xfbOffset += 1;
//
// which translates to:
//
// %newOffsetId = OpIAdd %int %currentOffsetId %int1
spirv::IdRef nextOffset(SpirvTransformerBase::GetNewId(blobOut));
spirv::WriteIAdd(blobOut, ids.intId(), nextOffset, xfbOffset, mIntNIds[1]);
xfbOffset = nextOffset;
}
}
}
}
}
}
void SpirvTransformFeedbackCodeGenerator::getVaryingTypeIds(const SpirvIDDiscoverer &ids,
GLenum componentType,
bool isPrivate,
spirv::IdRef *typeIdOut,
spirv::IdRef *typePtrOut)
{
switch (componentType)
{
case GL_INT:
*typeIdOut = ids.intId();
*typePtrOut = isPrivate ? mIntPrivatePointerId : mIntOutputPointerId;
break;
case GL_UNSIGNED_INT:
*typeIdOut = ids.uintId();
*typePtrOut = isPrivate ? mUintPrivatePointerId : mUintOutputPointerId;
break;
case GL_FLOAT:
*typeIdOut = ids.floatId();
*typePtrOut = isPrivate ? mFloatPrivatePointerId : mFloatOutputPointerId;
break;
default:
UNREACHABLE();
}
ASSERT(typeIdOut->valid());
ASSERT(typePtrOut->valid());
}
void SpirvTransformFeedbackCodeGenerator::writeGetOffsetsCall(spirv::IdRef xfbOffsets,
SpirvBlob *blobOut)
{
const spirv::IdRef xfbGetOffsetsParam(SpirvTransformerBase::GetNewId(blobOut));
const spirv::IdRef xfbOffsetsResult(SpirvTransformerBase::GetNewId(blobOut));
const spirv::IdRef xfbOffsetsVar(SpirvTransformerBase::GetNewId(blobOut));
// Generate code for the following:
//
// ivec4 xfbOffsets = ANGLEGetXfbOffsets(ivec4(stride0, stride1, stride2, stride3));
// Create a variable to hold the parameter, initialized with the constant ivec4 containing the
// strides.
spirv::WriteVariable(blobOut, mIVec4FuncPointerId, xfbGetOffsetsParam,
spv::StorageClassFunction, &mBufferStridesCompositeId);
// Create a variable to hold the result.
spirv::WriteVariable(blobOut, mIVec4FuncPointerId, xfbOffsetsVar, spv::StorageClassFunction,
nullptr);
// Call a helper function generated by the translator to calculate the offsets for the current
// vertex.
spirv::WriteFunctionCall(blobOut, mIVec4Id, xfbOffsetsResult, mGetXfbOffsetsFuncId,
{xfbGetOffsetsParam});
// Store the results.
spirv::WriteStore(blobOut, xfbOffsetsVar, xfbOffsetsResult, nullptr);
// Load from the variable for use in expressions.
spirv::WriteLoad(blobOut, mIVec4Id, xfbOffsets, xfbOffsetsVar, nullptr);
}
void SpirvTransformFeedbackCodeGenerator::writeComponentCapture(
const SpirvIDDiscoverer &ids,
uint32_t bufferIndex,
spirv::IdRef xfbOffset,
spirv::IdRef varyingTypeId,
spirv::IdRef varyingTypePtr,
spirv::IdRef varyingBaseId,
const spirv::IdRefList &accessChainIndices,
GLenum componentType,
SpirvBlob *blobOut)
{
spirv::IdRef component(SpirvTransformerBase::GetNewId(blobOut));
spirv::IdRef xfbOutPtr(SpirvTransformerBase::GetNewId(blobOut));
// Generate code for the following:
//
// ANGLEXfbN.xfbOut[xfbOffset] = tfVarying0.field[index][row][col]
// Load from the component traversing the base variable with the given indices. If there are no
// indices, the variable can be loaded directly.
spirv::IdRef loadPtr = varyingBaseId;
if (!accessChainIndices.empty())
{
loadPtr = SpirvTransformerBase::GetNewId(blobOut);
spirv::WriteAccessChain(blobOut, varyingTypePtr, loadPtr, varyingBaseId,
accessChainIndices);
}
spirv::WriteLoad(blobOut, varyingTypeId, component, loadPtr, nullptr);
// If the varying is int or uint, bitcast it to float to store in the float[] array used to
// capture transform feedback output.
spirv::IdRef asFloat = component;
if (componentType != GL_FLOAT)
{
asFloat = SpirvTransformerBase::GetNewId(blobOut);
spirv::WriteBitcast(blobOut, ids.floatId(), asFloat, component);
}
// Store into the transform feedback capture buffer at the current offset. Note that this
// buffer has only one field (xfbOut), hence ANGLEXfbN.xfbOut[xfbOffset] translates to ANGLEXfbN
// with access chain {0, xfbOffset}.
spirv::WriteAccessChain(blobOut, mFloatUniformPointerId, xfbOutPtr, mXfbBuffers[bufferIndex],
{mIntNIds[0], xfbOffset});
spirv::WriteStore(blobOut, xfbOutPtr, asFloat, nullptr);
}
void SpirvTransformFeedbackCodeGenerator::addExecutionMode(spirv::IdRef entryPointId, void SpirvTransformFeedbackCodeGenerator::addExecutionMode(spirv::IdRef entryPointId,
SpirvBlob *blobOut) SpirvBlob *blobOut)
{ {
if (mIsEmulated)
{
return;
}
if (mHasTransformFeedbackOutput) if (mHasTransformFeedbackOutput)
{ {
spirv::WriteExecutionMode(blobOut, entryPointId, spv::ExecutionModeXfb); spirv::WriteExecutionMode(blobOut, entryPointId, spv::ExecutionModeXfb);
...@@ -2226,7 +2774,7 @@ void SpirvTransformFeedbackCodeGenerator::addMemberDecorate(const ShaderInterfac ...@@ -2226,7 +2774,7 @@ void SpirvTransformFeedbackCodeGenerator::addMemberDecorate(const ShaderInterfac
spirv::IdRef id, spirv::IdRef id,
SpirvBlob *blobOut) SpirvBlob *blobOut)
{ {
if (info.fieldXfb.empty()) if (mIsEmulated || info.fieldXfb.empty())
{ {
return; return;
} }
...@@ -2267,7 +2815,7 @@ void SpirvTransformFeedbackCodeGenerator::addDecorate(const ShaderInterfaceVaria ...@@ -2267,7 +2815,7 @@ void SpirvTransformFeedbackCodeGenerator::addDecorate(const ShaderInterfaceVaria
spirv::IdRef id, spirv::IdRef id,
SpirvBlob *blobOut) SpirvBlob *blobOut)
{ {
if (info.xfb.buffer == ShaderInterfaceVariableXfbInfo::kInvalid) if (mIsEmulated || info.xfb.buffer == ShaderInterfaceVariableXfbInfo::kInvalid)
{ {
return; return;
} }
...@@ -2478,6 +3026,7 @@ class SpirvTransformer final : public SpirvTransformerBase ...@@ -2478,6 +3026,7 @@ class SpirvTransformer final : public SpirvTransformerBase
SpirvBlob *spirvBlobOut) SpirvBlob *spirvBlobOut)
: SpirvTransformerBase(spirvBlobIn, variableInfoMap, spirvBlobOut), : SpirvTransformerBase(spirvBlobIn, variableInfoMap, spirvBlobOut),
mOptions(options), mOptions(options),
mXfbCodeGenerator(options.isTransformFeedbackEmulated),
mPositionTransformer(options) mPositionTransformer(options)
{} {}
...@@ -2528,7 +3077,7 @@ class SpirvTransformer final : public SpirvTransformerBase ...@@ -2528,7 +3077,7 @@ class SpirvTransformer final : public SpirvTransformerBase
// Traversal state: // Traversal state:
bool mInsertFunctionVariables = false; bool mInsertFunctionVariables = false;
spirv::IdRef mEntryPointId; spirv::IdRef mEntryPointId;
spirv::IdRef mOpFunctionId; spirv::IdRef mCurrentFunctionId;
SpirvIDDiscoverer mIds; SpirvIDDiscoverer mIds;
...@@ -2622,6 +3171,7 @@ void SpirvTransformer::resolveVariableIds() ...@@ -2622,6 +3171,7 @@ void SpirvTransformer::resolveVariableIds()
currentWord += wordCount; currentWord += wordCount;
} }
UNREACHABLE();
} }
void SpirvTransformer::transformInstruction() void SpirvTransformer::transformInstruction()
...@@ -2635,7 +3185,8 @@ void SpirvTransformer::transformInstruction() ...@@ -2635,7 +3185,8 @@ void SpirvTransformer::transformInstruction()
spirv::IdResultType id; spirv::IdResultType id;
spv::FunctionControlMask functionControl; spv::FunctionControlMask functionControl;
spirv::IdRef functionType; spirv::IdRef functionType;
spirv::ParseFunction(instruction, &id, &mOpFunctionId, &functionControl, &functionType); spirv::ParseFunction(instruction, &id, &mCurrentFunctionId, &functionControl,
&functionType);
// SPIR-V is structured in sections. Function declarations come last. Only a few // SPIR-V is structured in sections. Function declarations come last. Only a few
// instructions such as Op*Access* or OpEmitVertex opcodes inside functions need to be // instructions such as Op*Access* or OpEmitVertex opcodes inside functions need to be
...@@ -2652,7 +3203,7 @@ void SpirvTransformer::transformInstruction() ...@@ -2652,7 +3203,7 @@ void SpirvTransformer::transformInstruction()
// Only write function variables for the EntryPoint function for non-compute shaders // Only write function variables for the EntryPoint function for non-compute shaders
mInsertFunctionVariables = mInsertFunctionVariables =
mOpFunctionId == mEntryPointId && mOptions.shaderType != gl::ShaderType::Compute; mCurrentFunctionId == mEntryPointId && mOptions.shaderType != gl::ShaderType::Compute;
} }
// Only look at interesting instructions. // Only look at interesting instructions.
...@@ -2749,7 +3300,8 @@ void SpirvTransformer::transformInstruction() ...@@ -2749,7 +3300,8 @@ void SpirvTransformer::transformInstruction()
void SpirvTransformer::writePendingDeclarations() void SpirvTransformer::writePendingDeclarations()
{ {
// Pre-rotation and transformation of depth to Vulkan clip space require declarations that may // Pre-rotation and transformation of depth to Vulkan clip space require declarations that may
// not necessarily be in the shader. // not necessarily be in the shader. Transform feedback emulation additionally requires a few
// overlapping ids.
if (IsRotationIdentity(mOptions.preRotation) && !mOptions.transformPositionToVulkanClipSpace && if (IsRotationIdentity(mOptions.preRotation) && !mOptions.transformPositionToVulkanClipSpace &&
!mOptions.isTransformFeedbackStage) !mOptions.isTransformFeedbackStage)
{ {
...@@ -2757,6 +3309,7 @@ void SpirvTransformer::writePendingDeclarations() ...@@ -2757,6 +3309,7 @@ void SpirvTransformer::writePendingDeclarations()
} }
mIds.writePendingDeclarations(mSpirvBlobOut); mIds.writePendingDeclarations(mSpirvBlobOut);
mXfbCodeGenerator.writePendingDeclarations(mVariableInfoById, mIds, mSpirvBlobOut);
} }
// Called by transformInstruction to insert necessary instructions for casting varyings. // Called by transformInstruction to insert necessary instructions for casting varyings.
...@@ -2781,7 +3334,9 @@ void SpirvTransformer::writeOutputPrologue() ...@@ -2781,7 +3334,9 @@ void SpirvTransformer::writeOutputPrologue()
// Whether gl_Position should be transformed to account for prerotation and Vulkan clip space. // Whether gl_Position should be transformed to account for prerotation and Vulkan clip space.
const bool transformPosition = const bool transformPosition =
!IsRotationIdentity(mOptions.preRotation) || mOptions.transformPositionToVulkanClipSpace; !IsRotationIdentity(mOptions.preRotation) || mOptions.transformPositionToVulkanClipSpace;
if (!transformPosition && !mOptions.isTransformFeedbackStage) const bool isXfbExtensionStage =
mOptions.isTransformFeedbackStage && !mOptions.isTransformFeedbackEmulated;
if (!transformPosition && !isXfbExtensionStage)
{ {
return; return;
} }
...@@ -2801,9 +3356,9 @@ void SpirvTransformer::writeOutputPrologue() ...@@ -2801,9 +3356,9 @@ void SpirvTransformer::writeOutputPrologue()
spirv::WriteLoad(mSpirvBlobOut, mIds.vec4Id(), positionId, positionPointerId, nullptr); spirv::WriteLoad(mSpirvBlobOut, mIds.vec4Id(), positionId, positionPointerId, nullptr);
// Write transform feedback output before modifying gl_Position. // Write transform feedback output before modifying gl_Position.
if (mOptions.isTransformFeedbackStage) if (isXfbExtensionStage)
{ {
mXfbCodeGenerator.writeTransformFeedbackOutput(positionId, mSpirvBlobOut); mXfbCodeGenerator.writeTransformFeedbackExtensionOutput(mIds, positionId, mSpirvBlobOut);
} }
if (transformPosition) if (transformPosition)
...@@ -2840,6 +3395,7 @@ void SpirvTransformer::visitName(const uint32_t *instruction) ...@@ -2840,6 +3395,7 @@ void SpirvTransformer::visitName(const uint32_t *instruction)
spirv::ParseName(instruction, &id, &name); spirv::ParseName(instruction, &id, &name);
mIds.visitName(id, name); mIds.visitName(id, name);
mXfbCodeGenerator.visitName(id, name);
} }
void SpirvTransformer::visitMemberName(const uint32_t *instruction) void SpirvTransformer::visitMemberName(const uint32_t *instruction)
...@@ -2897,6 +3453,7 @@ void SpirvTransformer::visitTypePointer(const uint32_t *instruction) ...@@ -2897,6 +3453,7 @@ void SpirvTransformer::visitTypePointer(const uint32_t *instruction)
mIds.visitTypePointer(id, storageClass, typeId); mIds.visitTypePointer(id, storageClass, typeId);
mVaryingPrecisionFixer.visitTypePointer(id, storageClass, typeId); mVaryingPrecisionFixer.visitTypePointer(id, storageClass, typeId);
mXfbCodeGenerator.visitTypePointer(id, storageClass, typeId);
} }
void SpirvTransformer::visitTypeVector(const uint32_t *instruction) void SpirvTransformer::visitTypeVector(const uint32_t *instruction)
...@@ -2907,6 +3464,7 @@ void SpirvTransformer::visitTypeVector(const uint32_t *instruction) ...@@ -2907,6 +3464,7 @@ void SpirvTransformer::visitTypeVector(const uint32_t *instruction)
spirv::ParseTypeVector(instruction, &id, &componentId, &componentCount); spirv::ParseTypeVector(instruction, &id, &componentId, &componentCount);
mIds.visitTypeVector(id, componentId, componentCount); mIds.visitTypeVector(id, componentId, componentCount);
mXfbCodeGenerator.visitTypeVector(mIds, id, componentId, componentCount);
} }
void SpirvTransformer::visitVariable(const uint32_t *instruction) void SpirvTransformer::visitVariable(const uint32_t *instruction)
...@@ -3164,8 +3722,16 @@ TransformationState SpirvTransformer::transformTypeStruct(const uint32_t *instru ...@@ -3164,8 +3722,16 @@ TransformationState SpirvTransformer::transformTypeStruct(const uint32_t *instru
TransformationState SpirvTransformer::transformReturn(const uint32_t *instruction) TransformationState SpirvTransformer::transformReturn(const uint32_t *instruction)
{ {
if (mOpFunctionId != mEntryPointId) if (mCurrentFunctionId != mEntryPointId)
{ {
if (mOptions.isTransformFeedbackStage)
{
// Transform feedback emulation is written to a designated function. Allow its code to
// be generated if this is the right function.
mXfbCodeGenerator.writeTransformFeedbackEmulationOutput(
mIds, mVaryingPrecisionFixer, mCurrentFunctionId, mSpirvBlobOut);
}
// We only need to process the precision info when returning from the entry point function // We only need to process the precision info when returning from the entry point function
return TransformationState::Unchanged; return TransformationState::Unchanged;
} }
...@@ -4398,17 +4964,6 @@ std::string GetXfbBufferName(const uint32_t bufferIndex) ...@@ -4398,17 +4964,6 @@ std::string GetXfbBufferName(const uint32_t bufferIndex)
return sh::vk::kXfbEmulationBufferBlockName + Str(bufferIndex); return sh::vk::kXfbEmulationBufferBlockName + Str(bufferIndex);
} }
void GlslangGenTransformFeedbackEmulationOutputs(const GlslangSourceOptions &options,
const gl::ProgramState &programState,
GlslangProgramInterfaceInfo *programInterfaceInfo,
std::string *vertexShader,
ShaderInterfaceVariableInfoMap *variableInfoMapOut)
{
GenerateTransformFeedbackEmulationOutputs(options, gl::ShaderType::Vertex, programState,
programInterfaceInfo, vertexShader,
variableInfoMapOut);
}
void GlslangAssignLocations(const GlslangSourceOptions &options, void GlslangAssignLocations(const GlslangSourceOptions &options,
const gl::ProgramState &programState, const gl::ProgramState &programState,
const gl::ProgramVaryingPacking &varyingPacking, const gl::ProgramVaryingPacking &varyingPacking,
...@@ -4462,11 +5017,11 @@ void GlslangAssignLocations(const GlslangSourceOptions &options, ...@@ -4462,11 +5017,11 @@ void GlslangAssignLocations(const GlslangSourceOptions &options,
// Assign qualifiers to all varyings captured by transform feedback // Assign qualifiers to all varyings captured by transform feedback
if (!programExecutable.getLinkedTransformFeedbackVaryings().empty() && if (!programExecutable.getLinkedTransformFeedbackVaryings().empty() &&
options.supportsTransformFeedbackExtension && shaderType == programExecutable.getLinkedTransformFeedbackStage())
(shaderType == programExecutable.getLinkedTransformFeedbackStage()))
{ {
AssignTransformFeedbackExtensionQualifiers(programExecutable, outputPacking, shaderType, AssignTransformFeedbackQualifiers(programExecutable, outputPacking, shaderType,
variableInfoMapOut); options.supportsTransformFeedbackExtension,
variableInfoMapOut);
} }
} }
...@@ -4503,26 +5058,7 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options, ...@@ -4503,26 +5058,7 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options,
(*shaderSourcesOut)[shaderType] = glShader ? glShader->getTranslatedSource() : ""; (*shaderSourcesOut)[shaderType] = glShader ? glShader->getTranslatedSource() : "";
} }
gl::ShaderType xfbStage = programState.getAttachedTransformFeedbackStage(); gl::ShaderType xfbStage = programState.getAttachedTransformFeedbackStage();
std::string *xfbSource = &(*shaderSourcesOut)[xfbStage];
// Write transform feedback output code for emulation path
if (xfbStage == gl::ShaderType::Vertex && !xfbSource->empty() &&
options.supportsTransformFeedbackEmulation)
{
if (options.enableTransformFeedbackEmulation &&
!programState.getLinkedTransformFeedbackVaryings().empty())
{
GenerateTransformFeedbackEmulationOutputs(options, xfbStage, programState,
programInterfaceInfo, xfbSource,
variableInfoMapOut);
}
else
{
*xfbSource = SubstituteTransformFeedbackMarkers(*xfbSource, "");
}
}
gl::ShaderType frontShaderType = gl::ShaderType::InvalidEnum; gl::ShaderType frontShaderType = gl::ShaderType::InvalidEnum;
for (const gl::ShaderType shaderType : programState.getExecutable().getLinkedShaderStages()) for (const gl::ShaderType shaderType : programState.getExecutable().getLinkedShaderStages())
......
...@@ -65,6 +65,7 @@ struct GlslangSpirvOptions ...@@ -65,6 +65,7 @@ struct GlslangSpirvOptions
bool removeEarlyFragmentTestsOptimization = false; bool removeEarlyFragmentTestsOptimization = false;
bool removeDebugInfo = false; bool removeDebugInfo = false;
bool isTransformFeedbackStage = false; bool isTransformFeedbackStage = false;
bool isTransformFeedbackEmulated = false;
}; };
using SpirvBlob = std::vector<uint32_t>; using SpirvBlob = std::vector<uint32_t>;
...@@ -75,9 +76,19 @@ struct ShaderInterfaceVariableXfbInfo ...@@ -75,9 +76,19 @@ struct ShaderInterfaceVariableXfbInfo
{ {
static constexpr uint32_t kInvalid = std::numeric_limits<uint32_t>::max(); static constexpr uint32_t kInvalid = std::numeric_limits<uint32_t>::max();
// Used by both extension and emulation
uint32_t buffer = kInvalid; uint32_t buffer = kInvalid;
uint32_t offset = kInvalid; uint32_t offset = kInvalid;
uint32_t stride = kInvalid; uint32_t stride = kInvalid;
// Used only by emulation (array index support is missing from VK_EXT_transform_feedback)
uint32_t arraySize = kInvalid;
uint32_t columnCount = kInvalid;
uint32_t rowCount = kInvalid;
uint32_t arrayIndex = kInvalid;
GLenum componentType = GL_FLOAT;
// If empty, the whole array is captured. Otherwise only the specified members are captured.
std::vector<ShaderInterfaceVariableXfbInfo> arrayElements;
}; };
// Information for each shader interface variable. Not all fields are relevant to each shader // Information for each shader interface variable. Not all fields are relevant to each shader
...@@ -169,14 +180,6 @@ bool GetImageNameWithoutIndices(std::string *name); ...@@ -169,14 +180,6 @@ bool GetImageNameWithoutIndices(std::string *name);
std::string GlslangGetMappedSamplerName(const std::string &originalName); std::string GlslangGetMappedSamplerName(const std::string &originalName);
std::string GetXfbBufferName(const uint32_t bufferIndex); std::string GetXfbBufferName(const uint32_t bufferIndex);
// NOTE: options.emulateTransformFeedback is ignored in this case. It is assumed to be always true.
void GlslangGenTransformFeedbackEmulationOutputs(
const GlslangSourceOptions &options,
const gl::ProgramState &programState,
GlslangProgramInterfaceInfo *programInterfaceInfo,
std::string *vertexShader,
ShaderInterfaceVariableInfoMap *variableInfoMapOut);
void GlslangAssignLocations(const GlslangSourceOptions &options, void GlslangAssignLocations(const GlslangSourceOptions &options,
const gl::ProgramState &programState, const gl::ProgramState &programState,
const gl::ProgramVaryingPacking &varyingPacking, const gl::ProgramVaryingPacking &varyingPacking,
......
...@@ -317,11 +317,9 @@ angle::Result ProgramMtl::linkImpl(const gl::Context *glContext, ...@@ -317,11 +317,9 @@ angle::Result ProgramMtl::linkImpl(const gl::Context *glContext,
// Gather variable info and transform sources. // Gather variable info and transform sources.
gl::ShaderMap<std::string> shaderSources; gl::ShaderMap<std::string> shaderSources;
gl::ShaderMap<std::string> xfbOnlyShaderSources;
ShaderInterfaceVariableInfoMap variableInfoMap; ShaderInterfaceVariableInfoMap variableInfoMap;
ShaderInterfaceVariableInfoMap xfbOnlyVariableInfoMap; ShaderInterfaceVariableInfoMap xfbOnlyVariableInfoMap;
mtl::GlslangGetShaderSource(mState, resources, &shaderSources, mtl::GlslangGetShaderSource(mState, resources, &shaderSources, &variableInfoMap,
&xfbOnlyShaderSources[gl::ShaderType::Vertex], &variableInfoMap,
&xfbOnlyVariableInfoMap); &xfbOnlyVariableInfoMap);
// Convert GLSL to spirv code // Convert GLSL to spirv code
...@@ -329,14 +327,14 @@ angle::Result ProgramMtl::linkImpl(const gl::Context *glContext, ...@@ -329,14 +327,14 @@ angle::Result ProgramMtl::linkImpl(const gl::Context *glContext,
gl::ShaderMap<std::vector<uint32_t>> xfbOnlyShaderCodes; // only vertex shader is needed. gl::ShaderMap<std::vector<uint32_t>> xfbOnlyShaderCodes; // only vertex shader is needed.
ANGLE_TRY(mtl::GlslangGetShaderSpirvCode( ANGLE_TRY(mtl::GlslangGetShaderSpirvCode(
contextMtl, mState.getExecutable().getLinkedShaderStages(), contextMtl->getCaps(), contextMtl, mState.getExecutable().getLinkedShaderStages(), contextMtl->getCaps(),
shaderSources, variableInfoMap, &shaderCodes)); shaderSources, false, variableInfoMap, &shaderCodes));
if (!mState.getLinkedTransformFeedbackVaryings().empty()) if (!mState.getLinkedTransformFeedbackVaryings().empty())
{ {
gl::ShaderBitSet onlyVS; gl::ShaderBitSet onlyVS;
onlyVS.set(gl::ShaderType::Vertex); onlyVS.set(gl::ShaderType::Vertex);
ANGLE_TRY(mtl::GlslangGetShaderSpirvCode(contextMtl, onlyVS, contextMtl->getCaps(), ANGLE_TRY(mtl::GlslangGetShaderSpirvCode(contextMtl, onlyVS, contextMtl->getCaps(),
xfbOnlyShaderSources, xfbOnlyVariableInfoMap, shaderSources, true, xfbOnlyVariableInfoMap,
&xfbOnlyShaderCodes)); &xfbOnlyShaderCodes));
} }
......
...@@ -41,12 +41,10 @@ struct TranslatedShaderInfo ...@@ -41,12 +41,10 @@ struct TranslatedShaderInfo
bool hasUBOArgumentBuffer; bool hasUBOArgumentBuffer;
}; };
// - shaderSourcesOut is result GLSL code per shader stage when XFB emulation is turned off. // shaderSourcesOut is result GLSL code per shader stage.
// - xfbOnlyShaderSourceOut will contain vertex shader's GLSL code when XFB emulation is turned on.
void GlslangGetShaderSource(const gl::ProgramState &programState, void GlslangGetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources, const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut, gl::ShaderMap<std::string> *shaderSourcesOut,
std::string *xfbOnlyShaderSourceOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut, ShaderInterfaceVariableInfoMap *variableInfoMapOut,
ShaderInterfaceVariableInfoMap *xfbOnlyVSVariableInfoMapOut); ShaderInterfaceVariableInfoMap *xfbOnlyVSVariableInfoMapOut);
...@@ -54,6 +52,7 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context, ...@@ -54,6 +52,7 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
const gl::ShaderBitSet &linkedShaderStages, const gl::ShaderBitSet &linkedShaderStages,
const gl::Caps &glCaps, const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
bool isTransformFeedbackEnabled,
const ShaderInterfaceVariableInfoMap &variableInfoMap, const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut); gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut);
......
...@@ -406,7 +406,6 @@ void TranslatedShaderInfo::reset() ...@@ -406,7 +406,6 @@ void TranslatedShaderInfo::reset()
void GlslangGetShaderSource(const gl::ProgramState &programState, void GlslangGetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources, const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut, gl::ShaderMap<std::string> *shaderSourcesOut,
std::string *xfbOnlyShaderSourceOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut, ShaderInterfaceVariableInfoMap *variableInfoMapOut,
ShaderInterfaceVariableInfoMap *xfbOnlyVSVariableInfoMapOut) ShaderInterfaceVariableInfoMap *xfbOnlyVSVariableInfoMapOut)
{ {
...@@ -416,32 +415,21 @@ void GlslangGetShaderSource(const gl::ProgramState &programState, ...@@ -416,32 +415,21 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
options.supportsTransformFeedbackEmulation = true; options.supportsTransformFeedbackEmulation = true;
// This will generate shader source WITHOUT XFB emulated outputs. // Get shader sources and fill variable info map with transform feedback disabled.
rx::GlslangGetShaderSource(options, programState, resources, &programInterfaceInfo, rx::GlslangGetShaderSource(options, programState, resources, &programInterfaceInfo,
shaderSourcesOut, variableInfoMapOut); shaderSourcesOut, variableInfoMapOut);
// This will generate vertex shader source WITH XFB emulated outputs. // Fill variable info map with transform feedback enabled.
if (xfbOnlyShaderSourceOut && !programState.getLinkedTransformFeedbackVaryings().empty()) if (!programState.getLinkedTransformFeedbackVaryings().empty())
{ {
gl::Shader *glShader = programState.getAttachedShader(gl::ShaderType::Vertex);
*xfbOnlyShaderSourceOut = glShader ? glShader->getTranslatedSource() : "";
GlslangProgramInterfaceInfo xfbOnlyInterfaceInfo; GlslangProgramInterfaceInfo xfbOnlyInterfaceInfo;
ResetGlslangProgramInterfaceInfo(&xfbOnlyInterfaceInfo); ResetGlslangProgramInterfaceInfo(&xfbOnlyInterfaceInfo);
options.enableTransformFeedbackEmulation = true; options.enableTransformFeedbackEmulation = true;
rx::GlslangGenTransformFeedbackEmulationOutputs(
options, programState, &xfbOnlyInterfaceInfo, xfbOnlyShaderSourceOut,
xfbOnlyVSVariableInfoMapOut);
const bool isTransformFeedbackStage =
!programState.getLinkedTransformFeedbackVaryings().empty();
GlslangAssignLocations(options, programState, resources.varyingPacking, GlslangAssignLocations(options, programState, resources.varyingPacking,
gl::ShaderType::Vertex, gl::ShaderType::InvalidEnum, gl::ShaderType::Vertex, gl::ShaderType::InvalidEnum, true,
isTransformFeedbackStage, &xfbOnlyInterfaceInfo, &xfbOnlyInterfaceInfo, xfbOnlyVSVariableInfoMapOut);
xfbOnlyVSVariableInfoMapOut);
} }
} }
...@@ -449,6 +437,7 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context, ...@@ -449,6 +437,7 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
const gl::ShaderBitSet &linkedShaderStages, const gl::ShaderBitSet &linkedShaderStages,
const gl::Caps &glCaps, const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources, const gl::ShaderMap<std::string> &shaderSources,
bool isTransformFeedbackEnabled,
const ShaderInterfaceVariableInfoMap &variableInfoMap, const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut) gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut)
{ {
...@@ -463,7 +452,9 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context, ...@@ -463,7 +452,9 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
GlslangSpirvOptions options; GlslangSpirvOptions options;
options.shaderType = shaderType; options.shaderType = shaderType;
options.transformPositionToVulkanClipSpace = true; options.transformPositionToVulkanClipSpace = true;
options.isTransformFeedbackStage = shaderType == gl::ShaderType::Vertex; options.isTransformFeedbackStage =
shaderType == gl::ShaderType::Vertex && isTransformFeedbackEnabled;
options.isTransformFeedbackEmulated = true;
angle::Result status = GlslangTransformSpirvCode( angle::Result status = GlslangTransformSpirvCode(
[context](GlslangError error) { return HandleError(context, error); }, options, [context](GlslangError error) { return HandleError(context, error); }, options,
......
...@@ -24,6 +24,42 @@ namespace rx ...@@ -24,6 +24,42 @@ namespace rx
{ {
namespace namespace
{ {
void LoadShaderInterfaceVariableXfbInfo(gl::BinaryInputStream *stream,
ShaderInterfaceVariableXfbInfo *xfb)
{
xfb->buffer = stream->readInt<uint32_t>();
xfb->offset = stream->readInt<uint32_t>();
xfb->stride = stream->readInt<uint32_t>();
xfb->arraySize = stream->readInt<uint32_t>();
xfb->columnCount = stream->readInt<uint32_t>();
xfb->rowCount = stream->readInt<uint32_t>();
xfb->arrayIndex = stream->readInt<uint32_t>();
xfb->componentType = stream->readInt<uint32_t>();
xfb->arrayElements.resize(stream->readInt<size_t>());
for (ShaderInterfaceVariableXfbInfo &arrayElement : xfb->arrayElements)
{
LoadShaderInterfaceVariableXfbInfo(stream, &arrayElement);
}
}
void SaveShaderInterfaceVariableXfbInfo(const ShaderInterfaceVariableXfbInfo &xfb,
gl::BinaryOutputStream *stream)
{
stream->writeInt(xfb.buffer);
stream->writeInt(xfb.offset);
stream->writeInt(xfb.stride);
stream->writeInt(xfb.arraySize);
stream->writeInt(xfb.columnCount);
stream->writeInt(xfb.rowCount);
stream->writeInt(xfb.arrayIndex);
stream->writeInt(xfb.componentType);
stream->writeInt(xfb.arrayElements.size());
for (const ShaderInterfaceVariableXfbInfo &arrayElement : xfb.arrayElements)
{
SaveShaderInterfaceVariableXfbInfo(arrayElement, stream);
}
}
bool ValidateTransformedSpirV(ContextVk *contextVk, bool ValidateTransformedSpirV(ContextVk *contextVk,
const gl::ShaderBitSet &linkedShaderStages, const gl::ShaderBitSet &linkedShaderStages,
const ShaderInterfaceVariableInfoMap &variableInfoMap, const ShaderInterfaceVariableInfoMap &variableInfoMap,
...@@ -125,6 +161,7 @@ ProgramInfo::~ProgramInfo() = default; ...@@ -125,6 +161,7 @@ ProgramInfo::~ProgramInfo() = default;
angle::Result ProgramInfo::initProgram(ContextVk *contextVk, angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
bool isLastPreFragmentStage, bool isLastPreFragmentStage,
bool isTransformFeedbackProgram,
const ShaderInfo &shaderInfo, const ShaderInfo &shaderInfo,
ProgramTransformOptions optionBits, ProgramTransformOptions optionBits,
const ShaderInterfaceVariableInfoMap &variableInfoMap) const ShaderInterfaceVariableInfoMap &variableInfoMap)
...@@ -138,9 +175,10 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk, ...@@ -138,9 +175,10 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
options.shaderType = shaderType; options.shaderType = shaderType;
options.removeEarlyFragmentTestsOptimization = options.removeEarlyFragmentTestsOptimization =
shaderType == gl::ShaderType::Fragment && optionBits.removeEarlyFragmentTestsOptimization; shaderType == gl::ShaderType::Fragment && optionBits.removeEarlyFragmentTestsOptimization;
options.removeDebugInfo = !contextVk->getRenderer()->getEnableValidationLayers(); options.removeDebugInfo = !contextVk->getRenderer()->getEnableValidationLayers();
options.isTransformFeedbackStage = isLastPreFragmentStage; options.isTransformFeedbackStage = isLastPreFragmentStage && isTransformFeedbackProgram;
options.negativeViewportSupported = contextVk->getFeatures().supportsNegativeViewport.enabled; options.isTransformFeedbackEmulated = contextVk->getFeatures().emulateTransformFeedback.enabled;
options.negativeViewportSupported = contextVk->getFeatures().supportsNegativeViewport.enabled;
if (isLastPreFragmentStage) if (isLastPreFragmentStage)
{ {
...@@ -245,15 +283,11 @@ std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(gl::BinaryInputStream * ...@@ -245,15 +283,11 @@ std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(gl::BinaryInputStream *
info.component = stream->readInt<uint32_t>(); info.component = stream->readInt<uint32_t>();
// PackedEnumBitSet uses uint8_t // PackedEnumBitSet uses uint8_t
info.activeStages = gl::ShaderBitSet(stream->readInt<uint8_t>()); info.activeStages = gl::ShaderBitSet(stream->readInt<uint8_t>());
info.xfb.buffer = stream->readInt<uint32_t>(); LoadShaderInterfaceVariableXfbInfo(stream, &info.xfb);
info.xfb.offset = stream->readInt<uint32_t>();
info.xfb.stride = stream->readInt<uint32_t>();
info.fieldXfb.resize(stream->readInt<size_t>()); info.fieldXfb.resize(stream->readInt<size_t>());
for (ShaderInterfaceVariableXfbInfo &xfb : info.fieldXfb) for (ShaderInterfaceVariableXfbInfo &xfb : info.fieldXfb)
{ {
xfb.buffer = stream->readInt<uint32_t>(); LoadShaderInterfaceVariableXfbInfo(stream, &xfb);
xfb.offset = stream->readInt<uint32_t>();
xfb.stride = stream->readInt<uint32_t>();
} }
info.useRelaxedPrecision = stream->readBool(); info.useRelaxedPrecision = stream->readBool();
info.varyingIsInput = stream->readBool(); info.varyingIsInput = stream->readBool();
...@@ -283,15 +317,11 @@ void ProgramExecutableVk::save(gl::BinaryOutputStream *stream) ...@@ -283,15 +317,11 @@ void ProgramExecutableVk::save(gl::BinaryOutputStream *stream)
stream->writeInt(info.component); stream->writeInt(info.component);
// PackedEnumBitSet uses uint8_t // PackedEnumBitSet uses uint8_t
stream->writeInt(info.activeStages.bits()); stream->writeInt(info.activeStages.bits());
stream->writeInt(info.xfb.buffer); SaveShaderInterfaceVariableXfbInfo(info.xfb, stream);
stream->writeInt(info.xfb.offset);
stream->writeInt(info.xfb.stride);
stream->writeInt(info.fieldXfb.size()); stream->writeInt(info.fieldXfb.size());
for (const ShaderInterfaceVariableXfbInfo &xfb : info.fieldXfb) for (const ShaderInterfaceVariableXfbInfo &xfb : info.fieldXfb)
{ {
stream->writeInt(xfb.buffer); SaveShaderInterfaceVariableXfbInfo(xfb, stream);
stream->writeInt(xfb.offset);
stream->writeInt(xfb.stride);
} }
stream->writeBool(info.useRelaxedPrecision); stream->writeBool(info.useRelaxedPrecision);
stream->writeBool(info.varyingIsInput); stream->writeBool(info.varyingIsInput);
......
...@@ -69,6 +69,7 @@ class ProgramInfo final : angle::NonCopyable ...@@ -69,6 +69,7 @@ class ProgramInfo final : angle::NonCopyable
angle::Result initProgram(ContextVk *contextVk, angle::Result initProgram(ContextVk *contextVk,
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
bool isLastPreFragmentStage, bool isLastPreFragmentStage,
bool isTransformFeedbackProgram,
const ShaderInfo &shaderInfo, const ShaderInfo &shaderInfo,
ProgramTransformOptions optionBits, ProgramTransformOptions optionBits,
const ShaderInterfaceVariableInfoMap &variableInfoMap); const ShaderInterfaceVariableInfoMap &variableInfoMap);
......
...@@ -269,7 +269,7 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context, ...@@ -269,7 +269,7 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
// Gather variable info and transform sources. // Gather variable info and transform sources.
gl::ShaderMap<std::string> shaderSources; gl::ShaderMap<std::string> shaderSources;
GlslangWrapperVk::GetShaderSource(contextVk->getRenderer()->getFeatures(), mState, resources, GlslangWrapperVk::GetShaderSource(contextVk->getFeatures(), mState, resources,
&mGlslangProgramInterfaceInfo, &shaderSources, &mGlslangProgramInterfaceInfo, &shaderSources,
&mExecutable.mVariableInfoMap); &mExecutable.mVariableInfoMap);
......
...@@ -208,8 +208,11 @@ class ProgramVk : public ProgramImpl ...@@ -208,8 +208,11 @@ class ProgramVk : public ProgramImpl
// specialization constants. // specialization constants.
if (!programInfo->valid(shaderType)) if (!programInfo->valid(shaderType))
{ {
const bool isTransformFeedbackProgram =
!mState.getLinkedTransformFeedbackVaryings().empty();
ANGLE_TRY(programInfo->initProgram(contextVk, shaderType, isLastPreFragmentStage, ANGLE_TRY(programInfo->initProgram(contextVk, shaderType, isLastPreFragmentStage,
mOriginalShaderInfo, optionBits, variableInfoMap)); isTransformFeedbackProgram, mOriginalShaderInfo,
optionBits, variableInfoMap));
} }
ASSERT(programInfo->valid(shaderType)); ASSERT(programInfo->valid(shaderType));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment