Reland "Vulkan: Implement OES_get_program_binary extension"

Reason for revert: default uniform initialization was incomplete

This change has the following fixes:
    1. Add missing default uniform initialization when loading
       program binaries.
    2. Re-enable OES Program Binary capabilities for Vulkan.
    3. Added two angle end2end test,
       - ProgramBinaryES3Test.BinaryWithLargeUniformCount
         uses several uniforms across the vertex and fragment
	 shaders.
       - ProgramBinaryES3Test.ActiveUniformShader tests
         the difference between uniform static and active use

Bug: angleproject:3216
Bug: angleproject:3217
Bug: angleproject:3665
Tests: dEQP-GLES3.functional.shader_api.program_binary*
       angle_end2end_tests --gtest_filter=ProgramBinary*
Change-Id: If6886f01241d65bb1e17a21cc3406533021072ee
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1699069
Commit-Queue: Mohan Maiya <m.maiya@samsung.com>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
Mohan Maiya 2019-07-19 13:06:16 -07:00 коммит произвёл Commit Bot
Родитель 8bea8eec7a
Коммит 9ec3f51d11
6 изменённых файлов: 346 добавлений и 25 удалений

Просмотреть файл

@ -677,11 +677,7 @@ void WriteBufferVariable(BinaryOutputStream *stream, const BufferVariable &var)
WriteShaderVar(stream, var);
stream->writeInt(var.bufferIndex);
stream->writeInt(var.blockInfo.offset);
stream->writeInt(var.blockInfo.arrayStride);
stream->writeInt(var.blockInfo.matrixStride);
stream->writeInt(var.blockInfo.isRowMajorMatrix);
stream->writeInt(var.blockInfo.topLevelArrayStride);
WriteBlockMemberInfo(stream, var.blockInfo);
stream->writeInt(var.topLevelArraySize);
for (ShaderType shaderType : AllShaderTypes())
@ -694,13 +690,9 @@ void LoadBufferVariable(BinaryInputStream *stream, BufferVariable *var)
{
LoadShaderVar(stream, var);
var->bufferIndex = stream->readInt<int>();
var->blockInfo.offset = stream->readInt<int>();
var->blockInfo.arrayStride = stream->readInt<int>();
var->blockInfo.matrixStride = stream->readInt<int>();
var->blockInfo.isRowMajorMatrix = stream->readBool();
var->blockInfo.topLevelArrayStride = stream->readInt<int>();
var->topLevelArraySize = stream->readInt<int>();
var->bufferIndex = stream->readInt<int>();
LoadBlockMemberInfo(stream, &var->blockInfo);
var->topLevelArraySize = stream->readInt<int>();
for (ShaderType shaderType : AllShaderTypes())
{
@ -862,6 +854,24 @@ bool IsActiveInterfaceBlock(const sh::InterfaceBlock &interfaceBlock)
return interfaceBlock.active || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED;
}
void WriteBlockMemberInfo(BinaryOutputStream *stream, const sh::BlockMemberInfo &var)
{
stream->writeInt(var.arrayStride);
stream->writeInt(var.isRowMajorMatrix);
stream->writeInt(var.matrixStride);
stream->writeInt(var.offset);
stream->writeInt(var.topLevelArrayStride);
}
void LoadBlockMemberInfo(BinaryInputStream *stream, sh::BlockMemberInfo *var)
{
var->arrayStride = stream->readInt<int>();
var->isRowMajorMatrix = stream->readBool();
var->matrixStride = stream->readInt<int>();
var->offset = stream->readInt<int>();
var->topLevelArrayStride = stream->readInt<int>();
}
// VariableLocation implementation.
VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false) {}
@ -4561,10 +4571,7 @@ void Program::serialize(const Context *context, angle::MemoryBuffer *binaryOut)
// FIXME: referenced
stream.writeInt(uniform.bufferIndex);
stream.writeInt(uniform.blockInfo.offset);
stream.writeInt(uniform.blockInfo.arrayStride);
stream.writeInt(uniform.blockInfo.matrixStride);
stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
WriteBlockMemberInfo(&stream, uniform.blockInfo);
// Active shader info
for (ShaderType shaderType : gl::AllShaderTypes())
@ -4759,11 +4766,8 @@ angle::Result Program::deserialize(const Context *context,
LinkedUniform uniform;
LoadShaderVar(&stream, &uniform);
uniform.bufferIndex = stream.readInt<int>();
uniform.blockInfo.offset = stream.readInt<int>();
uniform.blockInfo.arrayStride = stream.readInt<int>();
uniform.blockInfo.matrixStride = stream.readInt<int>();
uniform.blockInfo.isRowMajorMatrix = stream.readBool();
uniform.bufferIndex = stream.readInt<int>();
LoadBlockMemberInfo(&stream, &uniform.blockInfo);
uniform.typeInfo = &GetUniformTypeInfo(uniform.type);

Просмотреть файл

@ -43,6 +43,7 @@ namespace gl
{
class Buffer;
class BinaryInputStream;
class BinaryOutputStream;
struct Caps;
class Context;
struct Extensions;
@ -165,6 +166,9 @@ void LogLinkMismatch(InfoLog &infoLog,
bool IsActiveInterfaceBlock(const sh::InterfaceBlock &interfaceBlock);
void WriteBlockMemberInfo(BinaryOutputStream *stream, const sh::BlockMemberInfo &var);
void LoadBlockMemberInfo(BinaryInputStream *stream, sh::BlockMemberInfo *var);
// Struct used for correlating uniforms/elements of uniform arrays to handles
struct VariableLocation
{

Просмотреть файл

@ -305,12 +305,42 @@ std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context,
gl::InfoLog &infoLog)
{
ContextVk *contextVk = vk::GetImpl(context);
gl::ShaderMap<size_t> requiredBufferSize;
requiredBufferSize.fill(0);
angle::Result status = loadShaderSource(contextVk, stream);
if (status != angle::Result::Continue)
{
return std::make_unique<LinkEventDone>(status);
}
// Deserializes the uniformLayout data of mDefaultUniformBlocks
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
const size_t uniformCount = stream->readInt<size_t>();
for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
{
sh::BlockMemberInfo blockInfo;
gl::LoadBlockMemberInfo(stream, &blockInfo);
mDefaultUniformBlocks[shaderType].uniformLayout.push_back(blockInfo);
}
}
// Deserializes required uniform block memory sizes
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
requiredBufferSize[shaderType] = stream->readInt<size_t>();
}
reset(contextVk);
// Initialize and resize the mDefaultUniformBlocks' memory
status = resizeUniformBlockMemory(contextVk, requiredBufferSize);
if (status != angle::Result::Continue)
{
return std::make_unique<LinkEventDone>(status);
}
return std::make_unique<LinkEventDone>(linkImpl(context, infoLog));
}
@ -319,6 +349,25 @@ void ProgramVk::save(const gl::Context *context, gl::BinaryOutputStream *stream)
// (geofflang): Look into saving shader modules in ShaderInfo objects (keep in mind that we
// compile shaders lazily)
saveShaderSource(stream);
// Serializes the uniformLayout data of mDefaultUniformBlocks
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
const size_t uniformCount = mDefaultUniformBlocks[shaderType].uniformLayout.size();
stream->writeInt<size_t>(uniformCount);
for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
{
sh::BlockMemberInfo &blockInfo =
mDefaultUniformBlocks[shaderType].uniformLayout[uniformIndex];
gl::WriteBlockMemberInfo(stream, blockInfo);
}
}
// Serializes required uniform block memory sizes
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
stream->writeInt(mDefaultUniformBlocks[shaderType].uniformData.size());
}
}
void ProgramVk::setBinaryRetrievableHint(bool retrievable)
@ -335,12 +384,21 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog)
{
ContextVk *contextVk = vk::GetImpl(context);
// Link resources before calling GetShaderSource to make sure they are ready for the set/binding
// assignment done in that function.
linkResources(resources);
GlslangWrapper::GetShaderSource(mState, resources, &mShaderSources);
reset(contextVk);
angle::Result status = initDefaultUniformBlocks(context);
if (status != angle::Result::Continue)
{
return std::make_unique<LinkEventDone>(status);
}
// TODO(jie.a.chen@intel.com): Parallelize linking.
// http://crbug.com/849576
return std::make_unique<LinkEventDone>(linkImpl(context, infoLog));
@ -353,11 +411,8 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
RendererVk *renderer = contextVk->getRenderer();
gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback();
reset(contextVk);
updateBindingOffsets();
ANGLE_TRY(initDefaultUniformBlocks(glContext));
// Store a reference to the pipeline and descriptor set layouts. This will create them if they
// don't already exist in the cache.
@ -495,13 +550,22 @@ void ProgramVk::linkResources(const gl::ProgramLinkedResources &resources)
angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
{
ContextVk *contextVk = vk::GetImpl(glContext);
RendererVk *renderer = contextVk->getRenderer();
// Process vertex and fragment uniforms into std140 packing.
gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
gl::ShaderMap<size_t> requiredBufferSize;
requiredBufferSize.fill(0);
generateUniformLayoutMapping(layoutMap, requiredBufferSize);
initDefaultUniformLayoutMapping(layoutMap);
// All uniform initializations are complete, now resize the buffers accordingly and return
return resizeUniformBlockMemory(contextVk, requiredBufferSize);
}
void ProgramVk::generateUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap,
gl::ShaderMap<size_t> &requiredBufferSize)
{
for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{
gl::Shader *shader = mState.getAttachedShader(shaderType);
@ -513,7 +577,10 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
&requiredBufferSize[shaderType]);
}
}
}
void ProgramVk::initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap)
{
// Init the default block layout info.
const auto &uniforms = mState.getUniforms();
for (const gl::VariableLocation &location : mState.getUniformLocations())
@ -553,7 +620,12 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
mDefaultUniformBlocks[shaderType].uniformLayout.push_back(layoutInfo[shaderType]);
}
}
}
angle::Result ProgramVk::resizeUniformBlockMemory(ContextVk *contextVk,
gl::ShaderMap<size_t> &requiredBufferSize)
{
RendererVk *renderer = contextVk->getRenderer();
for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{
if (requiredBufferSize[shaderType] > 0)

Просмотреть файл

@ -173,6 +173,11 @@ class ProgramVk : public ProgramImpl
uint32_t descriptorSetIndex,
bool *newPoolAllocatedOut);
angle::Result initDefaultUniformBlocks(const gl::Context *glContext);
void generateUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap,
gl::ShaderMap<size_t> &requiredBufferSize);
void initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap);
angle::Result resizeUniformBlockMemory(ContextVk *contextVk,
gl::ShaderMap<size_t> &requiredBufferSize);
void updateDefaultUniformsDescriptorSet(ContextVk *contextVk);
void updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk);

Просмотреть файл

@ -331,6 +331,10 @@ void RendererVk::ensureCapsInitialized() const
mNativeCaps.maxSamples = vk_gl::GetMaxSampleCount(sampleCounts);
mNativeCaps.subPixelBits = limitsVk.subPixelPrecisionBits;
// Enable Program Binary extension.
mNativeExtensions.getProgramBinary = true;
mNativeCaps.programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
}
namespace egl_vk

Просмотреть файл

@ -388,6 +388,238 @@ TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
testBinaryAndUBOBlockIndexes(false);
}
// Tests the difference between uniform static and active use
TEST_P(ProgramBinaryES3Test, ActiveUniformShader)
{
// We can't run the test if no program binary formats are supported.
GLint binaryFormatCount = 0;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
ANGLE_SKIP_TEST_IF(!binaryFormatCount);
constexpr char kVS[] =
"#version 300 es\n"
"in vec4 position;\n"
"void main() {\n"
" gl_Position = position;\n"
"}";
constexpr char kFS[] =
"#version 300 es\n"
"precision mediump float;\n"
"uniform float values[2];\n"
"out vec4 color;\n"
"bool isZero(float value) {\n"
" return value == 0.0f;\n"
"}\n"
"void main() {\n"
" color = isZero(values[1]) ? vec4(1.0f,0.0f,0.0f,1.0f) : vec4(0.0f,1.0f,0.0f,1.0f);\n"
"}";
// Init and draw with the program.
ANGLE_GL_PROGRAM(program, kVS, kFS);
GLint valuesLoc = glGetUniformLocation(program.get(), "values");
ASSERT_NE(-1, valuesLoc);
glUseProgram(program.get());
GLfloat values[2] = {0.5f, 1.0f};
glUniform1fv(valuesLoc, 2, values);
ASSERT_GL_NO_ERROR();
glClearColor(1.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
drawQuad(program.get(), "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Read back the binary.
GLint programLength = 0;
glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
ASSERT_GL_NO_ERROR();
GLsizei readLength = 0;
GLenum binaryFormat = GL_NONE;
std::vector<uint8_t> binary(programLength);
glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
ASSERT_GL_NO_ERROR();
EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
// Load a new program with the binary and draw.
ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
valuesLoc = glGetUniformLocation(program.get(), "values");
ASSERT_NE(-1, valuesLoc);
glUseProgram(binaryProgram.get());
GLfloat values2[2] = {0.1f, 1.0f};
glUniform1fv(valuesLoc, 2, values2);
ASSERT_GL_NO_ERROR();
glClearColor(1.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
drawQuad(binaryProgram.get(), "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test that uses many uniforms in the shaders
TEST_P(ProgramBinaryES3Test, BinaryWithLargeUniformCount)
{
// Suspecting AMD driver bug - failure seen on bots running on ATI GPU on Windows.
// http://anglebug.com/3721
ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL() && IsWindows());
// We can't run the test if no program binary formats are supported.
GLint binaryFormatCount = 0;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
ANGLE_SKIP_TEST_IF(!binaryFormatCount);
constexpr char kVS[] =
"#version 300 es\n"
"uniform float redVS; \n"
"uniform block0 {\n"
" float val0;\n"
"};\n"
"uniform float greenVS; \n"
"uniform float blueVS; \n"
"in vec4 position;\n"
"out vec4 color;\n"
"void main() {\n"
" gl_Position = position;\n"
" color = vec4(redVS + val0, greenVS, blueVS, 1.0f);\n"
"}";
constexpr char kFS[] =
"#version 300 es\n"
"precision mediump float;\n"
"uniform float redFS; \n"
"uniform float greenFS; \n"
"uniform block1 {\n"
" float val1;\n"
" float val2;\n"
"};\n"
"uniform float blueFS; \n"
"in vec4 color;\n"
"out vec4 colorOut;\n"
"void main() {\n"
" colorOut = vec4(color.r + redFS,\n"
" color.g + greenFS + val1,\n"
" color.b + blueFS + val2, \n"
" color.a);\n"
"}";
// Init and draw with the program.
ANGLE_GL_PROGRAM(program, kVS, kFS);
float block0Data[4] = {-0.7f, 1.0f, 1.0f, 1.0f};
float block1Data[4] = {0.4f, -0.8f, 1.0f, 1.0f};
GLuint bindIndex0 = 5;
GLuint bindIndex1 = 2;
GLBuffer ubo0;
glBindBuffer(GL_UNIFORM_BUFFER, ubo0.get());
glBufferData(GL_UNIFORM_BUFFER, sizeof(block0Data), &block0Data, GL_STATIC_DRAW);
glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex0, ubo0.get(), 0, sizeof(block0Data));
ASSERT_GL_NO_ERROR();
GLBuffer ubo1;
glBindBuffer(GL_UNIFORM_BUFFER, ubo1.get());
glBufferData(GL_UNIFORM_BUFFER, sizeof(block1Data), &block1Data, GL_STATIC_DRAW);
glBindBufferRange(GL_UNIFORM_BUFFER, bindIndex1, ubo1.get(), 0, sizeof(block1Data));
ASSERT_GL_NO_ERROR();
GLint block0Index = glGetUniformBlockIndex(program.get(), "block0");
ASSERT_NE(-1, block0Index);
GLint block1Index = glGetUniformBlockIndex(program.get(), "block1");
ASSERT_NE(-1, block1Index);
glUniformBlockBinding(program.get(), block0Index, bindIndex0);
glUniformBlockBinding(program.get(), block1Index, bindIndex1);
ASSERT_GL_NO_ERROR();
GLint redVSLoc = glGetUniformLocation(program.get(), "redVS");
ASSERT_NE(-1, redVSLoc);
GLint greenVSLoc = glGetUniformLocation(program.get(), "greenVS");
ASSERT_NE(-1, greenVSLoc);
GLint blueVSLoc = glGetUniformLocation(program.get(), "blueVS");
ASSERT_NE(-1, blueVSLoc);
GLint redFSLoc = glGetUniformLocation(program.get(), "redFS");
ASSERT_NE(-1, redFSLoc);
GLint greenFSLoc = glGetUniformLocation(program.get(), "greenFS");
ASSERT_NE(-1, greenFSLoc);
GLint blueFSLoc = glGetUniformLocation(program.get(), "blueFS");
ASSERT_NE(-1, blueFSLoc);
glUseProgram(program.get());
glUniform1f(redVSLoc, 0.6f);
glUniform1f(greenVSLoc, 0.2f);
glUniform1f(blueVSLoc, 1.1f);
glUniform1f(redFSLoc, 0.1f);
glUniform1f(greenFSLoc, 0.4f);
glUniform1f(blueFSLoc, 0.7f);
ASSERT_GL_NO_ERROR();
glClearColor(1.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
drawQuad(program.get(), "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
// Read back the binary.
GLint programLength = 0;
glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
ASSERT_GL_NO_ERROR();
GLsizei readLength = 0;
GLenum binaryFormat = GL_NONE;
std::vector<uint8_t> binary(programLength);
glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
ASSERT_GL_NO_ERROR();
EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
// Load a new program with the binary and draw.
ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
redVSLoc = glGetUniformLocation(program.get(), "redVS");
ASSERT_NE(-1, redVSLoc);
greenVSLoc = glGetUniformLocation(program.get(), "greenVS");
ASSERT_NE(-1, greenVSLoc);
blueVSLoc = glGetUniformLocation(program.get(), "blueVS");
ASSERT_NE(-1, blueVSLoc);
redFSLoc = glGetUniformLocation(program.get(), "redFS");
ASSERT_NE(-1, redFSLoc);
greenFSLoc = glGetUniformLocation(program.get(), "greenFS");
ASSERT_NE(-1, greenFSLoc);
blueFSLoc = glGetUniformLocation(program.get(), "blueFS");
ASSERT_NE(-1, blueFSLoc);
glUseProgram(binaryProgram.get());
glUniform1f(redVSLoc, 0.2f);
glUniform1f(greenVSLoc, -0.6f);
glUniform1f(blueVSLoc, 1.0f);
glUniform1f(redFSLoc, 1.5f);
glUniform1f(greenFSLoc, 0.2f);
glUniform1f(blueFSLoc, 0.8f);
ASSERT_GL_NO_ERROR();
glClearColor(1.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
drawQuad(binaryProgram.get(), "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
}
ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test,
ES3_D3D11(),
ES3_OPENGL(),