Commit 9ec3f51d by Mohan Maiya Committed by Commit Bot

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: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent 8bea8eec
...@@ -677,11 +677,7 @@ void WriteBufferVariable(BinaryOutputStream *stream, const BufferVariable &var) ...@@ -677,11 +677,7 @@ void WriteBufferVariable(BinaryOutputStream *stream, const BufferVariable &var)
WriteShaderVar(stream, var); WriteShaderVar(stream, var);
stream->writeInt(var.bufferIndex); stream->writeInt(var.bufferIndex);
stream->writeInt(var.blockInfo.offset); WriteBlockMemberInfo(stream, var.blockInfo);
stream->writeInt(var.blockInfo.arrayStride);
stream->writeInt(var.blockInfo.matrixStride);
stream->writeInt(var.blockInfo.isRowMajorMatrix);
stream->writeInt(var.blockInfo.topLevelArrayStride);
stream->writeInt(var.topLevelArraySize); stream->writeInt(var.topLevelArraySize);
for (ShaderType shaderType : AllShaderTypes()) for (ShaderType shaderType : AllShaderTypes())
...@@ -695,11 +691,7 @@ void LoadBufferVariable(BinaryInputStream *stream, BufferVariable *var) ...@@ -695,11 +691,7 @@ void LoadBufferVariable(BinaryInputStream *stream, BufferVariable *var)
LoadShaderVar(stream, var); LoadShaderVar(stream, var);
var->bufferIndex = stream->readInt<int>(); var->bufferIndex = stream->readInt<int>();
var->blockInfo.offset = stream->readInt<int>(); LoadBlockMemberInfo(stream, &var->blockInfo);
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->topLevelArraySize = stream->readInt<int>();
for (ShaderType shaderType : AllShaderTypes()) for (ShaderType shaderType : AllShaderTypes())
...@@ -862,6 +854,24 @@ bool IsActiveInterfaceBlock(const sh::InterfaceBlock &interfaceBlock) ...@@ -862,6 +854,24 @@ bool IsActiveInterfaceBlock(const sh::InterfaceBlock &interfaceBlock)
return interfaceBlock.active || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED; 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 implementation.
VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false) {} VariableLocation::VariableLocation() : arrayIndex(0), index(kUnused), ignored(false) {}
...@@ -4561,10 +4571,7 @@ void Program::serialize(const Context *context, angle::MemoryBuffer *binaryOut) ...@@ -4561,10 +4571,7 @@ void Program::serialize(const Context *context, angle::MemoryBuffer *binaryOut)
// FIXME: referenced // FIXME: referenced
stream.writeInt(uniform.bufferIndex); stream.writeInt(uniform.bufferIndex);
stream.writeInt(uniform.blockInfo.offset); WriteBlockMemberInfo(&stream, uniform.blockInfo);
stream.writeInt(uniform.blockInfo.arrayStride);
stream.writeInt(uniform.blockInfo.matrixStride);
stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
// Active shader info // Active shader info
for (ShaderType shaderType : gl::AllShaderTypes()) for (ShaderType shaderType : gl::AllShaderTypes())
...@@ -4760,10 +4767,7 @@ angle::Result Program::deserialize(const Context *context, ...@@ -4760,10 +4767,7 @@ angle::Result Program::deserialize(const Context *context,
LoadShaderVar(&stream, &uniform); LoadShaderVar(&stream, &uniform);
uniform.bufferIndex = stream.readInt<int>(); uniform.bufferIndex = stream.readInt<int>();
uniform.blockInfo.offset = stream.readInt<int>(); LoadBlockMemberInfo(&stream, &uniform.blockInfo);
uniform.blockInfo.arrayStride = stream.readInt<int>();
uniform.blockInfo.matrixStride = stream.readInt<int>();
uniform.blockInfo.isRowMajorMatrix = stream.readBool();
uniform.typeInfo = &GetUniformTypeInfo(uniform.type); uniform.typeInfo = &GetUniformTypeInfo(uniform.type);
......
...@@ -43,6 +43,7 @@ namespace gl ...@@ -43,6 +43,7 @@ namespace gl
{ {
class Buffer; class Buffer;
class BinaryInputStream; class BinaryInputStream;
class BinaryOutputStream;
struct Caps; struct Caps;
class Context; class Context;
struct Extensions; struct Extensions;
...@@ -165,6 +166,9 @@ void LogLinkMismatch(InfoLog &infoLog, ...@@ -165,6 +166,9 @@ void LogLinkMismatch(InfoLog &infoLog,
bool IsActiveInterfaceBlock(const sh::InterfaceBlock &interfaceBlock); 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 used for correlating uniforms/elements of uniform arrays to handles
struct VariableLocation struct VariableLocation
{ {
......
...@@ -305,12 +305,42 @@ std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context, ...@@ -305,12 +305,42 @@ std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context,
gl::InfoLog &infoLog) gl::InfoLog &infoLog)
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
gl::ShaderMap<size_t> requiredBufferSize;
requiredBufferSize.fill(0);
angle::Result status = loadShaderSource(contextVk, stream); angle::Result status = loadShaderSource(contextVk, stream);
if (status != angle::Result::Continue) if (status != angle::Result::Continue)
{ {
return std::make_unique<LinkEventDone>(status); 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)); return std::make_unique<LinkEventDone>(linkImpl(context, infoLog));
} }
...@@ -319,6 +349,25 @@ void ProgramVk::save(const gl::Context *context, gl::BinaryOutputStream *stream) ...@@ -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 // (geofflang): Look into saving shader modules in ShaderInfo objects (keep in mind that we
// compile shaders lazily) // compile shaders lazily)
saveShaderSource(stream); 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) void ProgramVk::setBinaryRetrievableHint(bool retrievable)
...@@ -335,12 +384,21 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context, ...@@ -335,12 +384,21 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
const gl::ProgramLinkedResources &resources, const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog) gl::InfoLog &infoLog)
{ {
ContextVk *contextVk = vk::GetImpl(context);
// Link resources before calling GetShaderSource to make sure they are ready for the set/binding // Link resources before calling GetShaderSource to make sure they are ready for the set/binding
// assignment done in that function. // assignment done in that function.
linkResources(resources); linkResources(resources);
GlslangWrapper::GetShaderSource(mState, resources, &mShaderSources); 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. // TODO(jie.a.chen@intel.com): Parallelize linking.
// http://crbug.com/849576 // http://crbug.com/849576
return std::make_unique<LinkEventDone>(linkImpl(context, infoLog)); return std::make_unique<LinkEventDone>(linkImpl(context, infoLog));
...@@ -353,11 +411,8 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf ...@@ -353,11 +411,8 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback(); gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback();
reset(contextVk);
updateBindingOffsets(); updateBindingOffsets();
ANGLE_TRY(initDefaultUniformBlocks(glContext));
// Store a reference to the pipeline and descriptor set layouts. This will create them if they // Store a reference to the pipeline and descriptor set layouts. This will create them if they
// don't already exist in the cache. // don't already exist in the cache.
...@@ -495,13 +550,22 @@ void ProgramVk::linkResources(const gl::ProgramLinkedResources &resources) ...@@ -495,13 +550,22 @@ void ProgramVk::linkResources(const gl::ProgramLinkedResources &resources)
angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext) angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
{ {
ContextVk *contextVk = vk::GetImpl(glContext); ContextVk *contextVk = vk::GetImpl(glContext);
RendererVk *renderer = contextVk->getRenderer();
// Process vertex and fragment uniforms into std140 packing. // Process vertex and fragment uniforms into std140 packing.
gl::ShaderMap<sh::BlockLayoutMap> layoutMap; gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
gl::ShaderMap<size_t> requiredBufferSize; gl::ShaderMap<size_t> requiredBufferSize;
requiredBufferSize.fill(0); 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()) for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{ {
gl::Shader *shader = mState.getAttachedShader(shaderType); gl::Shader *shader = mState.getAttachedShader(shaderType);
...@@ -513,7 +577,10 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext) ...@@ -513,7 +577,10 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
&requiredBufferSize[shaderType]); &requiredBufferSize[shaderType]);
} }
} }
}
void ProgramVk::initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap)
{
// Init the default block layout info. // Init the default block layout info.
const auto &uniforms = mState.getUniforms(); const auto &uniforms = mState.getUniforms();
for (const gl::VariableLocation &location : mState.getUniformLocations()) for (const gl::VariableLocation &location : mState.getUniformLocations())
...@@ -553,7 +620,12 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext) ...@@ -553,7 +620,12 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
mDefaultUniformBlocks[shaderType].uniformLayout.push_back(layoutInfo[shaderType]); 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()) for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{ {
if (requiredBufferSize[shaderType] > 0) if (requiredBufferSize[shaderType] > 0)
......
...@@ -173,6 +173,11 @@ class ProgramVk : public ProgramImpl ...@@ -173,6 +173,11 @@ class ProgramVk : public ProgramImpl
uint32_t descriptorSetIndex, uint32_t descriptorSetIndex,
bool *newPoolAllocatedOut); bool *newPoolAllocatedOut);
angle::Result initDefaultUniformBlocks(const gl::Context *glContext); 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 updateDefaultUniformsDescriptorSet(ContextVk *contextVk);
void updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk); void updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk);
......
...@@ -331,6 +331,10 @@ void RendererVk::ensureCapsInitialized() const ...@@ -331,6 +331,10 @@ void RendererVk::ensureCapsInitialized() const
mNativeCaps.maxSamples = vk_gl::GetMaxSampleCount(sampleCounts); mNativeCaps.maxSamples = vk_gl::GetMaxSampleCount(sampleCounts);
mNativeCaps.subPixelBits = limitsVk.subPixelPrecisionBits; mNativeCaps.subPixelBits = limitsVk.subPixelPrecisionBits;
// Enable Program Binary extension.
mNativeExtensions.getProgramBinary = true;
mNativeCaps.programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
} }
namespace egl_vk namespace egl_vk
......
...@@ -388,6 +388,238 @@ TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw) ...@@ -388,6 +388,238 @@ TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
testBinaryAndUBOBlockIndexes(false); 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, ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test,
ES3_D3D11(), ES3_D3D11(),
ES3_OPENGL(), ES3_OPENGL(),
......
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