Commit 0bfa5504 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Emulate Transform Feedback with vertex shader output

In ES 3.0 and 3.1, only non-indexed GL_POINTS, GL_LINES and GL_TRIANGLES is supported for transform feedback. Without tessellation and geometry shaders, we can calculate the exact location where each vertex transform output should be written on the CPU, and have each vertex shader invocation write its data separately to the appropriate location in the buffer. This depends on the vertexPipelineStoresAndAtomics Vulkan feature. Bug: angleproject:3205 Change-Id: I68ccbb80aece597cf20c557a0aee842360fea593 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1645678 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 235e56fb
......@@ -118,6 +118,13 @@ struct FeaturesVk : FeatureSetBase
"supports_shader_stencil_export", FeatureCategory::VulkanFeatures,
"VkDevice supports the VK_EXT_shader_stencil_export extension", &members};
// Where VK_EXT_transform_feedback is not support, an emulation path is used.
// http://anglebug.com/3205
Feature emulateTransformFeedback = {
"emulate_transform_feedback", FeatureCategory::VulkanFeatures,
"Emulate transform feedback as the VK_EXT_transform_feedback is not present.", &members,
"http://anglebug.com/3205"};
// VK_PRESENT_MODE_FIFO_KHR causes random timeouts on Linux Intel. http://anglebug.com/3153
Feature disableFifoPresentMode = {
"disable_fifo_present_mode", FeatureCategory::VulkanWorkarounds,
......
......@@ -466,7 +466,7 @@
"proc table:src/libGLESv2/proc_table_autogen.cpp":
"e82a9970d6059a7c8b562726e3f219a4",
"uniform type:src/common/gen_uniform_type_table.py":
"9dd389f2b5793ba635169d61cef2dde9",
"a741cc301b1617ab0e4d29b35f1d3b96",
"uniform type:src/common/uniform_type_info_autogen.cpp":
"b31d181bc49ad1c3540401a5c874e692"
"d1cea53e456de010445790b8de94a50e"
}
\ No newline at end of file
......@@ -94,7 +94,7 @@ const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType)
}} // 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} }}"""
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_index_case_template = """case {enum_value}: return {index_value};"""
......@@ -183,15 +183,15 @@ def get_components(uniform_type):
def get_component_size(uniform_type):
component_type = get_component_type(uniform_type)
if (component_type) == "GL_BOOL":
if component_type == "GL_BOOL":
return "sizeof(GLint)"
elif (component_type) == "GL_FLOAT":
elif component_type == "GL_FLOAT":
return "sizeof(GLfloat)"
elif (component_type) == "GL_INT":
elif component_type == "GL_INT":
return "sizeof(GLint)"
elif (component_type) == "GL_UNSIGNED_INT":
elif component_type == "GL_UNSIGNED_INT":
return "sizeof(GLuint)"
elif (component_type) == "GL_NONE":
elif component_type == "GL_NONE":
return "0"
else:
raise "Invalid component type: " + component_type
......@@ -217,6 +217,22 @@ def get_is_image(uniform_type):
return cpp_bool("_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):
return type_info_data_template.format(
type=uniform_type,
......@@ -233,7 +249,8 @@ def gen_type_info(uniform_type):
external_size=get_external_size(uniform_type),
is_sampler=get_is_sampler(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):
......
......@@ -20,150 +20,159 @@ namespace
{
constexpr std::array<UniformTypeInfo, 62> kInfoTable = {
{{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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, "intBitsToFloat"},
{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,
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, "intBitsToFloat"},
{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_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},
sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, false, "intBitsToFloat"},
{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},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, "intBitsToFloat"},
{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,
false, false, true},
false, false, true, "intBitsToFloat"},
{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},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, false, false, true, "intBitsToFloat"},
{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_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},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"},
{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,
SamplerFormat::Signed, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true,
false, false},
false, false, "intBitsToFloat"},
{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,
true, false, false},
true, false, false, "intBitsToFloat"},
{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},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"},
{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_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},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 2, false, false, false, "intBitsToFloat"},
{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},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 3, false, false, false, "intBitsToFloat"},
{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},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 4, false, false, false, "intBitsToFloat"},
{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},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"},
{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,
SamplerFormat::Shadow, 1, 1, 1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true,
false, false},
false, false, "intBitsToFloat"},
{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,
false, false},
false, false, "intBitsToFloat"},
{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,
false, false},
false, false, "intBitsToFloat"},
{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},
1, sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"},
{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},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"},
{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},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"},
{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},
sizeof(GLint), sizeof(GLint) * 4, sizeof(GLint) * 1, true, false, false, "intBitsToFloat"},
{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_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,
false, false},
false, false, "intBitsToFloat"},
{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,
SamplerFormat::InvalidEnum, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
false, false, false},
false, false, false, "uintBitsToFloat"},
{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,
false, false, true},
false, false, true, "uintBitsToFloat"},
{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,
false, false, true},
false, false, true, "uintBitsToFloat"},
{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,
false, false, true},
false, false, true, "uintBitsToFloat"},
{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,
false, false, true},
false, false, true, "uintBitsToFloat"},
{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,
true, false, false},
true, false, false, "uintBitsToFloat"},
{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,
true, false, false},
true, false, false, "uintBitsToFloat"},
{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,
sizeof(GLuint) * 1, true, false, false},
sizeof(GLuint) * 1, true, false, false, "uintBitsToFloat"},
{GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, GL_UNSIGNED_INT,
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,
SamplerFormat::Unsigned, 1, 1, 1, sizeof(GLuint), sizeof(GLuint) * 4, sizeof(GLuint) * 1,
true, false, false},
true, false, false, "uintBitsToFloat"},
{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,
true, false, false},
true, false, false, "uintBitsToFloat"},
{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,
false, false, false},
false, false, false, "uintBitsToFloat"},
{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,
false, false, false},
false, false, false, "uintBitsToFloat"},
{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,
false, false, false}}};
false, false, false, "uintBitsToFloat"}}};
size_t GetTypeInfoIndex(GLenum uniformType)
{
......
......@@ -139,7 +139,8 @@ struct UniformTypeInfo final : angle::NonCopyable
size_t externalSize,
bool isSampler,
bool isMatrixType,
bool isImageType);
bool isImageType,
const char *glslAsFloat);
GLenum type;
GLenum componentType;
......@@ -156,6 +157,7 @@ struct UniformTypeInfo final : angle::NonCopyable
bool isSampler;
bool isMatrixType;
bool isImageType;
const char *glslAsFloat;
};
inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
......@@ -172,7 +174,8 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
size_t externalSize,
bool isSampler,
bool isMatrixType,
bool isImageType)
bool isImageType,
const char *glslAsFloat)
: type(type),
componentType(componentType),
textureType(textureType),
......@@ -187,7 +190,8 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
externalSize(externalSize),
isSampler(isSampler),
isMatrixType(isMatrixType),
isImageType(isImageType)
isImageType(isImageType),
glslAsFloat(glslAsFloat)
{}
const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType);
......
......@@ -157,12 +157,14 @@ constexpr const char kViewport[] = "viewport";
constexpr const char kHalfRenderAreaHeight[] = "halfRenderAreaHeight";
constexpr const char kViewportYScale[] = "viewportYScale";
constexpr const char kNegViewportYScale[] = "negViewportYScale";
constexpr const char kXfbActiveUnpaused[] = "xfbActiveUnpaused";
constexpr const char kXfbBufferOffsets[] = "xfbBufferOffsets";
constexpr const char kDepthRange[] = "depthRange";
constexpr size_t kNumDriverUniforms = 6;
constexpr size_t kNumDriverUniforms = 7;
constexpr std::array<const char *, kNumDriverUniforms> kDriverUniformNames = {
{kViewport, kHalfRenderAreaHeight, kViewportYScale, kNegViewportYScale, "padding",
kDepthRange}};
{kViewport, kHalfRenderAreaHeight, kViewportYScale, kNegViewportYScale, kXfbActiveUnpaused,
kXfbBufferOffsets, kDepthRange}};
template <TBasicType BasicType = EbtFloat, unsigned char PrimarySize = 1>
TIntermConstantUnion *CreateBasicConstant(float value)
......@@ -359,7 +361,8 @@ const TVariable *AddDriverUniformsToShader(TIntermBlock *root, TSymbolTable *sym
new TType(EbtFloat),
new TType(EbtFloat),
new TType(EbtFloat),
new TType(EbtFloat),
new TType(EbtUInt),
new TType(EbtInt, 4),
emulatedDepthRangeType,
}};
......
......@@ -44,6 +44,7 @@ class BufferState final : angle::NonCopyable
GLint64 getMapOffset() const { return mMapOffset; }
GLint64 getMapLength() const { return mMapLength; }
GLint64 getSize() const { return mSize; }
bool isBoundForTransformFeedback() const { return mTransformFeedbackIndexedBindingCount != 0; }
private:
friend class Buffer;
......
......@@ -41,7 +41,11 @@ enum
// GL_EXT_geometry_shader increases the minimum value of GL_MAX_UNIFORM_BUFFER_BINDINGS to 48.
IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS = 48,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS = 4,
// Transform feedback limits set to the minimum required by the spec.
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = 64,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 4,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS = 4,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS = 4,
// Maximum number of views which are supported by the implementation of ANGLE_multiview.
IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS = 4,
......
......@@ -3301,6 +3301,13 @@ void Context::initCaps()
LimitCap(&mState.mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
LimitCap(&mState.mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
LimitCap(&mState.mCaps.maxTransformFeedbackInterleavedComponents,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS);
LimitCap(&mState.mCaps.maxTransformFeedbackSeparateAttributes,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS);
LimitCap(&mState.mCaps.maxTransformFeedbackSeparateComponents,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS);
// Limit textures as well, so we can use fast bitsets with texture bindings.
LimitCap(&mState.mCaps.maxCombinedTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES);
LimitCap(&mState.mCaps.maxShaderTextureImageUnits[ShaderType::Vertex],
......
......@@ -1423,15 +1423,16 @@ angle::Result Program::link(const Context *context)
}
gatherTransformFeedbackVaryings(mergedVaryings);
mState.updateTransformFeedbackStrides();
}
mLinkingState.reset(new LinkingState());
mLinkingState->context = context;
mLinkingState->context = context;
mLinkingState->linkingFromBinary = false;
mLinkingState->programHash = programHash;
mLinkingState->linkEvent = mProgram->link(context, *resources, mInfoLog);
mLinkingState->resources = std::move(resources);
mLinkResolved = false;
mLinkingState->programHash = programHash;
mLinkingState->linkEvent = mProgram->link(context, *resources, mInfoLog);
mLinkingState->resources = std::move(resources);
mLinkResolved = false;
return angle::Result::Continue;
}
......@@ -1447,8 +1448,8 @@ void Program::resolveLinkImpl(const Context *context)
angle::Result result = mLinkingState->linkEvent->wait(context);
mLinked = result == angle::Result::Continue;
mLinkResolved = true;
mLinked = result == angle::Result::Continue;
mLinkResolved = true;
std::unique_ptr<LinkingState> linkingState = std::move(mLinkingState);
if (!mLinked)
{
......@@ -4016,7 +4017,7 @@ bool Program::linkOutputVariables(const Caps &caps,
// GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
// structures, so we may use getBasicTypeElementCount().
unsigned int elementCount = outputVariable.getBasicTypeElementCount();
unsigned int elementCount = outputVariable.getBasicTypeElementCount();
if (FindUsedOutputLocation(outputLocations, baseLocation, elementCount, reservedLocations,
outputVariableIndex))
{
......@@ -4785,6 +4786,11 @@ angle::Result Program::deserialize(const Context *context,
"Too many shader types");
mState.mLinkedShaderStages = ShaderBitSet(stream.readInt<uint8_t>());
if (!mState.mAttachedShaders[ShaderType::Compute])
{
mState.updateTransformFeedbackStrides();
}
postResolveLink(context);
return angle::Result::Continue;
......@@ -4792,11 +4798,6 @@ angle::Result Program::deserialize(const Context *context,
void Program::postResolveLink(const gl::Context *context)
{
if (!mState.mAttachedShaders[ShaderType::Compute])
{
mState.updateTransformFeedbackStrides();
}
mState.updateActiveSamplers();
mState.updateActiveImages();
......
......@@ -253,6 +253,7 @@ struct TransformFeedbackVarying : public sh::Varying
interpolation = parent.interpolation;
isInvariant = parent.isInvariant;
name = parent.name + "." + name;
mappedName = parent.mappedName + "." + mappedName;
}
std::string nameWithArrayIndex() const
......@@ -347,6 +348,11 @@ class ProgramState final : angle::NonCopyable
{
return mLinkedTransformFeedbackVaryings;
}
const std::vector<GLsizei> &getTransformFeedbackStrides() const
{
return mTransformFeedbackStrides;
}
size_t getTransformFeedbackBufferCount() const { return mTransformFeedbackStrides.size(); }
const std::vector<AtomicCounterBuffer> &getAtomicCounterBuffers() const
{
return mAtomicCounterBuffers;
......@@ -897,7 +903,6 @@ class Program final : angle::NonCopyable, public LabeledObject
// Writes a program's binary to the output memory buffer.
void serialize(const Context *context, angle::MemoryBuffer *binaryOut) const;
private:
struct LinkingState;
......
......@@ -79,12 +79,7 @@ QueryType Query::getType() const
return mQuery->getType();
}
rx::QueryImpl *Query::getImplementation()
{
return mQuery;
}
const rx::QueryImpl *Query::getImplementation() const
rx::QueryImpl *Query::getImplementation() const
{
return mQuery;
}
......
......@@ -47,8 +47,7 @@ class Query final : public RefCountObject, public LabeledObject
QueryType getType() const;
rx::QueryImpl *getImplementation();
const rx::QueryImpl *getImplementation() const;
rx::QueryImpl *getImplementation() const;
private:
rx::QueryImpl *mQuery;
......
......@@ -69,6 +69,21 @@ const std::vector<OffsetBindingPointer<Buffer>> &TransformFeedbackState::getInde
return mIndexedBuffers;
}
GLsizeiptr TransformFeedbackState::getPrimitivesDrawn() const
{
switch (mPrimitiveMode)
{
case gl::PrimitiveMode::Points:
return mVerticesDrawn;
case gl::PrimitiveMode::Lines:
return mVerticesDrawn / 2;
case gl::PrimitiveMode::Triangles:
return mVerticesDrawn / 3;
default:
return 0;
}
}
TransformFeedback::TransformFeedback(rx::GLImplFactory *implFactory, GLuint id, const Caps &caps)
: RefCountObject(id),
mState(caps.maxTransformFeedbackSeparateAttributes),
......@@ -289,12 +304,7 @@ bool TransformFeedback::buffersBoundForOtherUse() const
return false;
}
rx::TransformFeedbackImpl *TransformFeedback::getImplementation()
{
return mImplementation;
}
const rx::TransformFeedbackImpl *TransformFeedback::getImplementation() const
rx::TransformFeedbackImpl *TransformFeedback::getImplementation() const
{
return mImplementation;
}
......
......@@ -38,6 +38,8 @@ class TransformFeedbackState final : angle::NonCopyable
const OffsetBindingPointer<Buffer> &getIndexedBuffer(size_t idx) const;
const std::vector<OffsetBindingPointer<Buffer>> &getIndexedBuffers() const;
const Program *getBoundProgram() const { return mProgram; }
GLsizeiptr getVerticesDrawn() const { return mVerticesDrawn; }
GLsizeiptr getPrimitivesDrawn() const;
private:
friend class TransformFeedback;
......@@ -93,13 +95,15 @@ class TransformFeedback final : public RefCountObject, public LabeledObject
const OffsetBindingPointer<Buffer> &getIndexedBuffer(size_t index) const;
size_t getIndexedBufferCount() const;
GLsizeiptr getVerticesDrawn() const { return mState.getVerticesDrawn(); }
GLsizeiptr getPrimitivesDrawn() const { return mState.getPrimitivesDrawn(); }
// Returns true if any buffer bound to this object is also bound to another target.
bool buffersBoundForOtherUse() const;
angle::Result detachBuffer(const Context *context, GLuint bufferName);
rx::TransformFeedbackImpl *getImplementation();
const rx::TransformFeedbackImpl *getImplementation() const;
rx::TransformFeedbackImpl *getImplementation() const;
void onBindingChanged(const Context *context, bool bound);
......
......@@ -471,6 +471,10 @@ using ImageUnitMask = angle::BitSet<IMPLEMENTATION_MAX_IMAGE_UNITS>;
using SupportedSampleSet = std::set<GLuint>;
template <typename T>
using TransformFeedbackBuffersArray =
std::array<T, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS>;
// OffsetBindingPointer.getSize() returns the size specified by the user, which may be larger than
// the size of the bound buffer. This function reduces the returned size to fit the bound buffer if
// necessary. Returns 0 if no buffer is bound or if integer overflow occurs.
......
......@@ -88,6 +88,17 @@ const char *GetResourceTypeName(CommandGraphResourceType resourceType,
UNREACHABLE();
return "Query";
}
case CommandGraphResourceType::EmulatedQuery:
switch (function)
{
case CommandGraphNodeFunction::BeginTransformFeedbackQuery:
return "BeginTransformFeedbackQuery";
case CommandGraphNodeFunction::EndTransformFeedbackQuery:
return "EndTransformFeedbackQuery";
default:
UNREACHABLE();
return "EmulatedQuery";
}
case CommandGraphResourceType::FenceSync:
switch (function)
{
......@@ -442,7 +453,9 @@ void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIn
{
ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
mFunction == CommandGraphNodeFunction::EndQuery ||
mFunction == CommandGraphNodeFunction::WriteTimestamp);
mFunction == CommandGraphNodeFunction::WriteTimestamp ||
mFunction == CommandGraphNodeFunction::BeginTransformFeedbackQuery ||
mFunction == CommandGraphNodeFunction::EndTransformFeedbackQuery);
mQueryPool = queryPool->getHandle();
mQueryIndex = queryIndex;
}
......@@ -585,6 +598,15 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
break;
case CommandGraphNodeFunction::BeginTransformFeedbackQuery:
// Unless using VK_EXT_transform_feedback (not implemented currently), there's nothing
// to do.
break;
case CommandGraphNodeFunction::EndTransformFeedbackQuery:
// Same as BeginTransformFeedbackQuery.
break;
case CommandGraphNodeFunction::SetFenceSync:
ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
ASSERT(mFenceSyncEvent != VK_NULL_HANDLE);
......@@ -911,6 +933,18 @@ void CommandGraph::writeTimestamp(const QueryPool *queryPool, uint32_t queryInde
newNode->setQueryPool(queryPool, queryIndex);
}
void CommandGraph::beginTransformFeedbackEmulatedQuery()
{
allocateBarrierNode(CommandGraphNodeFunction::BeginTransformFeedbackQuery,
CommandGraphResourceType::EmulatedQuery, 0);
}
void CommandGraph::endTransformFeedbackEmulatedQuery()
{
allocateBarrierNode(CommandGraphNodeFunction::EndTransformFeedbackQuery,
CommandGraphResourceType::EmulatedQuery, 0);
}
void CommandGraph::setFenceSync(const vk::Event &event)
{
CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::SetFenceSync,
......@@ -973,6 +1007,7 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const
int imageIDCounter = 1;
int queryIDCounter = 1;
int fenceIDCounter = 1;
int xfbIDCounter = 1;
out << "digraph {" << std::endl;
......@@ -1049,6 +1084,9 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const
case CommandGraphResourceType::FenceSync:
id = fenceIDCounter++;
break;
case CommandGraphResourceType::EmulatedQuery:
id = xfbIDCounter++;
break;
default:
UNREACHABLE();
break;
......
......@@ -32,6 +32,9 @@ enum class CommandGraphResourceType
Framebuffer,
Image,
Query,
// Transform feedback queries could be handled entirely on the CPU (if not using
// VK_EXT_transform_feedback), but still need to generate a command graph barrier node.
EmulatedQuery,
FenceSync,
DebugMarker,
HostAvailabilityOperation,
......@@ -45,6 +48,8 @@ enum class CommandGraphNodeFunction
BeginQuery,
EndQuery,
WriteTimestamp,
BeginTransformFeedbackQuery,
EndTransformFeedbackQuery,
SetFenceSync,
WaitFenceSync,
InsertDebugMarker,
......@@ -446,6 +451,8 @@ class CommandGraph final : angle::NonCopyable
void beginQuery(const QueryPool *queryPool, uint32_t queryIndex);
void endQuery(const QueryPool *queryPool, uint32_t queryIndex);
void writeTimestamp(const QueryPool *queryPool, uint32_t queryIndex);
void beginTransformFeedbackEmulatedQuery();
void endTransformFeedbackEmulatedQuery();
// GLsync and EGLSync:
void setFenceSync(const vk::Event &event);
void waitFenceSync(const vk::Event &event);
......
......@@ -174,6 +174,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mProgram(nullptr),
mLastIndexBufferOffset(0),
mCurrentDrawElementsType(gl::DrawElementsType::InvalidEnum),
mXfbBaseVertex(0),
mClearColorMask(kAllColorChannelsMask),
mFlipYForCurrentSurface(false),
mIsAnyHostVisibleBufferWritten(false),
......@@ -201,6 +202,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mNewCommandBufferDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_UNIFORM_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
mDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] = &ContextVk::handleDirtyDefaultAttribs;
......@@ -210,6 +212,8 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyIndexBuffer;
mDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] = &ContextVk::handleDirtyDriverUniforms;
mDirtyBitHandlers[DIRTY_BIT_UNIFORM_BUFFERS] = &ContextVk::handleDirtyUniformBuffers;
mDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
&ContextVk::handleDirtyTransformFeedbackBuffers;
mDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = &ContextVk::handleDirtyDescriptorSets;
mDirtyBits = mNewCommandBufferDirtyBits;
......@@ -451,6 +455,13 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
mDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
// Update transform feedback offsets on every draw call.
if (mState.isTransformFeedbackActiveUnpaused())
{
mXfbBaseVertex = firstVertex;
invalidateDriverUniforms();
}
DirtyBits dirtyBits = mDirtyBits & dirtyBitMask;
if (dirtyBits.none())
......@@ -645,6 +656,17 @@ angle::Result ContextVk::handleDirtyUniformBuffers(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyTransformFeedbackBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
if (mProgram->hasTransformFeedbackOutput() && mState.isTransformFeedbackActive())
{
ANGLE_TRY(mProgram->updateTransformFeedbackDescriptorSet(
this, mDrawFramebuffer->getFramebuffer()));
}
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyDescriptorSets(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
......@@ -1595,6 +1617,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
glState.getDrawFramebuffer());
mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition,
mDrawFramebuffer->getRenderPassDesc());
invalidateCurrentTransformFeedbackBuffers();
break;
}
case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
......@@ -1632,6 +1655,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
invalidateCurrentTextures();
break;
case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
// Nothing to do.
break;
case gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING:
break;
......@@ -1879,6 +1903,17 @@ void ContextVk::onFramebufferChange(const vk::RenderPassDesc &renderPassDesc)
mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition, renderPassDesc);
}
void ContextVk::invalidateCurrentTransformFeedbackBuffers()
{
mDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
mDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
void ContextVk::onTransformFeedbackPauseResume()
{
invalidateDriverUniforms();
}
angle::Result ContextVk::dispatchCompute(const gl::Context *context,
GLuint numGroupsX,
GLuint numGroupsY,
......@@ -1951,6 +1986,8 @@ angle::Result ContextVk::handleDirtyDriverUniforms(const gl::Context *context,
mDriverUniformsDynamicOffset = static_cast<uint32_t>(offset);
uint32_t xfbActiveUnpaused = mState.isTransformFeedbackActiveUnpaused();
float depthRangeNear = mState.getNearPlane();
float depthRangeFar = mState.getFarPlane();
float depthRangeDiff = depthRangeFar - depthRangeNear;
......@@ -1963,9 +2000,19 @@ angle::Result ContextVk::handleDirtyDriverUniforms(const gl::Context *context,
halfRenderAreaHeight,
scaleY,
-scaleY,
0.0f,
xfbActiveUnpaused,
{},
{depthRangeNear, depthRangeFar, depthRangeDiff, 0.0f}};
if (xfbActiveUnpaused)
{
TransformFeedbackVk *transformFeedbackVk =
vk::GetImpl(mState.getCurrentTransformFeedback());
transformFeedbackVk->getBufferOffsets(this, mState.getProgram()->getState(), mXfbBaseVertex,
driverUniforms->xfbBufferOffsets.data(),
driverUniforms->xfbBufferOffsets.size());
}
ANGLE_TRY(mDriverUniformsBuffer.flush(this));
if (newBuffer)
......
......@@ -215,6 +215,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
void onFramebufferChange(const vk::RenderPassDesc &renderPassDesc);
void onHostVisibleBufferWrite() { mIsAnyHostVisibleBufferWritten = true; }
void invalidateCurrentTransformFeedbackBuffers();
void onTransformFeedbackPauseResume();
vk::DynamicQueryPool *getQueryPool(gl::QueryType queryType);
const VkClearValue &getClearColorValue() const;
......@@ -324,6 +327,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
DIRTY_BIT_INDEX_BUFFER,
DIRTY_BIT_DRIVER_UNIFORMS,
DIRTY_BIT_UNIFORM_BUFFERS,
DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS,
DIRTY_BIT_DESCRIPTOR_SETS,
DIRTY_BIT_MAX,
};
......@@ -391,6 +395,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyUniformBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyTransformFeedbackBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyDescriptorSets(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
......@@ -442,6 +448,12 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
const GLvoid *mLastIndexBufferOffset;
gl::DrawElementsType mCurrentDrawElementsType;
// Cache the current draw call's firstVertex to be passed to
// TransformFeedbackVk::getBufferOffsets. Unfortunately, gl_BaseVertex support in Vulkan is
// not yet ubiquitous, which would have otherwise removed the need for this value to be passed
// as a uniform.
GLint mXfbBaseVertex;
// Cached clear value/mask for color and depth/stencil.
VkClearValue mClearColorValue;
VkClearValue mClearDepthStencilValue;
......@@ -467,7 +479,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
float halfRenderAreaHeight;
float viewportYScale;
float negViewportYScale;
float padding;
uint32_t xfbActiveUnpaused;
std::array<int32_t, 4> xfbBufferOffsets;
// We'll use x, y, z for near / far / diff respectively.
std::array<float, 4> depthRange;
......
......@@ -236,12 +236,12 @@ IntermediateShaderSource::IntermediateShaderSource(const std::string &source)
else if (source.compare(cur, ConstStrLen(kXfbDeclMarkerBegin), kXfbDeclMarkerBegin) == 0)
{
cur += ConstStrLen(kXfbDeclMarkerBegin);
addTransformFeedbackOutputBlock();
addTransformFeedbackDeclarationBlock();
}
else if (source.compare(cur, ConstStrLen(kXfbOutMarkerBegin), kXfbOutMarkerBegin) == 0)
{
cur += ConstStrLen(kXfbOutMarkerBegin);
addTransformFeedbackDeclarationBlock();
addTransformFeedbackOutputBlock();
}
else
{
......@@ -366,6 +366,103 @@ uint32_t CountExplicitOutputs(OutputIter outputsBegin,
return std::accumulate(outputsBegin, outputsEnd, 0, reduce);
}
std::string GenerateTransformFeedbackVaryingOutput(const gl::TransformFeedbackVarying &varying,
const gl::UniformTypeInfo &info,
size_t strideBytes,
size_t offset,
const std::string &bufferIndex)
{
std::ostringstream result;
ASSERT(strideBytes % 4 == 0);
size_t stride = strideBytes / 4;
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)
{
for (int row = 0; row < info.rowCount; ++row)
{
result << "xfbOut" << bufferIndex << "[ANGLEUniforms.xfbBufferOffsets["
<< bufferIndex << "] + gl_VertexIndex * " << stride << " + " << offset
<< "] = " << info.glslAsFloat << "(" << varying.mappedName;
if (varying.isArray())
{
result << "[" << arrayIndex << "]";
}
if (info.columnCount > 1)
{
result << "[" << col << "]";
}
if (info.rowCount > 1)
{
result << "[" << row << "]";
}
result << ");\n";
++offset;
}
}
}
return result.str();
}
void GenerateTransformFeedbackOutputs(const gl::ProgramState &programState,
IntermediateShaderSource *vertexShader)
{
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();
const std::string xfbSet = Str(kUniformsAndXfbDescriptorSetIndex);
std::vector<std::string> xfbIndices(bufferCount);
std::string xfbDecl;
for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
{
const std::string xfbBinding = Str(kXfbBindingIndexStart + bufferIndex);
xfbIndices[bufferIndex] = Str(bufferIndex);
xfbDecl += "layout(set = " + xfbSet + ", binding = " + xfbBinding + ") buffer xfbBuffer" +
xfbIndices[bufferIndex] + " { float xfbOut" + xfbIndices[bufferIndex] +
"[]; };\n";
}
std::string xfbOut = "if (ANGLEUniforms.xfbActiveUnpaused != 0)\n{\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);
xfbOut += GenerateTransformFeedbackVaryingOutput(varying, info, bufferStrides[bufferIndex],
outputOffset, xfbIndices[bufferIndex]);
if (isInterleaved)
{
outputOffset += info.columnCount * info.rowCount * varying.size();
}
}
xfbOut += "}\n";
vertexShader->insertTransformFeedbackDeclaration(std::move(xfbDecl));
vertexShader->insertTransformFeedbackOutput(std::move(xfbOut));
}
} // anonymous namespace
// static
......@@ -525,7 +622,7 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
// See corresponding code in OutputVulkanGLSL.cpp.
const std::string driverUniformsDescriptorSet =
"set = " + Str(kDriverUniformsDescriptorSetIndex);
const std::string uniformsDescriptorSet = "set = " + Str(kUniformsDescriptorSetIndex);
const std::string uniformsDescriptorSet = "set = " + Str(kUniformsAndXfbDescriptorSetIndex);
const std::string uniformBlocksDescriptorSet = "set = " + Str(kUniformBlockDescriptorSetIndex);
const std::string texturesDescriptorSet = "set = " + Str(kTextureDescriptorSetIndex);
......@@ -643,10 +740,15 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
fragmentSource.insertLayoutSpecifier(kVaryingName, layout);
// Write transform feedback output code.
// TODO(syoussefi): support transform feedback. http://anglebug.com/3205
ASSERT(programState.getLinkedTransformFeedbackVaryings().size() == 0);
vertexSource.insertTransformFeedbackDeclaration("");
vertexSource.insertTransformFeedbackOutput("");
if (programState.getLinkedTransformFeedbackVaryings().empty())
{
vertexSource.insertTransformFeedbackDeclaration("");
vertexSource.insertTransformFeedbackOutput("");
}
else
{
GenerateTransformFeedbackOutputs(programState, &vertexSource);
}
vertexSource.insertQualifierSpecifier(kVaryingName, "out");
fragmentSource.insertQualifierSpecifier(kVaryingName, "in");
......
......@@ -217,7 +217,7 @@ ProgramVk::DefaultUniformBlock::DefaultUniformBlock() {}
ProgramVk::DefaultUniformBlock::~DefaultUniformBlock() = default;
ProgramVk::ProgramVk(const gl::ProgramState &state) : ProgramImpl(state), mUniformBlocksOffsets{} {}
ProgramVk::ProgramVk(const gl::ProgramState &state) : ProgramImpl(state), mDynamicBufferOffsets{} {}
ProgramVk::~ProgramVk() = default;
......@@ -297,8 +297,10 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext,
const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog)
{
ContextVk *contextVk = vk::GetImpl(glContext);
RendererVk *renderer = contextVk->getRenderer();
const gl::State &glState = glContext->getState();
ContextVk *contextVk = vk::GetImpl(glContext);
RendererVk *renderer = contextVk->getRenderer();
gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback();
reset(contextVk);
......@@ -312,14 +314,21 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext,
// Store a reference to the pipeline and descriptor set layouts. This will create them if they
// don't already exist in the cache.
vk::DescriptorSetLayoutDesc uniformsSetDesc;
uniformsSetDesc.update(kVertexUniformsBindingIndex, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
1, VK_SHADER_STAGE_VERTEX_BIT);
uniformsSetDesc.update(kFragmentUniformsBindingIndex, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
1, VK_SHADER_STAGE_FRAGMENT_BIT);
vk::DescriptorSetLayoutDesc uniformsAndXfbSetDesc;
uniformsAndXfbSetDesc.update(kVertexUniformsBindingIndex,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
VK_SHADER_STAGE_VERTEX_BIT);
uniformsAndXfbSetDesc.update(kFragmentUniformsBindingIndex,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
VK_SHADER_STAGE_FRAGMENT_BIT);
if (transformFeedback && !mState.getLinkedTransformFeedbackVaryings().empty())
{
vk::GetImpl(transformFeedback)->updateDescriptorSetLayout(mState, &uniformsAndXfbSetDesc);
}
ANGLE_TRY(renderer->getDescriptorSetLayout(
contextVk, uniformsSetDesc, &mDescriptorSetLayouts[kUniformsDescriptorSetIndex]));
contextVk, uniformsAndXfbSetDesc,
&mDescriptorSetLayouts[kUniformsAndXfbDescriptorSetIndex]));
vk::DescriptorSetLayoutDesc uniformBlocksSetDesc;
......@@ -360,7 +369,8 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext,
&mDescriptorSetLayouts[kDriverUniformsDescriptorSetIndex]));
vk::PipelineLayoutDesc pipelineLayoutDesc;
pipelineLayoutDesc.updateDescriptorSetLayout(kUniformsDescriptorSetIndex, uniformsSetDesc);
pipelineLayoutDesc.updateDescriptorSetLayout(kUniformsAndXfbDescriptorSetIndex,
uniformsAndXfbSetDesc);
pipelineLayoutDesc.updateDescriptorSetLayout(kUniformBlockDescriptorSetIndex,
uniformBlocksSetDesc);
pipelineLayoutDesc.updateDescriptorSetLayout(kTextureDescriptorSetIndex, texturesSetDesc);
......@@ -372,14 +382,15 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext,
// Note that this may reserve more sets than strictly necessary for a particular layout.
// TODO(jmadill): Optimize descriptor counts. http://anglebug.com/3117
VkDescriptorPoolSize uniformSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
GetUniformBufferDescriptorCount()};
std::array<VkDescriptorPoolSize, 2> uniformAndXfbSetSize = {
{{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, GetUniformBufferDescriptorCount()},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS}}};
VkDescriptorPoolSize uniformBlockSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
renderer->getMaxUniformBlocks()};
VkDescriptorPoolSize textureSetSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
renderer->getMaxActiveTextures()};
ANGLE_TRY(
mDynamicDescriptorPools[kUniformsDescriptorSetIndex].init(contextVk, &uniformSetSize, 1));
ANGLE_TRY(mDynamicDescriptorPools[kUniformsAndXfbDescriptorSetIndex].init(
contextVk, uniformAndXfbSetSize.data(), uniformAndXfbSetSize.size()));
ANGLE_TRY(mDynamicDescriptorPools[kUniformBlockDescriptorSetIndex].init(
contextVk, &uniformBlockSetSize, 1));
ANGLE_TRY(
......@@ -476,7 +487,7 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
}
}
if (mDefaultUniformBlocksDirty.any())
if (mDefaultUniformBlocksDirty.any() || mState.getTransformFeedbackBufferCount() > 0)
{
// Initialize the "empty" uniform block if necessary.
if (!mDefaultUniformBlocksDirty.all())
......@@ -824,18 +835,19 @@ angle::Result ProgramVk::updateUniforms(ContextVk *contextVk)
{
ASSERT(dirtyUniforms());
// Update buffer memory by immediate mapping. This immediate update only works once.
bool anyNewBufferAllocated = false;
// Update buffer memory by immediate mapping. This immediate update only works once.
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
{
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
if (mDefaultUniformBlocksDirty[shaderType])
{
bool bufferModified = false;
ANGLE_TRY(SyncDefaultUniformBlock(contextVk, &uniformBlock.storage,
uniformBlock.uniformData,
&mUniformBlocksOffsets[shaderType], &bufferModified));
bool bufferModified = false;
uint32_t offsetIndex = static_cast<uint32_t>(shaderType) - kShaderTypeMin;
ANGLE_TRY(
SyncDefaultUniformBlock(contextVk, &uniformBlock.storage, uniformBlock.uniformData,
&mDynamicBufferOffsets[offsetIndex], &bufferModified));
mDefaultUniformBlocksDirty.reset(shaderType);
if (bufferModified)
......@@ -849,14 +861,15 @@ angle::Result ProgramVk::updateUniforms(ContextVk *contextVk)
{
// We need to reinitialize the descriptor sets if we newly allocated buffers since we can't
// modify the descriptor sets once initialized.
ANGLE_TRY(allocateDescriptorSet(contextVk, kUniformsDescriptorSetIndex));
ANGLE_TRY(updateDefaultUniformsDescriptorSet(contextVk));
ANGLE_TRY(allocateDescriptorSet(contextVk, kUniformsAndXfbDescriptorSetIndex));
updateDefaultUniformsDescriptorSet(contextVk);
updateTransformFeedbackDescriptorSetImpl(contextVk);
}
return angle::Result::Continue;
}
angle::Result ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk)
void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk)
{
gl::ShaderMap<VkDescriptorBufferInfo> descriptorBufferInfo;
gl::ShaderMap<VkWriteDescriptorSet> writeDescriptorInfo;
......@@ -883,7 +896,7 @@ angle::Result ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk
writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeInfo.pNext = nullptr;
writeInfo.dstSet = mDescriptorSets[kUniformsDescriptorSetIndex];
writeInfo.dstSet = mDescriptorSets[kUniformsAndXfbDescriptorSetIndex];
writeInfo.dstBinding = static_cast<uint32_t>(shaderType);
writeInfo.dstArrayElement = 0;
writeInfo.descriptorCount = 1;
......@@ -895,18 +908,12 @@ angle::Result ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk
VkDevice device = contextVk->getDevice();
constexpr uint32_t kShaderTypeMin = static_cast<uint32_t>(gl::kGLES2ShaderTypeMin);
constexpr uint32_t kShaderTypeMax = static_cast<uint32_t>(gl::kGLES2ShaderTypeMax);
constexpr uint32_t kGLES2ShaderCount = kShaderTypeMax - kShaderTypeMin + 1;
vkUpdateDescriptorSets(device, kGLES2ShaderCount, writeDescriptorInfo.data(), 0, nullptr);
return angle::Result::Continue;
vkUpdateDescriptorSets(device, kShaderTypeCount, writeDescriptorInfo.data(), 0, nullptr);
}
angle::Result ProgramVk::updateUniformBuffersDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer)
{
ASSERT(hasUniformBuffers());
ANGLE_TRY(allocateDescriptorSet(contextVk, kUniformBlockDescriptorSetIndex));
VkDescriptorSet descriptorSet = mDescriptorSets[kUniformBlockDescriptorSetIndex];
......@@ -987,6 +994,39 @@ angle::Result ProgramVk::updateUniformBuffersDescriptorSet(ContextVk *contextVk,
return angle::Result::Continue;
}
angle::Result ProgramVk::updateTransformFeedbackDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer)
{
const gl::State &glState = contextVk->getState();
ASSERT(hasTransformFeedbackOutput());
TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(glState.getCurrentTransformFeedback());
transformFeedbackVk->addFramebufferDependency(contextVk, mState, framebuffer);
ANGLE_TRY(allocateDescriptorSet(contextVk, kUniformsAndXfbDescriptorSetIndex));
updateDefaultUniformsDescriptorSet(contextVk);
updateTransformFeedbackDescriptorSetImpl(contextVk);
return angle::Result::Continue;
}
void ProgramVk::updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk)
{
const gl::State &glState = contextVk->getState();
if (!hasTransformFeedbackOutput())
{
// NOTE(syoussefi): a possible optimization is to skip this if transform feedback is
// paused. However, even if paused, |updateDescriptorSet| must be called at least once for
// the sake of validation.
return;
}
TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(glState.getCurrentTransformFeedback());
transformFeedbackVk->updateDescriptorSet(
contextVk, mState, mDescriptorSets[kUniformsAndXfbDescriptorSetIndex], kShaderTypeCount);
}
angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer)
{
......@@ -1121,19 +1161,15 @@ angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk,
descSet = mEmptyDescriptorSets[descriptorSetIndex];
}
constexpr uint32_t kShaderTypeMin = static_cast<uint32_t>(gl::kGLES2ShaderTypeMin);
constexpr uint32_t kShaderTypeMax = static_cast<uint32_t>(gl::kGLES2ShaderTypeMax);
constexpr uint32_t kShaderTypeCount = kShaderTypeMax - kShaderTypeMin + 1;
// Default uniforms are encompassed in a block per shader stage, and they are assigned
// through dynamic uniform buffers (requiring dynamic offsets). No other descriptor
// requires a dynamic offset.
const uint32_t uniformBlockOffsetCount =
descriptorSetIndex == kUniformsDescriptorSetIndex ? kShaderTypeCount : 0;
descriptorSetIndex == kUniformsAndXfbDescriptorSetIndex ? kShaderTypeCount : 0;
commandBuffer->bindGraphicsDescriptorSets(mPipelineLayout.get(), descriptorSetIndex, 1,
&descSet, uniformBlockOffsetCount,
mUniformBlocksOffsets.data() + kShaderTypeMin);
mDynamicBufferOffsets.data() + kShaderTypeMin);
}
return angle::Result::Continue;
......
......@@ -16,6 +16,7 @@
#include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace rx
......@@ -109,6 +110,8 @@ class ProgramVk : public ProgramImpl
vk::FramebufferHelper *framebuffer);
angle::Result updateUniformBuffersDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer);
angle::Result updateTransformFeedbackDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer);
angle::Result updateDescriptorSets(ContextVk *contextVk, vk::CommandBuffer *commandBuffer);
......@@ -119,6 +122,10 @@ class ProgramVk : public ProgramImpl
bool hasTextures() const { return !mState.getSamplerBindings().empty(); }
bool hasUniformBuffers() const { return !mState.getUniformBlocks().empty(); }
bool hasTransformFeedbackOutput() const
{
return !mState.getLinkedTransformFeedbackVaryings().empty();
}
bool dirtyUniforms() const { return mDefaultUniformBlocksDirty.any(); }
......@@ -159,7 +166,8 @@ class ProgramVk : public ProgramImpl
bool *newPoolAllocatedOut);
angle::Result initDefaultUniformBlocks(const gl::Context *glContext);
angle::Result updateDefaultUniformsDescriptorSet(ContextVk *contextVk);
void updateDefaultUniformsDescriptorSet(ContextVk *contextVk);
void updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk);
template <class T>
void getUniformImpl(GLint location, T *v, GLenum entryPointType) const;
......@@ -219,7 +227,11 @@ class ProgramVk : public ProgramImpl
gl::ShaderMap<DefaultUniformBlock> mDefaultUniformBlocks;
gl::ShaderBitSet mDefaultUniformBlocksDirty;
gl::ShaderMap<uint32_t> mUniformBlocksOffsets;
static constexpr uint32_t kShaderTypeMin = static_cast<uint32_t>(gl::kGLES2ShaderTypeMin);
static constexpr uint32_t kShaderTypeMax = static_cast<uint32_t>(gl::kGLES2ShaderTypeMax);
static constexpr uint32_t kShaderTypeCount = kShaderTypeMax - kShaderTypeMin + 1;
std::array<uint32_t, kShaderTypeCount> mDynamicBufferOffsets;
// This is a special "empty" placeholder buffer for when a shader has no uniforms.
// It is necessary because we want to keep a compatible pipeline layout in all cases,
......
......@@ -9,25 +9,34 @@
#include "libANGLE/renderer/vulkan/QueryVk.h"
#include "libANGLE/Context.h"
#include "libANGLE/TransformFeedback.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
#include "common/debug.h"
namespace rx
{
QueryVk::QueryVk(gl::QueryType type) : QueryImpl(type), mCachedResult(0), mCachedResultValid(false)
QueryVk::QueryVk(gl::QueryType type)
: QueryImpl(type),
mTransformFeedbackPrimitivesDrawn(0),
mCachedResult(0),
mCachedResultValid(false)
{}
QueryVk::~QueryVk() = default;
void QueryVk::onDestroy(const gl::Context *context)
{
ContextVk *contextVk = vk::GetImpl(context);
vk::DynamicQueryPool *queryPool = contextVk->getQueryPool(getType());
queryPool->freeQuery(contextVk, &mQueryHelper);
queryPool->freeQuery(contextVk, &mQueryHelperTimeElapsedBegin);
ContextVk *contextVk = vk::GetImpl(context);
if (getType() != gl::QueryType::TransformFeedbackPrimitivesWritten)
{
vk::DynamicQueryPool *queryPool = contextVk->getQueryPool(getType());
queryPool->freeQuery(contextVk, &mQueryHelper);
queryPool->freeQuery(contextVk, &mQueryHelperTimeElapsedBegin);
}
}
angle::Result QueryVk::begin(const gl::Context *context)
......@@ -36,6 +45,14 @@ angle::Result QueryVk::begin(const gl::Context *context)
mCachedResultValid = false;
// Transform feedback query is a handled by a CPU-calculated value when emulated.
if (getType() == gl::QueryType::TransformFeedbackPrimitivesWritten)
{
mTransformFeedbackPrimitivesDrawn = 0;
contextVk->getCommandGraph()->beginTransformFeedbackEmulatedQuery();
return angle::Result::Continue;
}
if (!mQueryHelper.getQueryPool())
{
ANGLE_TRY(contextVk->getQueryPool(getType())->allocateQuery(contextVk, &mQueryHelper));
......@@ -64,7 +81,22 @@ angle::Result QueryVk::end(const gl::Context *context)
{
ContextVk *contextVk = vk::GetImpl(context);
if (getType() == gl::QueryType::TimeElapsed)
if (getType() == gl::QueryType::TransformFeedbackPrimitivesWritten)
{
mCachedResult = mTransformFeedbackPrimitivesDrawn;
// There could be transform feedback in progress, so add the primitives drawn so far from
// the current transform feedback object.
gl::TransformFeedback *transformFeedback =
context->getState().getCurrentTransformFeedback();
if (transformFeedback)
{
mCachedResult += transformFeedback->getPrimitivesDrawn();
}
mCachedResultValid = true;
contextVk->getCommandGraph()->endTransformFeedbackEmulatedQuery();
}
else if (getType() == gl::QueryType::TimeElapsed)
{
mQueryHelper.writeTimestamp(contextVk);
}
......@@ -217,4 +249,12 @@ angle::Result QueryVk::isResultAvailable(const gl::Context *context, bool *avail
return angle::Result::Continue;
}
void QueryVk::onTransformFeedbackEnd(const gl::Context *context)
{
gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
ASSERT(transformFeedback);
mTransformFeedbackPrimitivesDrawn += transformFeedback->getPrimitivesDrawn();
}
} // namespace rx
......@@ -15,6 +15,7 @@
namespace rx
{
class TransformFeedbackVk;
class QueryVk : public QueryImpl
{
......@@ -33,13 +34,18 @@ class QueryVk : public QueryImpl
angle::Result getResult(const gl::Context *context, GLuint64 *params) override;
angle::Result isResultAvailable(const gl::Context *context, bool *available) override;
void onTransformFeedbackEnd(const gl::Context *context);
private:
angle::Result getResult(const gl::Context *context, bool wait);
// Used for AnySamples, AnySamplesConservative, Timestamp and TimeElapsed (end)
// Used for AnySamples, AnySamplesConservative, Timestamp and TimeElapsed (end).
vk::QueryHelper mQueryHelper;
// An additional query used for TimeElapsed (begin), as it is implemented using Timestamp
// An additional query used for TimeElapsed (begin), as it is implemented using Timestamp.
vk::QueryHelper mQueryHelperTimeElapsedBegin;
// Used with TransformFeedbackPrimitivesWritten when transform feedback is emulated.
size_t mTransformFeedbackPrimitivesDrawn;
uint64_t mCachedResult;
bool mCachedResultValid;
};
......
......@@ -951,6 +951,8 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledFeatures.features.independentBlend = mPhysicalDeviceFeatures.independentBlend;
enabledFeatures.features.robustBufferAccess = mPhysicalDeviceFeatures.robustBufferAccess;
enabledFeatures.features.samplerAnisotropy = mPhysicalDeviceFeatures.samplerAnisotropy;
enabledFeatures.features.vertexPipelineStoresAndAtomics =
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics;
if (!vk::CommandBuffer::ExecutesInline())
{
enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries;
......@@ -1128,6 +1130,14 @@ gl::Version RendererVk::getMaxSupportedESVersion() const
maxVersion = std::max(maxVersion, gl::Version(2, 0));
}
// If vertexPipelineStoresAndAtomics is not supported, we can't currently support transform
// feedback. TODO(syoussefi): this should be conditioned to the extension not being present as
// well, when that code path is implemented. http://anglebug.com/3206
if (!mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics)
{
maxVersion = std::max(maxVersion, gl::Version(2, 0));
}
return maxVersion;
}
......@@ -1202,6 +1212,13 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames)
mFeatures.supportsShaderStencilExport.enabled = true;
}
// TODO(syoussefi): when the code path using the extension is implemented, this should be
// conditioned to the extension not being present as well. http://anglebug.com/3206
if (mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics)
{
mFeatures.emulateTransformFeedback.enabled = true;
}
if (IsLinux() && IsIntel(mPhysicalDeviceProperties.vendorID))
{
mFeatures.disableFifoPresentMode.enabled = true;
......
......@@ -9,6 +9,14 @@
#include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
#include "libANGLE/Context.h"
#include "libANGLE/Query.h"
#include "libANGLE/renderer/vulkan/BufferVk.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/ProgramVk.h"
#include "libANGLE/renderer/vulkan/QueryVk.h"
#include "common/debug.h"
namespace rx
......@@ -23,26 +31,44 @@ TransformFeedbackVk::~TransformFeedbackVk() {}
angle::Result TransformFeedbackVk::begin(const gl::Context *context,
gl::PrimitiveMode primitiveMode)
{
UNIMPLEMENTED();
return angle::Result::Stop;
ContextVk *contextVk = vk::GetImpl(context);
// Make sure the transform feedback buffers are bound to the program descriptor sets.
contextVk->invalidateCurrentTransformFeedbackBuffers();
vk::GetImpl(context)->onTransformFeedbackPauseResume();
onBeginEnd(context);
return angle::Result::Continue;
}
angle::Result TransformFeedbackVk::end(const gl::Context *context)
{
UNIMPLEMENTED();
return angle::Result::Stop;
// If there's an active transform feedback query, accumulate the primitives drawn.
const gl::State &glState = context->getState();
gl::Query *transformFeedbackQuery =
glState.getActiveQuery(gl::QueryType::TransformFeedbackPrimitivesWritten);
if (transformFeedbackQuery)
{
vk::GetImpl(transformFeedbackQuery)->onTransformFeedbackEnd(context);
}
vk::GetImpl(context)->onTransformFeedbackPauseResume();
onBeginEnd(context);
return angle::Result::Continue;
}
angle::Result TransformFeedbackVk::pause(const gl::Context *context)
{
UNIMPLEMENTED();
return angle::Result::Stop;
vk::GetImpl(context)->onTransformFeedbackPauseResume();
return angle::Result::Continue;
}
angle::Result TransformFeedbackVk::resume(const gl::Context *context)
{
UNIMPLEMENTED();
return angle::Result::Stop;
vk::GetImpl(context)->onTransformFeedbackPauseResume();
return angle::Result::Continue;
}
angle::Result TransformFeedbackVk::bindIndexedBuffer(
......@@ -50,8 +76,167 @@ angle::Result TransformFeedbackVk::bindIndexedBuffer(
size_t index,
const gl::OffsetBindingPointer<gl::Buffer> &binding)
{
UNIMPLEMENTED();
return angle::Result::Stop;
RendererVk *rendererVk = vk::GetImpl(context)->getRenderer();
const VkDeviceSize offsetAlignment =
rendererVk->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
// Make sure there's no possible under/overflow with binding size.
static_assert(sizeof(VkDeviceSize) >= sizeof(binding.getSize()), "VkDeviceSize too small");
mBoundBufferRanges[index].offset = binding.getOffset();
mBoundBufferRanges[index].size = gl::GetBoundBufferAvailableSize(binding);
// Set the offset as close as possible to the requested offset while remaining aligned.
mBoundBufferRanges[index].alignedOffset =
(mBoundBufferRanges[index].offset / offsetAlignment) * offsetAlignment;
return angle::Result::Continue;
}
void TransformFeedbackVk::updateDescriptorSetLayout(
const gl::ProgramState &programState,
vk::DescriptorSetLayoutDesc *descSetLayoutOut) const
{
size_t xfbBufferCount = programState.getTransformFeedbackBufferCount();
for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
{
descSetLayoutOut->update(kXfbBindingIndexStart + bufferIndex,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT);
}
}
void TransformFeedbackVk::addFramebufferDependency(ContextVk *contextVk,
const gl::ProgramState &programState,
vk::FramebufferHelper *framebuffer) const
{
const std::vector<gl::OffsetBindingPointer<gl::Buffer>> &xfbBuffers =
mState.getIndexedBuffers();
size_t xfbBufferCount = programState.getTransformFeedbackBufferCount();
ASSERT(xfbBufferCount > 0);
ASSERT(programState.getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS ||
xfbBufferCount == 1);
// Set framebuffer dependent to the transform feedback buffers. This is especially done
// separately from |updateDescriptorSet|, to avoid introducing unnecessary buffer barriers
// every time the descriptor set is updated (which, as the set is shared with default uniforms,
// could get updated frequently).
for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
{
const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = xfbBuffers[bufferIndex];
gl::Buffer *buffer = bufferBinding.get();
ASSERT(buffer != nullptr);
vk::BufferHelper &bufferHelper = vk::GetImpl(buffer)->getBuffer();
bufferHelper.addWriteDependency(framebuffer);
bufferHelper.onWrite(contextVk, VK_ACCESS_SHADER_WRITE_BIT);
}
}
void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk,
const gl::ProgramState &programState,
VkDescriptorSet descSet,
uint32_t bindingOffset) const
{
const std::vector<gl::OffsetBindingPointer<gl::Buffer>> &xfbBuffers =
mState.getIndexedBuffers();
size_t xfbBufferCount = programState.getTransformFeedbackBufferCount();
ASSERT(xfbBufferCount > 0);
ASSERT(programState.getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS ||
xfbBufferCount == 1);
std::array<VkDescriptorBufferInfo, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS>
descriptorBufferInfo;
// Write default uniforms for each shader type.
for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
{
VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[bufferIndex];
const BoundBufferRange &bufferRange = mBoundBufferRanges[bufferIndex];
const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = xfbBuffers[bufferIndex];
gl::Buffer *buffer = bufferBinding.get();
ASSERT(buffer != nullptr);
vk::BufferHelper &bufferHelper = vk::GetImpl(buffer)->getBuffer();
bufferInfo.buffer = bufferHelper.getBuffer().getHandle();
bufferInfo.offset = bufferRange.alignedOffset;
bufferInfo.range = bufferRange.size + (bufferRange.offset - bufferRange.alignedOffset);
}
VkDevice device = contextVk->getDevice();
VkWriteDescriptorSet writeDescriptorInfo = {};
writeDescriptorInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorInfo.dstSet = descSet;
writeDescriptorInfo.dstBinding = bindingOffset;
writeDescriptorInfo.dstArrayElement = 0;
writeDescriptorInfo.descriptorCount = xfbBufferCount;
writeDescriptorInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
writeDescriptorInfo.pImageInfo = nullptr;
writeDescriptorInfo.pBufferInfo = descriptorBufferInfo.data();
writeDescriptorInfo.pTexelBufferView = nullptr;
vkUpdateDescriptorSets(device, 1, &writeDescriptorInfo, 0, nullptr);
}
void TransformFeedbackVk::getBufferOffsets(ContextVk *contextVk,
const gl::ProgramState &programState,
GLint drawCallFirstVertex,
int32_t *offsetsOut,
size_t offsetsSize) const
{
GLsizeiptr verticesDrawn = mState.getVerticesDrawn();
const std::vector<GLsizei> &bufferStrides =
mState.getBoundProgram()->getTransformFeedbackStrides();
size_t xfbBufferCount = programState.getTransformFeedbackBufferCount();
ASSERT(xfbBufferCount > 0);
// The caller should make sure the offsets array has enough space. The maximum possible number
// of outputs is gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS.
ASSERT(offsetsSize >= xfbBufferCount);
for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
{
const BoundBufferRange &bufferRange = mBoundBufferRanges[bufferIndex];
int64_t offsetFromDescriptor =
static_cast<int64_t>(bufferRange.offset - bufferRange.alignedOffset);
int64_t drawCallVertexOffset = static_cast<int64_t>(verticesDrawn) - drawCallFirstVertex;
int64_t writeOffset =
(offsetFromDescriptor + drawCallVertexOffset * bufferStrides[bufferIndex]) /
static_cast<int64_t>(sizeof(uint32_t));
offsetsOut[bufferIndex] = static_cast<int32_t>(writeOffset);
// Assert on overflow. For now, support transform feedback up to 2GB.
ASSERT(offsetsOut[bufferIndex] == writeOffset);
}
}
void TransformFeedbackVk::onBeginEnd(const gl::Context *context)
{
// Currently, we don't handle resources switching from read-only to writable and back correctly.
// In the case of transform feedback, the attached buffers can switch between being written by
// transform feedback and being read as a vertex array buffer. For now, we'll end the render
// pass every time transform feedback is started or ended to work around this issue temporarily.
//
// TODO(syoussefi): detect changes to buffer usage (e.g. as transform feedback output, vertex
// or index data etc) in the front end and notify the backend. A new node should be created
// only on such changes. http://anglebug.com/3205
ContextVk *contextVk = vk::GetImpl(context);
FramebufferVk *framebufferVk = vk::GetImpl(context->getState().getDrawFramebuffer());
vk::FramebufferHelper *framebuffer = framebufferVk->getFramebuffer();
if (framebuffer->hasStartedRenderPass())
{
framebuffer->finishCurrentCommands(contextVk);
}
}
} // namespace rx
......@@ -11,9 +11,19 @@
#define LIBANGLE_RENDERER_VULKAN_TRANSFORMFEEDBACKVK_H_
#include "libANGLE/renderer/TransformFeedbackImpl.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace gl
{
class ProgramState;
} // namespace gl
namespace rx
{
namespace vk
{
class DescriptorSetLayoutDesc;
}
class TransformFeedbackVk : public TransformFeedbackImpl
{
......@@ -29,6 +39,37 @@ class TransformFeedbackVk : public TransformFeedbackImpl
angle::Result bindIndexedBuffer(const gl::Context *context,
size_t index,
const gl::OffsetBindingPointer<gl::Buffer> &binding) override;
void updateDescriptorSetLayout(const gl::ProgramState &programState,
vk::DescriptorSetLayoutDesc *descSetLayoutOut) const;
void addFramebufferDependency(ContextVk *contextVk,
const gl::ProgramState &programState,
vk::FramebufferHelper *framebuffer) const;
void updateDescriptorSet(ContextVk *contextVk,
const gl::ProgramState &programState,
VkDescriptorSet descSet,
uint32_t bindingOffset) const;
void getBufferOffsets(ContextVk *contextVk,
const gl::ProgramState &programState,
GLint drawCallFirstVertex,
int32_t *offsetsOut,
size_t offsetsSize) const;
private:
void onBeginEnd(const gl::Context *context);
// Cached buffer properties for faster descriptor set update and offset calculation.
struct BoundBufferRange
{
// Offset as provided by OffsetBindingPointer.
VkDeviceSize offset = 0;
// Size as provided by OffsetBindingPointer.
VkDeviceSize size = 0;
// Aligned offset usable for VkDescriptorBufferInfo. This value could be smaller than
// offset.
VkDeviceSize alignedOffset = 0;
};
gl::TransformFeedbackBuffersArray<BoundBufferRange> mBoundBufferRanges;
};
} // namespace rx
......
......@@ -891,16 +891,17 @@ class PipelineLayoutCache final : angle::NonCopyable
//
// The set/binding assignment is done as following:
//
// - Set 0 contains the ANGLE driver uniforms at binding 0. Note that driver uniforms are updated
// - Set 0 contains uniform blocks created to encompass default uniforms. Bindings 0 and 1
// correspond to default uniforms in the vertex and fragment shaders respectively. Additionally,
// transform feedback buffers are bound from binding 2 and up.
// - Set 1 contains all textures.
// - Set 2 contains all uniform blocks.
// - Set 3 contains the ANGLE driver uniforms at binding 0. Note that driver uniforms are updated
// only under rare circumstances, such as viewport or depth range change. However, there is only
// one binding in this set.
// - Set 1 contains uniform blocks created to encompass default uniforms. Bindings 0 and 1
// correspond to default uniforms in the vertex and fragment shaders respectively.
// - Set 2 contains all textures.
// - Set 3 contains all uniform blocks.
// Uniforms set index:
constexpr uint32_t kUniformsDescriptorSetIndex = 0;
constexpr uint32_t kUniformsAndXfbDescriptorSetIndex = 0;
// Textures set index:
constexpr uint32_t kTextureDescriptorSetIndex = 1;
// Uniform blocks set index:
......@@ -914,6 +915,8 @@ constexpr uint32_t kReservedDriverUniformBindingCount = 1;
constexpr uint32_t kVertexUniformsBindingIndex = 0;
// Binding index for default uniforms in the fragment shader:
constexpr uint32_t kFragmentUniformsBindingIndex = 1;
// Binding index start for transform feedback buffers:
constexpr uint32_t kXfbBindingIndexStart = 2;
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
......@@ -225,14 +225,21 @@ void RendererVk::ensureCapsInitialized() const
// The gles2.0 section 2.10 states that "gl_Position is not a varying variable and does
// not count against this limit.", but the Vulkan spec has no such mention in its Built-in
// vars section. It is implicit that we need to actually reserve it for Vulkan in that case.
// TODO(lucferron): AMD has a weird behavior when we edge toward the maximum number of varyings
// and can often crash. Reserving an additional varying just for them bringing the total to 2.
// http://anglebug.com/2483
//
// Note: AMD has a weird behavior when we edge toward the maximum number of varyings and can
// often crash. Reserving an additional varying just for them bringing the total to 2.
constexpr GLint kReservedVaryingCount = 2;
mNativeCaps.maxVaryingVectors =
(mPhysicalDeviceProperties.limits.maxVertexOutputComponents / 4) - kReservedVaryingCount;
mNativeCaps.maxVertexOutputComponents = mNativeCaps.maxVaryingVectors * 4;
mNativeCaps.maxTransformFeedbackInterleavedComponents =
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS;
mNativeCaps.maxTransformFeedbackSeparateAttributes =
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS;
mNativeCaps.maxTransformFeedbackSeparateComponents =
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS;
const VkPhysicalDeviceLimits &limits = mPhysicalDeviceProperties.limits;
const uint32_t sampleCounts = limits.framebufferColorSampleCounts &
limits.framebufferDepthSampleCounts &
......
......@@ -26,9 +26,11 @@
PROC(Context) \
PROC(Framebuffer) \
PROC(MemoryObject) \
PROC(Query) \
PROC(Program) \
PROC(Semaphore) \
PROC(Texture) \
PROC(TransformFeedback) \
PROC(VertexArray)
#define ANGLE_PRE_DECLARE_OBJECT(OBJ) class OBJ;
......
......@@ -537,7 +537,6 @@
2950 VULKAN : dEQP-GLES3.functional.implementation_limits.max_fragment_input_components = SKIP
2950 VULKAN : dEQP-GLES3.functional.implementation_limits.max_program_texel_offset = SKIP
2950 VULKAN : dEQP-GLES3.functional.implementation_limits.min_program_texel_offset = SKIP
2950 VULKAN : dEQP-GLES3.functional.implementation_limits.max_transform_feedback_* = SKIP
// 3D texture (anglebug.com/3188), 2D array (anglebug.com/3189):
3189 VULKAN : dEQP-GLES3.functional.shaders.texture_functions.texturegrad.sampler2darrayshadow_vertex = SKIP
......@@ -680,22 +679,6 @@
3198 VULKAN : dEQP-GLES3.functional.uniform_api.value.* = SKIP
3198 VULKAN : dEQP-GLES3.functional.uniform_api.random.* = SKIP
// Transform feedback:
3205 VULKAN : dEQP-GLES3.functional.negative_api.shader.uniform_block_binding = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.shader.bind_transform_feedback = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.shader.begin_transform_feedback = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.shader.pause_transform_feedback = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.shader.resume_transform_feedback = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.shader.end_transform_feedback = FAIL
3205 VULKAN : dEQP-GLES3.functional.transform_feedback.* = FAIL
3205 VULKAN : dEQP-GLES3.functional.state_query.boolean.transform_feedback_* = FAIL
3205 VULKAN : dEQP-GLES3.functional.state_query.integers.max_transform_feedback_* = FAIL
3205 VULKAN : dEQP-GLES3.functional.state_query.integers.transform_feedback_* = FAIL
3205 VULKAN : dEQP-GLES3.functional.state_query.indexed.transform_feedback_* = FAIL
3205 VULKAN : dEQP-GLES3.functional.state_query.shader.transform_feedback = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.vertex_array.draw_range_elements = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.vertex_array.draw_range_elements_incomplete_primitive = FAIL
// Flat shading:
3430 VULKAN : dEQP-GLES3.functional.rasterization.flatshading.* = FAIL
3430 VULKAN : dEQP-GLES3.functional.shaders.linkage.varying.basic_types.u* = FAIL
......
......@@ -49,8 +49,8 @@
3457 VULKAN : KHR-GLES3.packed_pixels.pbo_rectangle.depth* = SKIP
3457 VULKAN : KHR-GLES3.packed_depth_stencil.* = SKIP
// CopyTexImage conversion bugs.
3458 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.* = FAIL
// CopyTexImage conversion missing 2D Array and 3D texture support.
3458 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.* = SKIP
// Require 3D textures.
3188 VULKAN : KHR-GLES3.packed_pixels.varied_rectangle.* = SKIP
......
......@@ -105,7 +105,7 @@ TEST_P(TransformFeedbackTest, ZeroSizedViewport)
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
// End the query and transform feedkback
// End the query and transform feedback
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
glEndTransformFeedback();
......@@ -236,7 +236,7 @@ TEST_P(TransformFeedbackTest, RecordAndDraw)
glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
// End the query and transform feedkback
// End the query and transform feedback
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
glEndTransformFeedback();
......@@ -1644,8 +1644,16 @@ TEST_P(TransformFeedbackTest, EndWithDifferentProgramContextSwitch)
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(TransformFeedbackTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(TransformFeedbackLifetimeTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(TransformFeedbackTest,
ES3_D3D11(),
ES3_OPENGL(),
ES3_OPENGLES(),
ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(TransformFeedbackLifetimeTest,
ES3_D3D11(),
ES3_OPENGL(),
ES3_OPENGLES(),
ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(TransformFeedbackTestES31, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES());
} // anonymous namespace
......@@ -63,7 +63,7 @@ class VulkanUniformUpdatesTest : public ANGLETest
// Force a small limit on the max sets per pool to more easily trigger a new allocation.
rx::vk::DynamicDescriptorPool *uniformPool =
programVk->getDynamicDescriptorPool(rx::kUniformsDescriptorSetIndex);
programVk->getDynamicDescriptorPool(rx::kUniformsAndXfbDescriptorSetIndex);
uniformPool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting);
VkDescriptorPoolSize uniformSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
rx::GetUniformBufferDescriptorCount()};
......
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