Commit 6db1c2e8 by Jamie Madill

Link interface blocks in ProgramImpl::link.

This allows the back-end to have access to the interface block info in the link operation, and also allows the interface block info to have direct access to the post-link Impl information. BUG=angleproject:2208 Change-Id: Ib2bfb3c9155eee715bd3d29de1c3fdd67b16eed4 Reviewed-on: https://chromium-review.googlesource.com/753521Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 8f8edd6e
......@@ -871,7 +871,7 @@ Error Program::link(const gl::Context *context)
}
gatherAtomicCounterBuffers();
gatherInterfaceBlockInfo(context);
initInterfaceBlockBindings();
setUniformValuesFromBindingQualifiers();
......@@ -2874,55 +2874,8 @@ void Program::gatherAtomicCounterBuffers()
// TODO(jie.a.chen@intel.com): Get the actual BUFFER_DATA_SIZE from backend for each buffer.
}
void Program::gatherUniformBlockInfo(const gl::Context *context)
void Program::initInterfaceBlockBindings()
{
UniformBlockLinker blockLinker(&mState.mUniformBlocks, &mState.mUniforms);
InitUniformBlockLinker(context, mState, &blockLinker);
auto getImplBlockSize = [this](const std::string &name, const std::string &mappedName,
size_t *sizeOut) {
return this->mProgram->getUniformBlockSize(name, mappedName, sizeOut);
};
auto getImplMemberInfo = [this](const std::string &name, const std::string &mappedName,
sh::BlockMemberInfo *infoOut) {
return this->mProgram->getUniformBlockMemberInfo(name, mappedName, infoOut);
};
blockLinker.linkBlocks(getImplBlockSize, getImplMemberInfo);
}
void Program::gatherShaderStorageBlockInfo(const gl::Context *context)
{
ShaderStorageBlockLinker blockLinker(&mState.mShaderStorageBlocks);
InitShaderStorageBlockLinker(context, mState, &blockLinker);
// We don't have a way of determining block info for shader storage blocks yet.
// TODO(jiajia.qin@intel.com): Determine correct block size and layout.
auto getImplBlockSize = [this](const std::string &name, const std::string &mappedName,
size_t *sizeOut) {
return this->mProgram->getUniformBlockSize(name, mappedName, sizeOut);
};
auto getImplMemberInfo = [this](const std::string &name, const std::string &mappedName,
sh::BlockMemberInfo *infoOut) {
return this->mProgram->getUniformBlockMemberInfo(name, mappedName, infoOut);
};
blockLinker.linkBlocks(getImplBlockSize, getImplMemberInfo);
}
void Program::gatherInterfaceBlockInfo(const Context *context)
{
ASSERT(mState.mUniformBlocks.empty());
ASSERT(mState.mShaderStorageBlocks.empty());
gatherUniformBlockInfo(context);
if (context->getClientVersion() >= Version(3, 1))
{
gatherShaderStorageBlockInfo(context);
}
// Set initial bindings from shader.
for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
{
......
......@@ -640,9 +640,7 @@ class Program final : angle::NonCopyable, public LabeledObject
void setUniformValuesFromBindingQualifiers();
void gatherAtomicCounterBuffers();
void gatherUniformBlockInfo(const gl::Context *context);
void gatherShaderStorageBlockInfo(const gl::Context *context);
void gatherInterfaceBlockInfo(const Context *context);
void initInterfaceBlockBindings();
// Both these function update the cached uniform values and return a modified "count"
// so that the uniform update doesn't overflow the uniform.
......
......@@ -637,6 +637,8 @@ void InterfaceBlockLinker::addShaderBlocks(GLenum shader,
void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
const GetBlockMemberInfo &getMemberInfo) const
{
ASSERT(mBlocksOut->empty());
std::set<std::string> visitedList;
for (const auto &shaderBlocks : mShaderBlocks)
......
......@@ -83,17 +83,6 @@ class ProgramImpl : angle::NonCopyable
// TODO: synchronize in syncState when dirty bits exist.
virtual void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) = 0;
// May only be called after a successful link operation.
// Return false for inactive blocks.
virtual bool getUniformBlockSize(const std::string &blockName,
const std::string &blockMappedName,
size_t *sizeOut) const = 0;
// May only be called after a successful link operation.
// Returns false for inactive members.
virtual bool getUniformBlockMemberInfo(const std::string &memberUniformName,
const std::string &memberUniformMappedName,
sh::BlockMemberInfo *memberInfoOut) const = 0;
// CHROMIUM_path_rendering
// Set parameters to control fragment shader input variable interpolation
virtual void setPathFragmentInputGen(const std::string &inputName,
......
......@@ -63,10 +63,6 @@ class MockProgramImpl : public rx::ProgramImpl
MOCK_CONST_METHOD3(getUniformuiv, void(const gl::Context *, GLint, GLuint *));
MOCK_METHOD2(setUniformBlockBinding, void(GLuint, GLuint));
MOCK_CONST_METHOD3(getUniformBlockSize,
bool(const std::string &, const std::string &, size_t *));
MOCK_CONST_METHOD3(getUniformBlockMemberInfo,
bool(const std::string &, const std::string &, sh::BlockMemberInfo *));
MOCK_METHOD4(setPathFragmentInputGen,
void(const std::string &, GLenum, GLint, const GLfloat *));
......
......@@ -199,6 +199,97 @@ void GetMatrixUniform(GLint columns, GLint rows, NonFloatT *dataOut, const NonFl
UNREACHABLE();
}
class UniformBlockInfo final : angle::NonCopyable
{
public:
UniformBlockInfo() {}
void getShaderBlockInfo(const gl::Context *context, gl::Shader *shader);
bool getBlockSize(const std::string &name, const std::string &mappedName, size_t *sizeOut);
bool getBlockMemberInfo(const std::string &name,
const std::string &mappedName,
sh::BlockMemberInfo *infoOut);
private:
size_t getBlockInfo(const sh::InterfaceBlock &interfaceBlock);
std::map<std::string, size_t> mBlockSizes;
sh::BlockLayoutMap mBlockLayout;
};
void UniformBlockInfo::getShaderBlockInfo(const gl::Context *context, gl::Shader *shader)
{
for (const sh::InterfaceBlock &interfaceBlock : shader->getUniformBlocks(context))
{
if (!interfaceBlock.staticUse && interfaceBlock.layout == sh::BLOCKLAYOUT_PACKED)
continue;
if (mBlockSizes.count(interfaceBlock.name) > 0)
continue;
size_t dataSize = getBlockInfo(interfaceBlock);
mBlockSizes[interfaceBlock.name] = dataSize;
}
}
size_t UniformBlockInfo::getBlockInfo(const sh::InterfaceBlock &interfaceBlock)
{
ASSERT(interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED);
// define member uniforms
sh::Std140BlockEncoder std140Encoder;
sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
sh::BlockLayoutEncoder *encoder = nullptr;
if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD140)
{
encoder = &std140Encoder;
}
else
{
encoder = &hlslEncoder;
}
sh::GetUniformBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder,
interfaceBlock.isRowMajorLayout, &mBlockLayout);
return encoder->getBlockSize();
}
bool UniformBlockInfo::getBlockSize(const std::string &name,
const std::string &mappedName,
size_t *sizeOut)
{
size_t nameLengthWithoutArrayIndex;
gl::ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex);
auto sizeIter = mBlockSizes.find(baseName);
if (sizeIter == mBlockSizes.end())
{
*sizeOut = 0;
return false;
}
*sizeOut = sizeIter->second;
return true;
};
bool UniformBlockInfo::getBlockMemberInfo(const std::string &name,
const std::string &mappedName,
sh::BlockMemberInfo *infoOut)
{
auto infoIter = mBlockLayout.find(name);
if (infoIter == mBlockLayout.end())
{
*infoOut = sh::BlockMemberInfo::getDefaultBlockInfo();
return false;
}
*infoOut = infoIter->second;
return true;
};
} // anonymous namespace
// D3DUniform Implementation
......@@ -1028,10 +1119,6 @@ void ProgramD3D::save(const gl::Context *context, gl::BinaryOutputStream *stream
stream->writeInt(uniform->registerElement);
}
// Ensure we init the uniform block structure data if we should.
// http://anglebug.com/1637
ensureUniformBlocksInitialized();
stream->writeInt(mD3DUniformBlocks.size());
for (const D3DUniformBlock &uniformBlock : mD3DUniformBlocks)
{
......@@ -1505,8 +1592,6 @@ gl::LinkResult ProgramD3D::link(const gl::Context *context,
infoLog << "Failed to create D3D compute shader.";
return result;
}
initUniformBlockInfo(context, computeShader);
}
else
{
......@@ -1582,11 +1667,10 @@ gl::LinkResult ProgramD3D::link(const gl::Context *context,
infoLog << "Failed to create D3D shaders.";
return result;
}
initUniformBlockInfo(context, vertexShader);
initUniformBlockInfo(context, fragmentShader);
}
linkResources(context, resources);
return true;
}
......@@ -1596,29 +1680,15 @@ GLboolean ProgramD3D::validate(const gl::Caps & /*caps*/, gl::InfoLog * /*infoLo
return GL_TRUE;
}
void ProgramD3D::initUniformBlockInfo(const gl::Context *context, gl::Shader *shader)
void ProgramD3D::initializeUniformBlocks()
{
for (const sh::InterfaceBlock &interfaceBlock : shader->getUniformBlocks(context))
{
if (!interfaceBlock.staticUse && interfaceBlock.layout == sh::BLOCKLAYOUT_PACKED)
continue;
if (mBlockDataSizes.count(interfaceBlock.name) > 0)
continue;
size_t dataSize = getUniformBlockInfo(interfaceBlock);
mBlockDataSizes[interfaceBlock.name] = dataSize;
}
}
void ProgramD3D::ensureUniformBlocksInitialized()
{
// Lazy init.
if (mState.getUniformBlocks().empty() || !mD3DUniformBlocks.empty())
if (mState.getUniformBlocks().empty())
{
return;
}
ASSERT(mD3DUniformBlocks.empty());
// Assign registers and update sizes.
const ShaderD3D *vertexShaderD3D = SafeGetImplAs<ShaderD3D>(mState.getAttachedVertexShader());
const ShaderD3D *fragmentShaderD3D =
......@@ -1731,8 +1801,6 @@ void ProgramD3D::updateUniformBufferCache(const gl::Caps &caps,
return;
}
ensureUniformBlocksInitialized();
mVertexUBOCache.clear();
mFragmentUBOCache.clear();
......@@ -2278,30 +2346,6 @@ void ProgramD3D::setUniformMatrixfvInternal(GLint location,
}
}
size_t ProgramD3D::getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock)
{
ASSERT(interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED);
// define member uniforms
sh::Std140BlockEncoder std140Encoder;
sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false);
sh::BlockLayoutEncoder *encoder = nullptr;
if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD140)
{
encoder = &std140Encoder;
}
else
{
encoder = &hlslEncoder;
}
sh::GetUniformBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder,
interfaceBlock.isRowMajorLayout, &mBlockInfo);
return encoder->getBlockSize();
}
void ProgramD3D::assignAllSamplerRegisters()
{
for (D3DUniform *d3dUniform : mD3DUniforms)
......@@ -2595,40 +2639,6 @@ const D3DUniform *ProgramD3D::getD3DUniformFromLocation(GLint location) const
return mD3DUniforms[mState.getUniformLocations()[location].index];
}
bool ProgramD3D::getUniformBlockSize(const std::string &blockName,
const std::string & /* blockMappedName */,
size_t *sizeOut) const
{
size_t nameLengthWithoutArrayIndex;
gl::ParseArrayIndex(blockName, &nameLengthWithoutArrayIndex);
std::string baseName = blockName.substr(0u, nameLengthWithoutArrayIndex);
auto sizeIter = mBlockDataSizes.find(baseName);
if (sizeIter == mBlockDataSizes.end())
{
*sizeOut = 0;
return false;
}
*sizeOut = sizeIter->second;
return true;
}
bool ProgramD3D::getUniformBlockMemberInfo(const std::string &memberUniformName,
const std::string & /* memberUniformMappedName */,
sh::BlockMemberInfo *memberInfoOut) const
{
auto infoIter = mBlockInfo.find(memberUniformName);
if (infoIter == mBlockInfo.end())
{
*memberInfoOut = sh::BlockMemberInfo::getDefaultBlockInfo();
return false;
}
*memberInfoOut = infoIter->second;
return true;
}
void ProgramD3D::setPathFragmentInputGen(const std::string &inputName,
GLenum genMode,
GLint components,
......@@ -2720,4 +2730,56 @@ void ProgramD3D::updateCachedPixelExecutableIndex()
}
}
void ProgramD3D::linkResources(const gl::Context *context,
const gl::ProgramLinkedResources &resources)
{
UniformBlockInfo uniformBlockInfo;
if (mState.getAttachedVertexShader())
{
uniformBlockInfo.getShaderBlockInfo(context, mState.getAttachedVertexShader());
}
if (mState.getAttachedFragmentShader())
{
uniformBlockInfo.getShaderBlockInfo(context, mState.getAttachedFragmentShader());
}
if (mState.getAttachedComputeShader())
{
uniformBlockInfo.getShaderBlockInfo(context, mState.getAttachedComputeShader());
}
// Gather interface block info.
auto getUniformBlockSize = [&uniformBlockInfo](const std::string &name,
const std::string &mappedName, size_t *sizeOut) {
return uniformBlockInfo.getBlockSize(name, mappedName, sizeOut);
};
auto getUniformBlockMemberInfo = [&uniformBlockInfo](const std::string &name,
const std::string &mappedName,
sh::BlockMemberInfo *infoOut) {
return uniformBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
};
resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo);
initializeUniformBlocks();
// TODO(jiajia.qin@intel.com): Determine correct shader storage block info.
auto getShaderStorageBlockSize = [](const std::string &name, const std::string &mappedName,
size_t *sizeOut) {
*sizeOut = 0;
return true;
};
auto getShaderStorageBlockMemberInfo =
[](const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut) {
*infoOut = sh::BlockMemberInfo::getDefaultBlockInfo();
return true;
};
resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize,
getShaderStorageBlockMemberInfo);
}
} // namespace rx
......@@ -196,12 +196,6 @@ class ProgramD3D : public ProgramImpl
gl::InfoLog &infoLog) override;
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
bool getUniformBlockSize(const std::string &blockName,
const std::string &blockMappedName,
size_t *sizeOut) const override;
bool getUniformBlockMemberInfo(const std::string &memberUniformName,
const std::string &memberUniformMappedName,
sh::BlockMemberInfo *memberInfoOut) const override;
void setPathFragmentInputGen(const std::string &inputName,
GLenum genMode,
GLint components,
......@@ -428,16 +422,15 @@ class ProgramD3D : public ProgramImpl
void initAttribLocationsToD3DSemantic(const gl::Context *context);
void reset();
void ensureUniformBlocksInitialized();
void initUniformBlockInfo(const gl::Context *context, gl::Shader *shader);
size_t getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock);
void initializeUniformBlocks();
void updateCachedInputLayoutFromShader(const gl::Context *context);
void updateCachedOutputLayoutFromShader();
void updateCachedVertexExecutableIndex();
void updateCachedPixelExecutableIndex();
void linkResources(const gl::Context *context, const gl::ProgramLinkedResources &resources);
RendererD3D *mRenderer;
DynamicHLSL *mDynamicHLSL;
......@@ -498,9 +491,6 @@ class ProgramD3D : public ProgramImpl
bool mFragmentUniformsDirty;
bool mComputeUniformsDirty;
std::map<std::string, sh::BlockMemberInfo> mBlockInfo;
std::map<std::string, size_t> mBlockDataSizes;
static unsigned int issueSerial();
static unsigned int mCurrentSerial;
......
......@@ -14,6 +14,7 @@
#include "common/string_utils.h"
#include "common/utilities.h"
#include "libANGLE/Context.h"
#include "libANGLE/ProgramLinkedResources.h"
#include "libANGLE/Uniform.h"
#include "libANGLE/renderer/gl/ContextGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
......@@ -212,6 +213,7 @@ gl::LinkResult ProgramGL::link(const gl::Context *context,
mStateManager->forceUseProgram(mProgramID);
}
linkResources(resources);
postLink();
return true;
......@@ -805,4 +807,35 @@ void ProgramGL::markUnusedUniformLocations(std::vector<gl::VariableLocation> *un
}
}
void ProgramGL::linkResources(const gl::ProgramLinkedResources &resources)
{
// Gather interface block info.
auto getUniformBlockSize = [this](const std::string &name, const std::string &mappedName,
size_t *sizeOut) {
return this->getUniformBlockSize(name, mappedName, sizeOut);
};
auto getUniformBlockMemberInfo = [this](const std::string &name, const std::string &mappedName,
sh::BlockMemberInfo *infoOut) {
return this->getUniformBlockMemberInfo(name, mappedName, infoOut);
};
resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo);
// TODO(jiajia.qin@intel.com): Determine correct shader storage block info.
auto getShaderStorageBlockSize = [](const std::string &name, const std::string &mappedName,
size_t *sizeOut) {
*sizeOut = 0;
return true;
};
auto getShaderStorageBlockMemberInfo =
[](const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut) {
*infoOut = sh::BlockMemberInfo::getDefaultBlockInfo();
return true;
};
resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize,
getShaderStorageBlockMemberInfo);
}
} // namespace rx
......@@ -71,13 +71,6 @@ class ProgramGL : public ProgramImpl
void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
bool getUniformBlockSize(const std::string &blockName,
const std::string &blockMappedName,
size_t *sizeOut) const override;
bool getUniformBlockMemberInfo(const std::string &memberUniformName,
const std::string &memberUniformMappedName,
sh::BlockMemberInfo *memberInfoOut) const override;
void setPathFragmentInputGen(const std::string &inputName,
GLenum genMode,
GLint components,
......@@ -97,6 +90,14 @@ class ProgramGL : public ProgramImpl
void postLink();
void reapplyUBOBindingsIfNeeded(const gl::Context *context);
bool getUniformBlockSize(const std::string &blockName,
const std::string &blockMappedName,
size_t *sizeOut) const;
bool getUniformBlockMemberInfo(const std::string &memberUniformName,
const std::string &memberUniformMappedName,
sh::BlockMemberInfo *memberInfoOut) const;
void linkResources(const gl::ProgramLinkedResources &resources);
// Helper function, makes it simpler to type.
GLint uniLoc(GLint glLocation) const { return mUniformRealLocationMap[glLocation]; }
......
......@@ -183,23 +183,6 @@ void ProgramNULL::setUniformBlockBinding(GLuint uniformBlockIndex, GLuint unifor
{
}
bool ProgramNULL::getUniformBlockSize(const std::string &blockName,
const std::string &blockMappedName,
size_t *sizeOut) const
{
// TODO(geofflang): Compute reasonable sizes?
*sizeOut = 0;
return true;
}
bool ProgramNULL::getUniformBlockMemberInfo(const std::string &memberUniformName,
const std::string &memberUniformMappedName,
sh::BlockMemberInfo *memberInfoOut) const
{
// TODO(geofflang): Compute reasonable values?
return true;
}
void ProgramNULL::setPathFragmentInputGen(const std::string &inputName,
GLenum genMode,
GLint components,
......
......@@ -89,17 +89,6 @@ class ProgramNULL : public ProgramImpl
// TODO: synchronize in syncState when dirty bits exist.
void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
// May only be called after a successful link operation.
// Return false for inactive blocks.
bool getUniformBlockSize(const std::string &blockName,
const std::string &blockMappedName,
size_t *sizeOut) const override;
// May only be called after a successful link operation.
// Returns false for inactive members.
bool getUniformBlockMemberInfo(const std::string &memberUniformName,
const std::string &memberUniformMappedName,
sh::BlockMemberInfo *memberInfoOut) const override;
// CHROMIUM_path_rendering
// Set parameters to control fragment shader input variable interpolation
void setPathFragmentInputGen(const std::string &inputName,
......
......@@ -528,22 +528,6 @@ void ProgramVk::setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformB
UNIMPLEMENTED();
}
bool ProgramVk::getUniformBlockSize(const std::string &blockName,
const std::string &blockMappedName,
size_t *sizeOut) const
{
UNIMPLEMENTED();
return bool();
}
bool ProgramVk::getUniformBlockMemberInfo(const std::string &memberUniformName,
const std::string &memberUniformMappedName,
sh::BlockMemberInfo *memberInfoOut) const
{
UNIMPLEMENTED();
return bool();
}
void ProgramVk::setPathFragmentInputGen(const std::string &inputName,
GLenum genMode,
GLint components,
......
......@@ -94,18 +94,6 @@ class ProgramVk : public ProgramImpl
// TODO: synchronize in syncState when dirty bits exist.
void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
// May only be called after a successful link operation.
// Return false for inactive blocks.
bool getUniformBlockSize(const std::string &blockName,
const std::string &blockMappedName,
size_t *sizeOut) const override;
// May only be called after a successful link operation.
// Returns false for inactive members.
bool getUniformBlockMemberInfo(const std::string &memberUniformName,
const std::string &memberUniformMappedName,
sh::BlockMemberInfo *memberInfoOut) const override;
void setPathFragmentInputGen(const std::string &inputName,
GLenum genMode,
GLint components,
......
......@@ -1156,6 +1156,46 @@ TEST_P(UniformBufferTest, Std140UniformBlockInstanceWithNestedStructsContainingV
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Tests the detaching shaders from the program and using uniform blocks works.
// This covers a bug in ANGLE's D3D back-end.
TEST_P(UniformBufferTest, DetachShaders)
{
GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, mVertexShaderSource);
ASSERT_NE(0u, vertexShader);
GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, mFragmentShaderSource);
ASSERT_NE(0u, fragmentShader);
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
ASSERT_TRUE(LinkAttachedProgram(program));
glDetachShader(program, vertexShader);
glDetachShader(program, fragmentShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glClear(GL_COLOR_BUFFER_BIT);
float floatData[4] = {0.5f, 0.75f, 0.25f, 1.0f};
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 4, floatData, GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
GLint uniformBufferIndex = glGetUniformBlockIndex(mProgram, "uni");
ASSERT_NE(uniformBufferIndex, -1);
glUniformBlockBinding(program, uniformBufferIndex, 0);
drawQuad(program, "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
glDeleteProgram(program);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(UniformBufferTest,
ES3_D3D11(),
......
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