зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
8bea8eec7a
Коммит
9ec3f51d11
|
@ -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(),
|
||||
|
|
Загрузка…
Ссылка в новой задаче