Commit 68694e99 by Gregoire Payen de La Garanderie Committed by Geoff Lang

Add UBO offset support for D3D11.1.

Also fixes the uniform count upper limit in glGetActiveUniformsiv, as well as an assert hit with used but unbound uniform buffer. BUG=angleproject:507 BUG=angleproject:962 Change-Id: I096fe1c9b4f0f398f3a638cd8311278987dfb7dc Reviewed-on: https://chromium-review.googlesource.com/263404Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tested-by: 's avatarGregoire Payen de La Garanderie <Gregory.Payen@imgtec.com>
parent 90a09b56
......@@ -1001,9 +1001,9 @@ Error Program::applyUniforms()
return mProgram->applyUniforms();
}
Error Program::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers, const Caps &caps)
Error Program::applyUniformBuffers(const gl::Data &data)
{
return mProgram->applyUniformBuffers(boundBuffers, caps);
return mProgram->applyUniformBuffers(data, mUniformBlockBindings);
}
void Program::flagForDeletion()
......@@ -1142,6 +1142,11 @@ GLuint Program::getUniformBlockIndex(const std::string &name)
return mProgram->getUniformBlockIndex(name);
}
const UniformBlock *Program::getUniformBlockByIndex(GLuint index) const
{
return mProgram->getUniformBlockByIndex(index);
}
void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
{
mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
......
......@@ -184,7 +184,7 @@ class Program : angle::NonCopyable
void getUniformuiv(GLint location, GLuint *params);
Error applyUniforms();
Error applyUniformBuffers(const std::vector<Buffer*> boundBuffers, const Caps &caps);
Error applyUniformBuffers(const gl::Data &data);
void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const;
void getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const;
......@@ -196,6 +196,8 @@ class Program : angle::NonCopyable
void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding);
GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const;
const UniformBlock *getUniformBlockByIndex(GLuint index) const;
void setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode);
void getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const;
GLsizei getTransformFeedbackVaryingCount() const;
......
......@@ -940,6 +940,20 @@ Buffer *State::getIndexedUniformBuffer(GLuint index) const
return mUniformBuffers[index].get();
}
GLintptr State::getIndexedUniformBufferOffset(GLuint index) const
{
ASSERT(static_cast<size_t>(index) < mUniformBuffers.size());
return mUniformBuffers[index].getOffset();
}
GLsizeiptr State::getIndexedUniformBufferSize(GLuint index) const
{
ASSERT(static_cast<size_t>(index) < mUniformBuffers.size());
return mUniformBuffers[index].getSize();
}
void State::setGenericTransformFeedbackBufferBinding(Buffer *buffer)
{
mGenericTransformFeedbackBuffer.set(buffer);
......
......@@ -200,6 +200,8 @@ class State : angle::NonCopyable
void setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size);
GLuint getIndexedUniformBufferId(GLuint index) const;
Buffer *getIndexedUniformBuffer(GLuint index) const;
GLintptr getIndexedUniformBufferOffset(GLuint index) const;
GLsizeiptr getIndexedUniformBufferSize(GLuint index) const;
// GL_TRANSFORM_FEEDBACK_BUFFER - Both indexed and generic targets
void setGenericTransformFeedbackBufferBinding(Buffer *buffer);
......
......@@ -94,7 +94,7 @@ class ProgramImpl : angle::NonCopyable
const gl::Caps &caps) = 0;
virtual gl::Error applyUniforms() = 0;
virtual gl::Error applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers, const gl::Caps &caps) = 0;
virtual gl::Error applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[]) = 0;
virtual bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader,
unsigned int registerIndex, const gl::Caps &caps) = 0;
......
......@@ -1117,12 +1117,20 @@ gl::Error ProgramD3D::applyUniforms()
return gl::Error(GL_NO_ERROR);
}
gl::Error ProgramD3D::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers, const gl::Caps &caps)
gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[])
{
ASSERT(boundBuffers.size() == mUniformBlocks.size());
GLint vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS];
GLint fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS];
const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
for (unsigned int registerIndex = 0; registerIndex < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; ++registerIndex)
{
vertexUniformBuffers[registerIndex] = -1;
}
for (unsigned int registerIndex = 0; registerIndex < gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS; ++registerIndex)
{
fragmentUniformBuffers[registerIndex] = -1;
}
const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
......@@ -1130,15 +1138,9 @@ gl::Error ProgramD3D::applyUniformBuffers(const std::vector<gl::Buffer*> boundBu
for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
{
gl::UniformBlock *uniformBlock = mUniformBlocks[uniformBlockIndex];
gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
ASSERT(uniformBlock && uniformBuffer);
GLuint blockBinding = uniformBlockBindings[uniformBlockIndex];
if (uniformBuffer->getSize() < uniformBlock->dataSize)
{
// undefined behaviour
return gl::Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small.");
}
ASSERT(uniformBlock);
// Unnecessary to apply an unreferenced standard or shared UBO
if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader())
......@@ -1149,21 +1151,21 @@ gl::Error ProgramD3D::applyUniformBuffers(const std::vector<gl::Buffer*> boundBu
if (uniformBlock->isReferencedByVertexShader())
{
unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
ASSERT(vertexUniformBuffers[registerIndex] == NULL);
ASSERT(registerIndex < caps.maxVertexUniformBlocks);
vertexUniformBuffers[registerIndex] = uniformBuffer;
ASSERT(vertexUniformBuffers[registerIndex] == -1);
ASSERT(registerIndex < data.caps->maxVertexUniformBlocks);
vertexUniformBuffers[registerIndex] = blockBinding;
}
if (uniformBlock->isReferencedByFragmentShader())
{
unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
ASSERT(registerIndex < caps.maxFragmentUniformBlocks);
fragmentUniformBuffers[registerIndex] = uniformBuffer;
ASSERT(fragmentUniformBuffers[registerIndex] == -1);
ASSERT(registerIndex < data.caps->maxFragmentUniformBlocks);
fragmentUniformBuffers[registerIndex] = blockBinding;
}
}
return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
return mRenderer->setUniformBuffers(data, vertexUniformBuffers, fragmentUniformBuffers);
}
bool ProgramD3D::assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader,
......
......@@ -81,7 +81,7 @@ class ProgramD3D : public ProgramImpl
void initializeUniformStorage();
gl::Error applyUniforms();
gl::Error applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers, const gl::Caps &caps);
gl::Error applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[]) override;
bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader,
unsigned int registerIndex, const gl::Caps &caps);
void dirtyAllUniforms();
......
......@@ -133,7 +133,7 @@ gl::Error RendererD3D::drawElements(const gl::Data &data,
return error;
}
error = applyUniformBuffers(data);
error = program->applyUniformBuffers(data);
if (error.isError())
{
return error;
......@@ -203,7 +203,7 @@ gl::Error RendererD3D::drawArrays(const gl::Data &data,
return error;
}
error = applyUniformBuffers(data);
error = program->applyUniformBuffers(data);
if (error.isError())
{
return error;
......@@ -474,32 +474,6 @@ gl::Error RendererD3D::applyTextures(const gl::Data &data)
return gl::Error(GL_NO_ERROR);
}
gl::Error RendererD3D::applyUniformBuffers(const gl::Data &data)
{
gl::Program *program = data.state->getProgram();
std::vector<gl::Buffer*> boundBuffers;
for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
{
GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
if (data.state->getIndexedUniformBuffer(blockBinding)->id() == 0)
{
// undefined behaviour
return gl::Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer.");
}
else
{
gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(blockBinding);
ASSERT(uniformBuffer);
boundBuffers.push_back(uniformBuffer);
}
}
return program->applyUniformBuffers(boundBuffers, *data.caps);
}
bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode)
{
if (drawMode == GL_POINTS)
......
......@@ -105,7 +105,9 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler) = 0;
virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture) = 0;
virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]) = 0;
virtual gl::Error setUniformBuffers(const gl::Data &data,
const GLint vertexUniformBuffers[],
const GLint fragmentUniformBuffers[]) = 0;
virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState) = 0;
virtual gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
......@@ -207,7 +209,6 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
gl::Error applyTextures(const gl::Data &data, gl::SamplerType shaderType,
const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount);
gl::Error applyTextures(const gl::Data &data);
gl::Error applyUniformBuffers(const gl::Data &data);
bool skipDraw(const gl::Data &data, GLenum drawMode);
void markTransformFeedbackUsage(const gl::Data &data);
......
......@@ -143,6 +143,23 @@ ID3D11Resource *GetViewResource(ID3D11View *view)
return resource;
}
void CalculateConstantBufferParams(GLintptr offset, GLsizeiptr size, UINT *outFirstConstant, UINT *outNumConstants)
{
// The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange).
ASSERT(offset % 256 == 0);
// firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must be a multiple of 16 constants.
*outFirstConstant = offset / 16;
// The GL size is not required to be aligned to a 256 bytes boundary.
// Round the size up to a 256 bytes boundary then express the results in constants of 16-bytes.
*outNumConstants = rx::roundUp(size, static_cast<GLsizeiptr>(256)) / 16;
// Since the size is rounded up, firstConstant + numConstants may be bigger than the actual size of the buffer.
// This behaviour is explictly allowed according to the documentation on ID3D11DeviceContext1::PSSetConstantBuffers1
// https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx
}
}
Renderer11::Renderer11(egl::Display *display)
......@@ -168,6 +185,8 @@ Renderer11::Renderer11(egl::Display *display)
mSyncQuery = NULL;
mSupportsConstantBufferOffsets = false;
mD3d11Module = NULL;
mDxgiModule = NULL;
......@@ -502,6 +521,13 @@ void Renderer11::initializeDevice()
const gl::Caps &rendererCaps = getRendererCaps();
if (getDeviceContext1IfSupported())
{
D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options;
mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS));
mSupportsConstantBufferOffsets = (d3d11Options.ConstantBufferOffsetting != FALSE);
}
mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits);
mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits);
......@@ -792,11 +818,23 @@ gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *t
return gl::Error(GL_NO_ERROR);
}
gl::Error Renderer11::setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[])
gl::Error Renderer11::setUniformBuffers(const gl::Data &data,
const GLint vertexUniformBuffers[],
const GLint fragmentUniformBuffers[])
{
for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; uniformBufferIndex++)
for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < data.caps->maxVertexUniformBlocks; uniformBufferIndex++)
{
const gl::Buffer *uniformBuffer = vertexUniformBuffers[uniformBufferIndex];
GLint binding = vertexUniformBuffers[uniformBufferIndex];
if (binding == -1)
{
continue;
}
gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(binding);
GLintptr uniformBufferOffset = data.state->getIndexedUniformBufferOffset(binding);
GLsizeiptr uniformBufferSize = data.state->getIndexedUniformBufferSize(binding);
if (uniformBuffer)
{
Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation());
......@@ -807,18 +845,44 @@ gl::Error Renderer11::setUniformBuffers(const gl::Buffer *vertexUniformBuffers[]
return gl::Error(GL_OUT_OF_MEMORY);
}
if (mCurrentConstantBufferVS[uniformBufferIndex] != bufferStorage->getSerial())
if (mCurrentConstantBufferVS[uniformBufferIndex] != bufferStorage->getSerial() ||
mCurrentConstantBufferVSOffset[uniformBufferIndex] != uniformBufferOffset ||
mCurrentConstantBufferVSSize[uniformBufferIndex] != uniformBufferSize)
{
mDeviceContext->VSSetConstantBuffers(getReservedVertexUniformBuffers() + uniformBufferIndex,
1, &constantBuffer);
if (mSupportsConstantBufferOffsets && uniformBufferSize != 0)
{
UINT firstConstant = 0, numConstants = 0;
CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants);
mDeviceContext1->VSSetConstantBuffers1(getReservedVertexUniformBuffers() + uniformBufferIndex,
1, &constantBuffer, &firstConstant, &numConstants);
}
else
{
ASSERT(uniformBufferOffset == 0);
mDeviceContext->VSSetConstantBuffers(getReservedVertexUniformBuffers() + uniformBufferIndex,
1, &constantBuffer);
}
mCurrentConstantBufferVS[uniformBufferIndex] = bufferStorage->getSerial();
mCurrentConstantBufferVSOffset[uniformBufferIndex] = uniformBufferOffset;
mCurrentConstantBufferVSSize[uniformBufferIndex] = uniformBufferSize;
}
}
}
for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS; uniformBufferIndex++)
for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < data.caps->maxFragmentUniformBlocks; uniformBufferIndex++)
{
const gl::Buffer *uniformBuffer = fragmentUniformBuffers[uniformBufferIndex];
GLint binding = fragmentUniformBuffers[uniformBufferIndex];
if (binding == -1)
{
continue;
}
gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(binding);
GLintptr uniformBufferOffset = data.state->getIndexedUniformBufferOffset(binding);
GLsizeiptr uniformBufferSize = data.state->getIndexedUniformBufferSize(binding);
if (uniformBuffer)
{
Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation());
......@@ -829,11 +893,27 @@ gl::Error Renderer11::setUniformBuffers(const gl::Buffer *vertexUniformBuffers[]
return gl::Error(GL_OUT_OF_MEMORY);
}
if (mCurrentConstantBufferPS[uniformBufferIndex] != bufferStorage->getSerial())
if (mCurrentConstantBufferPS[uniformBufferIndex] != bufferStorage->getSerial() ||
mCurrentConstantBufferPSOffset[uniformBufferIndex] != uniformBufferOffset ||
mCurrentConstantBufferPSSize[uniformBufferIndex] != uniformBufferSize)
{
mDeviceContext->PSSetConstantBuffers(getReservedFragmentUniformBuffers() + uniformBufferIndex,
1, &constantBuffer);
if (mSupportsConstantBufferOffsets && uniformBufferSize != 0)
{
UINT firstConstant = 0, numConstants = 0;
CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants);
mDeviceContext1->PSSetConstantBuffers1(getReservedFragmentUniformBuffers() + uniformBufferIndex,
1, &constantBuffer, &firstConstant, &numConstants);
}
else
{
ASSERT(uniformBufferOffset == 0);
mDeviceContext->PSSetConstantBuffers(getReservedFragmentUniformBuffers() + uniformBufferIndex,
1, &constantBuffer);
}
mCurrentConstantBufferPS[uniformBufferIndex] = bufferStorage->getSerial();
mCurrentConstantBufferPSOffset[uniformBufferIndex] = uniformBufferOffset;
mCurrentConstantBufferPSSize[uniformBufferIndex] = uniformBufferSize;
}
}
}
......@@ -2000,7 +2080,11 @@ void Renderer11::markAllStateDirty()
for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; i++)
{
mCurrentConstantBufferVS[i] = static_cast<unsigned int>(-1);
mCurrentConstantBufferVSOffset[i] = 0;
mCurrentConstantBufferVSSize[i] = 0;
mCurrentConstantBufferPS[i] = static_cast<unsigned int>(-1);
mCurrentConstantBufferPSOffset[i] = 0;
mCurrentConstantBufferPSSize[i] = 0;
}
mCurrentVertexConstantBuffer = NULL;
......@@ -3425,7 +3509,7 @@ GLenum Renderer11::getVertexComponentType(const gl::VertexFormat &vertexFormat)
void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const
{
d3d11_gl::GenerateCaps(mDevice, outCaps, outTextureCaps, outExtensions);
d3d11_gl::GenerateCaps(mDevice, mDeviceContext, outCaps, outTextureCaps, outExtensions);
}
Workarounds Renderer11::generateWorkarounds() const
......
......@@ -87,7 +87,9 @@ class Renderer11 : public RendererD3D
virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler);
virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture);
virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]);
gl::Error setUniformBuffers(const gl::Data &data,
const GLint vertexUniformBuffers[],
const GLint fragmentUniformBuffers[]) override;
virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState);
gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
......@@ -344,12 +346,16 @@ class Renderer11 : public RendererD3D
ID3D11Buffer *mDriverConstantBufferVS;
ID3D11Buffer *mCurrentVertexConstantBuffer;
unsigned int mCurrentConstantBufferVS[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS];
GLintptr mCurrentConstantBufferVSOffset[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS];
GLsizeiptr mCurrentConstantBufferVSSize[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS];
dx_PixelConstants mPixelConstants;
dx_PixelConstants mAppliedPixelConstants;
ID3D11Buffer *mDriverConstantBufferPS;
ID3D11Buffer *mCurrentPixelConstantBuffer;
unsigned int mCurrentConstantBufferPS[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS];
unsigned int mCurrentConstantBufferPS[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS];
GLintptr mCurrentConstantBufferPSOffset[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS];
GLsizeiptr mCurrentConstantBufferPSSize[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS];
ID3D11Buffer *mCurrentGeometryConstantBuffer;
......@@ -374,6 +380,9 @@ class Renderer11 : public RendererD3D
// Sync query
ID3D11Query *mSyncQuery;
// Constant buffer offset support
bool mSupportsConstantBufferOffsets;
ID3D11Device *mDevice;
D3D_FEATURE_LEVEL mFeatureLevel;
ID3D11DeviceContext *mDeviceContext;
......
......@@ -957,7 +957,7 @@ static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL feature
}
}
void GenerateCaps(ID3D11Device *device, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions)
void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions)
{
D3D_FEATURE_LEVEL featureLevel = device->GetFeatureLevel();
......@@ -1054,6 +1054,22 @@ void GenerateCaps(ID3D11Device *device, gl::Caps *caps, gl::TextureCapsMap *text
// Setting a large alignment forces uniform buffers to bind with zero offset
caps->uniformBufferOffsetAlignment = static_cast<GLuint>(std::numeric_limits<GLint>::max());
ID3D11DeviceContext1 *deviceContext1 = d3d11::DynamicCastComObject<ID3D11DeviceContext1>(deviceContext);
if (deviceContext1)
{
D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options;
device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS));
if (d3d11Options.ConstantBufferOffsetting)
{
// With DirectX 11.1, constant buffer offset and size must be a multiple of 16 constants of 16 bytes each.
// https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx
caps->uniformBufferOffsetAlignment = 256;
}
SafeRelease(deviceContext1);
}
caps->maxCombinedUniformBlocks = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks;
caps->maxCombinedVertexUniformComponents = (static_cast<GLint64>(caps->maxVertexUniformBlocks) * static_cast<GLint64>(caps->maxUniformBlockSize / 4)) +
......
......@@ -51,7 +51,7 @@ namespace d3d11_gl
{
GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel);
void GenerateCaps(ID3D11Device *device, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions);
void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions);
}
......
......@@ -860,7 +860,9 @@ gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *te
return gl::Error(GL_NO_ERROR);
}
gl::Error Renderer9::setUniformBuffers(const gl::Buffer* /*vertexUniformBuffers*/[], const gl::Buffer* /*fragmentUniformBuffers*/[])
gl::Error Renderer9::setUniformBuffers(const gl::Data &/*data*/,
const GLint /*vertexUniformBuffers*/[],
const GLint /*fragmentUniformBuffers*/[])
{
// No effect in ES2/D3D9
return gl::Error(GL_NO_ERROR);
......
......@@ -91,7 +91,9 @@ class Renderer9 : public RendererD3D
virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler);
virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture);
virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]);
gl::Error setUniformBuffers(const gl::Data &data,
const GLint vertexUniformBuffers[],
const GLint fragmentUniformBuffers[]) override;
virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState);
gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor,
......
......@@ -367,7 +367,7 @@ gl::Error ProgramGL::applyUniforms()
return gl::Error(GL_INVALID_OPERATION);
}
gl::Error ProgramGL::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers, const gl::Caps &caps)
gl::Error ProgramGL::applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[])
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION);
......
......@@ -79,7 +79,7 @@ class ProgramGL : public ProgramImpl
const gl::Caps &caps) override;
gl::Error applyUniforms() override;
gl::Error applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers, const gl::Caps &caps) override;
gl::Error applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[]) override;
bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader,
unsigned int registerIndex, const gl::Caps &caps) override;
......
......@@ -1436,6 +1436,36 @@ static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsiz
}
}
// Uniform buffer validation
for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
{
const gl::UniformBlock *uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding);
if (!uniformBuffer)
{
// undefined behaviour
context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
return false;
}
size_t uniformBufferSize = state.getIndexedUniformBufferSize(blockBinding);
if (uniformBufferSize == 0)
{
// Bind the whole buffer.
uniformBufferSize = uniformBuffer->getSize();
}
if (uniformBufferSize < uniformBlock->dataSize)
{
// undefined behaviour
context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
return false;
}
}
// No-op if zero count
return (count > 0);
}
......
......@@ -2082,7 +2082,7 @@ void GL_APIENTRY GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const
return;
}
if (uniformCount > 0)
if (uniformCount > programObject->getActiveUniformCount())
{
context->recordError(Error(GL_INVALID_VALUE));
return;
......
......@@ -45,6 +45,7 @@
'<(angle_path)/src/tests/end2end_tests/SwizzleTest.cpp',
'<(angle_path)/src/tests/end2end_tests/TextureTest.cpp',
'<(angle_path)/src/tests/end2end_tests/TransformFeedbackTest.cpp',
'<(angle_path)/src/tests/end2end_tests/UniformBufferTest.cpp',
'<(angle_path)/src/tests/end2end_tests/UniformTest.cpp',
'<(angle_path)/src/tests/end2end_tests/UnpackAlignmentTest.cpp',
'<(angle_path)/src/tests/end2end_tests/UnpackRowLength.cpp',
......
#include "ANGLETest.h"
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_TYPED_TEST_CASE(UniformBufferTest, ES3_D3D11_FL11_1, ES3_D3D11_FL11_1_REFERENCE);
template<typename T>
class UniformBufferTest : public ANGLETest
{
protected:
UniformBufferTest() : ANGLETest(T::GetGlesMajorVersion(), T::GetPlatform())
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
virtual void SetUp()
{
ANGLETest::SetUp();
const std::string vertexShaderSource = SHADER_SOURCE
( #version 300 es\n
in vec4 position;
void main()
{
gl_Position = position;
}
);
const std::string fragmentShaderSource = SHADER_SOURCE
( #version 300 es\n
precision highp float;
uniform uni {
vec4 color;
};
out vec4 fragColor;
void main()
{
fragColor = color;
}
);
mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
ASSERT_NE(mProgram, 0u);
mUniformBufferIndex = glGetUniformBlockIndex(mProgram, "uni");
ASSERT_NE(mUniformBufferIndex, -1);
glGenBuffers(1, &mUniformBuffer);
ASSERT_GL_NO_ERROR();
}
virtual void TearDown()
{
glDeleteBuffers(1, &mUniformBuffer);
glDeleteProgram(mProgram);
ANGLETest::TearDown();
}
GLuint mProgram;
GLint mUniformBufferIndex;
GLuint mUniformBuffer;
};
// Test that using a UBO with a non-zero offset and size actually works.
// The first step of this test renders a color from a UBO with a zero offset.
// The second step renders a color from a UBO with a non-zero offset.
TYPED_TEST(UniformBufferTest, UniformBufferRange)
{
int px = getWindowWidth() / 2;
int py = getWindowHeight() / 2;
// Query the uniform buffer alignment requirement
GLint alignment;
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
GLint64 maxUniformBlockSize;
glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
if (alignment >= maxUniformBlockSize)
{
// ANGLE doesn't implement UBO offsets for this platform.
// Ignore the test case.
return;
}
ASSERT_GL_NO_ERROR();
// Let's create a buffer which contains two vec4.
GLuint vec4Size = 4 * sizeof(float);
GLuint stride = 0;
do
{
stride += alignment;
}
while (stride < vec4Size);
std::vector<char> v(2 * stride);
float *first = reinterpret_cast<float*>(v.data());
float *second = reinterpret_cast<float*>(v.data() + stride);
first[0] = 10.f / 255.f;
first[1] = 20.f / 255.f;
first[2] = 30.f / 255.f;
first[3] = 40.f / 255.f;
second[0] = 110.f / 255.f;
second[1] = 120.f / 255.f;
second[2] = 130.f / 255.f;
second[3] = 140.f / 255.f;
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
// We use on purpose a size which is not a multiple of the alignment.
glBufferData(GL_UNIFORM_BUFFER, stride + vec4Size, v.data(), GL_STATIC_DRAW);
glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
EXPECT_GL_NO_ERROR();
// Bind the first part of the uniform buffer and draw
// Use a size which is smaller than the alignment to check
// to check that this case is handle correctly in the conversion to 11.1.
glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, 0, vec4Size);
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
// Bind the second part of the uniform buffer and draw
// Furthermore the D3D11.1 backend will internally round the vec4Size (16 bytes) to a stride (256 bytes)
// hence it will try to map the range [stride, 2 * stride] which is
// out-of-bound of the buffer bufferSize = stride + vec4Size < 2 * stride.
// Ensure that this behaviour works.
glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, stride, vec4Size);
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 110, 120, 130, 140);
}
// Test uniform block bindings.
TYPED_TEST(UniformBufferTest, UniformBufferBindings)
{
int px = getWindowWidth() / 2;
int py = getWindowHeight() / 2;
ASSERT_GL_NO_ERROR();
// Let's create a buffer which contains one vec4.
GLuint vec4Size = 4 * sizeof(float);
std::vector<char> v(vec4Size);
float *first = reinterpret_cast<float*>(v.data());
first[0] = 10.f / 255.f;
first[1] = 20.f / 255.f;
first[2] = 30.f / 255.f;
first[3] = 40.f / 255.f;
glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
glBufferData(GL_UNIFORM_BUFFER, vec4Size, v.data(), GL_STATIC_DRAW);
EXPECT_GL_NO_ERROR();
// Try to bind the buffer to binding point 2
glUniformBlockBinding(mProgram, mUniformBufferIndex, 2);
glBindBufferBase(GL_UNIFORM_BUFFER, 2, mUniformBuffer);
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
// Clear the framebuffer
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_EQ(px, py, 0, 0, 0, 0);
// Try to bind the buffer to another binding point
glUniformBlockBinding(mProgram, mUniformBufferIndex, 5);
glBindBufferBase(GL_UNIFORM_BUFFER, 5, mUniformBuffer);
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
}
// Test that ANGLE handles used but unbound UBO.
// TODO: A test case shouldn't depend on the error code of an undefined behaviour. Move this to unit tests of the validation layer.
TYPED_TEST(UniformBufferTest, UnboundUniformBuffer)
{
glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
......@@ -29,18 +29,21 @@ DEFINE_ANGLE_TEST_PLATFORM(D3D9, EGL_PLATFORM_ANGLE_TYPE_D3D9_
DEFINE_ANGLE_TEST_PLATFORM(D3D9_REFERENCE, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL11_1, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 11, 1, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL11_0, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 11, 0, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL10_1, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 10, 1, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL10_0, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 10, 0, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL9_3, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 9, 3, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_WARP, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL11_1_WARP, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 11, 1, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL11_0_WARP, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 11, 0, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL10_1_WARP, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 10, 1, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL10_0_WARP, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 10, 0, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL9_3_WARP, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 9, 3, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_REFERENCE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL11_1_REFERENCE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 11, 1, EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL11_0_REFERENCE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 11, 0, EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL10_1_REFERENCE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 10, 1, EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE);
DEFINE_ANGLE_TEST_PLATFORM(D3D11_FL10_0_REFERENCE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, 10, 0, EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE);
......@@ -92,6 +95,7 @@ typedef TestFixture<2, OPENGL> ES2_OPENGL;
typedef TestFixture<2, OPENGLES> ES2_OPENGLES;
typedef TestFixture<3, D3D11> ES3_D3D11;
typedef TestFixture<3, D3D11_FL11_1> ES3_D3D11_FL11_1;
typedef TestFixture<3, D3D11_FL11_0> ES3_D3D11_FL11_0;
typedef TestFixture<3, D3D11_FL10_1> ES3_D3D11_FL10_1;
typedef TestFixture<3, D3D11_FL10_0> ES3_D3D11_FL10_0;
......@@ -102,6 +106,7 @@ typedef TestFixture<3, D3D11_FL10_1_WARP> ES3_D3D11_FL10_1_WARP;
typedef TestFixture<3, D3D11_FL10_0_WARP> ES3_D3D11_FL10_0_WARP;
typedef TestFixture<3, D3D11_REFERENCE> ES3_D3D11_REFERENCE;
typedef TestFixture<3, D3D11_FL11_1_REFERENCE> ES3_D3D11_FL11_1_REFERENCE;
typedef TestFixture<3, D3D11_FL11_0_REFERENCE> ES3_D3D11_FL11_0_REFERENCE;
typedef TestFixture<3, D3D11_FL10_1_REFERENCE> ES3_D3D11_FL10_1_REFERENCE;
typedef TestFixture<3, D3D11_FL10_0_REFERENCE> ES3_D3D11_FL10_0_REFERENCE;
......
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