зеркало из https://github.com/AvaloniaUI/angle.git
Front-end support for xfb capture of I/O block members
Validation and generation of transform feedback varyings that specify an I/O block member are implemented in this change. The GL backend is able to pass the added tests. Bug: angleproject:3606 Change-Id: I66d02bed8ca9161555d0d1e7a32ae9ef4d9e813f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2599952 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com>
This commit is contained in:
Родитель
c500ee031d
Коммит
8065aa82d3
|
@ -306,16 +306,28 @@ const sh::ShaderVariable *ShaderVariable::findField(const std::string &fullName,
|
|||
return nullptr;
|
||||
}
|
||||
size_t pos = fullName.find_first_of(".");
|
||||
std::string topName, fieldName;
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
return nullptr;
|
||||
// If this is a shader I/O block without an instance name, return the field given only the
|
||||
// field name.
|
||||
if (!isShaderIOBlock || !name.empty())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fieldName = fullName;
|
||||
}
|
||||
std::string topName = fullName.substr(0, pos);
|
||||
if (topName != name)
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
std::string baseName = isShaderIOBlock ? structName : name;
|
||||
topName = fullName.substr(0, pos);
|
||||
if (topName != baseName)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
fieldName = fullName.substr(pos + 1);
|
||||
}
|
||||
std::string fieldName = fullName.substr(pos + 1);
|
||||
if (fieldName.empty())
|
||||
{
|
||||
return nullptr;
|
||||
|
|
|
@ -628,9 +628,8 @@ const std::vector<sh::ShaderVariable> &Shader::getActiveOutputVariables()
|
|||
|
||||
std::string Shader::getTransformFeedbackVaryingMappedName(const std::string &tfVaryingName)
|
||||
{
|
||||
// TODO(jiawei.shao@intel.com): support transform feedback on geometry shader.
|
||||
ASSERT(mState.getShaderType() == ShaderType::Vertex ||
|
||||
mState.getShaderType() == ShaderType::Geometry);
|
||||
ASSERT(mState.getShaderType() != ShaderType::Fragment &&
|
||||
mState.getShaderType() != ShaderType::Compute);
|
||||
const auto &varyings = getOutputVaryings();
|
||||
auto bracketPos = tfVaryingName.find("[");
|
||||
if (bracketPos != std::string::npos)
|
||||
|
@ -658,8 +657,21 @@ std::string Shader::getTransformFeedbackVaryingMappedName(const std::string &tfV
|
|||
{
|
||||
GLuint fieldIndex = 0;
|
||||
const auto *field = varying.findField(tfVaryingName, &fieldIndex);
|
||||
ASSERT(field != nullptr && !field->isStruct() && !field->isArray());
|
||||
return varying.mappedName + "." + field->mappedName;
|
||||
if (field == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ASSERT(field != nullptr && !field->isStruct() &&
|
||||
(!field->isArray() || varying.isShaderIOBlock));
|
||||
std::string mappedName;
|
||||
// If it's an I/O block without an instance name, don't include the block name.
|
||||
if (!varying.isShaderIOBlock || !varying.name.empty())
|
||||
{
|
||||
mappedName =
|
||||
varying.isShaderIOBlock ? varying.mappedStructName : varying.mappedName;
|
||||
mappedName += '.';
|
||||
}
|
||||
return mappedName + field->mappedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -667,7 +667,7 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
|
|||
const sh::ShaderVariable *field = input->findField(tfVarying, &fieldIndex);
|
||||
if (field != nullptr)
|
||||
{
|
||||
ASSERT(!field->isStruct() && !field->isArray());
|
||||
ASSERT(!field->isStruct() && (!field->isArray() || input->isShaderIOBlock));
|
||||
|
||||
packUserVaryingFieldTF(ref, *field, fieldIndex);
|
||||
uniqueFullNames[ref.frontShaderStage].insert(tfVarying);
|
||||
|
|
|
@ -2800,6 +2800,213 @@ TEST_P(TransformFeedbackTestES32, PrimitivesWrittenAndGenerated)
|
|||
}
|
||||
}
|
||||
|
||||
// Verify that capture of I/O block fields works, both when the instance name is specified and when
|
||||
// not. This test uses interleaved components.
|
||||
TEST_P(TransformFeedbackTestES31, IOBlocksInterleaved)
|
||||
{
|
||||
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
|
||||
|
||||
// http://anglebug.com/5488
|
||||
ANGLE_SKIP_TEST_IF(IsQualcomm() && IsOpenGLES());
|
||||
|
||||
// Not supported in Vulkan yet. http://anglebug.com/3606
|
||||
ANGLE_SKIP_TEST_IF(IsVulkan());
|
||||
|
||||
constexpr char kVS[] = R"(#version 310 es
|
||||
#extension GL_EXT_shader_io_blocks : require
|
||||
|
||||
out VSBlock1
|
||||
{
|
||||
vec4 a;
|
||||
vec4 b[2];
|
||||
} blockOut1;
|
||||
|
||||
out VSBlock2
|
||||
{
|
||||
vec4 c;
|
||||
mat3 d;
|
||||
vec4 e;
|
||||
};
|
||||
|
||||
out vec4 looseVarying;
|
||||
|
||||
void main()
|
||||
{
|
||||
blockOut1.a = vec4(0.15, 0.18, 0.21, 0.24);
|
||||
blockOut1.b[0] = vec4(0.27, 0.30, 0.33, 0.36);
|
||||
blockOut1.b[1] = vec4(0.39, 0.42, 0.45, 0.48);
|
||||
c = vec4(0.51, 0.54, 0.57, 0.6);
|
||||
d = mat3(vec3(0.63, 0.66, 0.69), vec3(0.72, 0.75, 0.78), vec3(0.81, 0.84, 0.87));
|
||||
e = vec4(0.9, 0.93, 0.96, 0.99);
|
||||
looseVarying = vec4(0.25, 0.5, 0.75, 1.0);
|
||||
})";
|
||||
|
||||
constexpr char kFS[] = R"(#version 310 es
|
||||
#extension GL_EXT_shader_io_blocks : require
|
||||
precision mediump float;
|
||||
|
||||
layout(location = 0) out mediump vec4 color;
|
||||
|
||||
in VSBlock2
|
||||
{
|
||||
vec4 c;
|
||||
mat3 d;
|
||||
vec4 e;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
color = vec4(c.x, d[0].y, e.z, 1.0);
|
||||
})";
|
||||
|
||||
std::vector<std::string> tfVaryings = {"VSBlock1.b", "d", "looseVarying"};
|
||||
constexpr size_t kCapturedVaryingsCount = 3;
|
||||
constexpr std::array<size_t, kCapturedVaryingsCount> kCaptureSizes = {8, 9, 4};
|
||||
const std::vector<float> kExpected[kCapturedVaryingsCount] = {
|
||||
{0.27, 0.30, 0.33, 0.36, 0.39, 0.42, 0.45, 0.48},
|
||||
{0.63, 0.66, 0.69, 0.72, 0.75, 0.78, 0.81, 0.84, 0.87},
|
||||
{0.25, 0.5, 0.75, 1.0},
|
||||
};
|
||||
|
||||
ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(program, kVS, kFS, tfVaryings, GL_INTERLEAVED_ATTRIBS);
|
||||
EXPECT_GL_NO_ERROR();
|
||||
|
||||
GLTransformFeedback xfb;
|
||||
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, xfb);
|
||||
|
||||
GLBuffer xfbBuffer;
|
||||
|
||||
size_t totalSize = 0;
|
||||
for (size_t index = 0; index < kCapturedVaryingsCount; ++index)
|
||||
{
|
||||
totalSize += kCaptureSizes[index];
|
||||
}
|
||||
|
||||
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfbBuffer);
|
||||
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, totalSize * sizeof(float), nullptr, GL_STATIC_DRAW);
|
||||
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfbBuffer);
|
||||
|
||||
glUseProgram(program);
|
||||
|
||||
glBeginTransformFeedback(GL_POINTS);
|
||||
glDrawArrays(GL_POINTS, 0, 1);
|
||||
glEndTransformFeedback();
|
||||
|
||||
const float *bufferData = static_cast<float *>(glMapBufferRange(
|
||||
GL_TRANSFORM_FEEDBACK_BUFFER, 0, totalSize * sizeof(float), GL_MAP_READ_BIT));
|
||||
|
||||
size_t currentOffset = 0;
|
||||
for (size_t index = 0; index < kCapturedVaryingsCount; ++index)
|
||||
{
|
||||
for (size_t component = 0; component < kCaptureSizes[index]; ++component)
|
||||
{
|
||||
EXPECT_NEAR(bufferData[currentOffset + component], kExpected[index][component], 0.001f)
|
||||
<< index << " " << component;
|
||||
}
|
||||
currentOffset += kCaptureSizes[index];
|
||||
}
|
||||
|
||||
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
|
||||
}
|
||||
|
||||
// Verify that capture of I/O block fields works. This test uses separate components.
|
||||
TEST_P(TransformFeedbackTestES31, IOBlocksSeparate)
|
||||
{
|
||||
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
|
||||
|
||||
// http://anglebug.com/5487
|
||||
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsOpenGL());
|
||||
|
||||
// http://anglebug.com/5488
|
||||
ANGLE_SKIP_TEST_IF(IsQualcomm() && IsOpenGLES());
|
||||
|
||||
// Not supported in Vulkan yet. http://anglebug.com/3606
|
||||
ANGLE_SKIP_TEST_IF(IsVulkan());
|
||||
|
||||
constexpr char kVS[] = R"(#version 310 es
|
||||
#extension GL_EXT_shader_io_blocks : require
|
||||
|
||||
out VSBlock
|
||||
{
|
||||
float a;
|
||||
vec2 b;
|
||||
};
|
||||
|
||||
out float c;
|
||||
|
||||
void main()
|
||||
{
|
||||
a = 0.25;
|
||||
b = vec2(0.5, 0.75);
|
||||
c = 1.0;
|
||||
})";
|
||||
|
||||
constexpr char kFS[] = R"(#version 310 es
|
||||
#extension GL_EXT_shader_io_blocks : require
|
||||
precision mediump float;
|
||||
|
||||
layout(location = 0) out mediump vec4 color;
|
||||
|
||||
in VSBlock
|
||||
{
|
||||
float a;
|
||||
vec2 b;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
color = vec4(a, b, 1.0);
|
||||
})";
|
||||
|
||||
std::vector<std::string> tfVaryings = {"a", "b", "c"};
|
||||
constexpr size_t kCapturedVaryingsCount = 3;
|
||||
constexpr std::array<size_t, kCapturedVaryingsCount> kCaptureSizes = {1, 2, 1};
|
||||
const std::vector<float> kExpected[kCapturedVaryingsCount] = {
|
||||
{0.25},
|
||||
{0.5, 0.75},
|
||||
{1.0},
|
||||
};
|
||||
|
||||
ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(program, kVS, kFS, tfVaryings, GL_SEPARATE_ATTRIBS);
|
||||
EXPECT_GL_NO_ERROR();
|
||||
|
||||
GLTransformFeedback xfb;
|
||||
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, xfb);
|
||||
|
||||
std::array<GLBuffer, kCapturedVaryingsCount> xfbBuffers;
|
||||
|
||||
for (size_t index = 0; index < kCapturedVaryingsCount; ++index)
|
||||
{
|
||||
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfbBuffers[index]);
|
||||
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, kCaptureSizes[index] * sizeof(float), nullptr,
|
||||
GL_STATIC_DRAW);
|
||||
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, index, xfbBuffers[index]);
|
||||
}
|
||||
|
||||
glUseProgram(program);
|
||||
|
||||
glBeginTransformFeedback(GL_POINTS);
|
||||
glDrawArrays(GL_POINTS, 0, 1);
|
||||
glEndTransformFeedback();
|
||||
|
||||
for (size_t index = 0; index < kCapturedVaryingsCount; ++index)
|
||||
{
|
||||
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfbBuffers[index]);
|
||||
|
||||
const float *bufferData = static_cast<float *>(
|
||||
glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, kCaptureSizes[index] * sizeof(float),
|
||||
GL_MAP_READ_BIT));
|
||||
|
||||
for (size_t component = 0; component < kCaptureSizes[index]; ++component)
|
||||
{
|
||||
EXPECT_NEAR(bufferData[component], kExpected[index][component], 0.001f)
|
||||
<< index << " " << component;
|
||||
}
|
||||
|
||||
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
|
||||
}
|
||||
}
|
||||
|
||||
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
|
||||
// tests should be run against.
|
||||
ANGLE_INSTANTIATE_TEST_ES3(TransformFeedbackTest);
|
||||
|
|
|
@ -350,6 +350,11 @@ bool IsNVIDIA()
|
|||
return HasSystemVendorID(kVendorID_NVIDIA);
|
||||
}
|
||||
|
||||
bool IsQualcomm()
|
||||
{
|
||||
return IsNexus5X() || IsNexus9() || IsPixelXL() || IsPixel2() || IsPixel2XL();
|
||||
}
|
||||
|
||||
bool IsConfigAllowlisted(const SystemInfo &systemInfo, const PlatformParameters ¶m)
|
||||
{
|
||||
VendorID vendorID =
|
||||
|
|
|
@ -44,6 +44,7 @@ bool IsIntel();
|
|||
bool IsAMD();
|
||||
bool IsARM();
|
||||
bool IsNVIDIA();
|
||||
bool IsQualcomm();
|
||||
|
||||
// GPU devices.
|
||||
bool IsSwiftshaderDevice();
|
||||
|
|
Загрузка…
Ссылка в новой задаче