Commit d779f6a9 by Jamie Madill Committed by Commit Bot

D3D11: Refactor draw call functions.

This allow for better code reuse for the Indirect draw calls. It also cleans up the InputLayoutCache to be only responsible for caching input layouts, and moves the logic for maintaining state into StateManager11. Bug: angleproject:2389 Change-Id: I84aae164bf1b94a394743cf58650adfdcfc2c17a Reviewed-on: https://chromium-review.googlesource.com/948796 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent a07b4213
......@@ -143,6 +143,13 @@ bool DrawCallParams::isDrawElements() const
return (mType != GL_NONE);
}
bool DrawCallParams::isDrawIndirect() const
{
// This is a bit of a hack - it's quite possible for a direct call to have a zero count, but we
// assume these calls are filtered out before they make it to this code.
return (mIndexCount == 0 && mVertexCount == 0);
}
Error DrawCallParams::ensureIndexRangeResolved(const Context *context) const
{
if (mIndexRange.valid() || !isDrawElements())
......
......@@ -108,6 +108,7 @@ class DrawCallParams final : angle::NonCopyable
Error ensureIndexRangeResolved(const Context *context) const;
bool isDrawElements() const;
bool isDrawIndirect() const;
// ensureIndexRangeResolved must be called first.
const IndexRange &getIndexRange() const;
......
......@@ -308,6 +308,13 @@ gl::Error GetIndexTranslationDestType(const gl::Context *context,
// see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
if (usePrimitiveRestartWorkaround)
{
// Conservatively assume we need to translate the indices for draw indirect.
if (drawCallParams.isDrawIndirect())
{
*destTypeOut = GL_UNSIGNED_INT;
return gl::NoError();
}
ANGLE_TRY(drawCallParams.ensureIndexRangeResolved(context));
const gl::IndexRange &indexRange = drawCallParams.getIndexRange();
if (indexRange.end == gl::GetPrimitiveRestartIndex(drawCallParams.type()))
......
......@@ -21,15 +21,81 @@
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
#include "libANGLE/renderer/d3d/d3d11/Fence11.h"
#include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h"
#include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h"
#include "libANGLE/renderer/d3d/d3d11/ProgramPipeline11.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/StateManager11.h"
#include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.h"
#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace rx
{
namespace
{
bool DrawCallHasStreamingVertexArrays(const gl::Context *context, GLenum mode)
{
const gl::State &glState = context->getGLState();
const gl::VertexArray *vertexArray = glState.getVertexArray();
VertexArray11 *vertexArray11 = GetImplAs<VertexArray11>(vertexArray);
// Direct drawing doesn't support dynamic attribute storage since it needs the first and count
// to translate when applyVertexBuffer. GL_LINE_LOOP and GL_TRIANGLE_FAN are not supported
// either since we need to simulate them in D3D.
if (vertexArray11->hasActiveDynamicAttrib(context) || mode == GL_LINE_LOOP ||
mode == GL_TRIANGLE_FAN)
{
return true;
}
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
if (InstancedPointSpritesActive(programD3D, mode))
{
return true;
}
return false;
}
bool DrawCallHasStreamingElementArray(const gl::Context *context, GLenum srcType)
{
const gl::State &glState = context->getGLState();
gl::Buffer *elementArrayBuffer = glState.getVertexArray()->getElementArrayBuffer().get();
bool primitiveRestartWorkaround =
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), srcType);
const GLenum dstType = (srcType == GL_UNSIGNED_INT || primitiveRestartWorkaround)
? GL_UNSIGNED_INT
: GL_UNSIGNED_SHORT;
// Not clear where the offset comes from here.
bool needsTranslation = false;
ClassifyIndexStorage(glState, elementArrayBuffer, srcType, dstType, 0, &needsTranslation);
return needsTranslation;
}
template <typename IndirectBufferT>
gl::Error ReadbackIndirectBuffer(const gl::Context *context,
const void *indirect,
const IndirectBufferT **bufferPtrOut)
{
const gl::State &glState = context->getGLState();
gl::Buffer *drawIndirectBuffer = glState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
ASSERT(drawIndirectBuffer);
Buffer11 *storage = GetImplAs<Buffer11>(drawIndirectBuffer);
uintptr_t offset = reinterpret_cast<uintptr_t>(indirect);
const uint8_t *bufferData = nullptr;
ANGLE_TRY(storage->getData(context, &bufferData));
ASSERT(bufferData);
*bufferPtrOut = reinterpret_cast<const IndirectBufferT *>(bufferData + offset);
return gl::NoError();
}
} // anonymous namespace
Context11::Context11(const gl::ContextState &state, Renderer11 *renderer)
: ContextImpl(state), mRenderer(renderer)
{
......@@ -158,8 +224,10 @@ gl::Error Context11::finish(const gl::Context *context)
gl::Error Context11::drawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count)
{
ANGLE_TRY(prepareForDrawCall(context, mode));
return mRenderer->drawArrays(context, mode, first, count, 0);
const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>();
ASSERT(!drawCallParams.isDrawElements() && !drawCallParams.isDrawIndirect());
ANGLE_TRY(prepareForDrawCall(context, drawCallParams));
return mRenderer->drawArrays(context, drawCallParams);
}
gl::Error Context11::drawArraysInstanced(const gl::Context *context,
......@@ -168,8 +236,10 @@ gl::Error Context11::drawArraysInstanced(const gl::Context *context,
GLsizei count,
GLsizei instanceCount)
{
ANGLE_TRY(prepareForDrawCall(context, mode));
return mRenderer->drawArrays(context, mode, first, count, instanceCount);
const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>();
ASSERT(!drawCallParams.isDrawElements() && !drawCallParams.isDrawIndirect());
ANGLE_TRY(prepareForDrawCall(context, drawCallParams));
return mRenderer->drawArrays(context, drawCallParams);
}
gl::Error Context11::drawElements(const gl::Context *context,
......@@ -178,8 +248,10 @@ gl::Error Context11::drawElements(const gl::Context *context,
GLenum type,
const void *indices)
{
ANGLE_TRY(prepareForDrawCall(context, mode));
return mRenderer->drawElements(context, mode, count, type, indices, 0);
const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>();
ASSERT(drawCallParams.isDrawElements() && !drawCallParams.isDrawIndirect());
ANGLE_TRY(prepareForDrawCall(context, drawCallParams));
return mRenderer->drawElements(context, drawCallParams);
}
gl::Error Context11::drawElementsInstanced(const gl::Context *context,
......@@ -189,8 +261,10 @@ gl::Error Context11::drawElementsInstanced(const gl::Context *context,
const void *indices,
GLsizei instances)
{
ANGLE_TRY(prepareForDrawCall(context, mode));
return mRenderer->drawElements(context, mode, count, type, indices, instances);
const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>();
ASSERT(drawCallParams.isDrawElements() && !drawCallParams.isDrawIndirect());
ANGLE_TRY(prepareForDrawCall(context, drawCallParams));
return mRenderer->drawElements(context, drawCallParams);
}
gl::Error Context11::drawRangeElements(const gl::Context *context,
......@@ -201,16 +275,32 @@ gl::Error Context11::drawRangeElements(const gl::Context *context,
GLenum type,
const void *indices)
{
ANGLE_TRY(prepareForDrawCall(context, mode));
return mRenderer->drawElements(context, mode, count, type, indices, 0);
const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>();
ASSERT(drawCallParams.isDrawElements() && !drawCallParams.isDrawIndirect());
ANGLE_TRY(prepareForDrawCall(context, drawCallParams));
return mRenderer->drawElements(context, drawCallParams);
}
gl::Error Context11::drawArraysIndirect(const gl::Context *context,
GLenum mode,
const void *indirect)
{
ANGLE_TRY(prepareForDrawCall(context, mode));
return mRenderer->drawArraysIndirect(context, mode, indirect);
if (DrawCallHasStreamingVertexArrays(context, mode))
{
const gl::DrawArraysIndirectCommand *cmd = nullptr;
ANGLE_TRY(ReadbackIndirectBuffer(context, indirect, &cmd));
gl::DrawCallParams drawCallParams(mode, cmd->first, cmd->count, cmd->instanceCount);
ANGLE_TRY(prepareForDrawCall(context, drawCallParams));
return mRenderer->drawArrays(context, drawCallParams);
}
else
{
const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>();
ASSERT(!drawCallParams.isDrawElements() && drawCallParams.isDrawIndirect());
ANGLE_TRY(prepareForDrawCall(context, drawCallParams));
return mRenderer->drawArraysIndirect(context, drawCallParams);
}
}
gl::Error Context11::drawElementsIndirect(const gl::Context *context,
......@@ -218,8 +308,34 @@ gl::Error Context11::drawElementsIndirect(const gl::Context *context,
GLenum type,
const void *indirect)
{
ANGLE_TRY(prepareForDrawCall(context, mode));
return mRenderer->drawElementsIndirect(context, mode, type, indirect);
if (DrawCallHasStreamingVertexArrays(context, mode) ||
DrawCallHasStreamingElementArray(context, type))
{
const gl::DrawElementsIndirectCommand *cmd = nullptr;
ANGLE_TRY(ReadbackIndirectBuffer(context, indirect, &cmd));
const gl::Type &typeInfo = gl::GetTypeInfo(type);
const void *indices = reinterpret_cast<const void *>(
static_cast<uintptr_t>(cmd->firstIndex * typeInfo.bytes));
gl::DrawCallParams drawCallParams(mode, cmd->count, type, indices, cmd->baseVertex,
cmd->primCount);
// We must explicitly resolve the index range for the slow-path indirect drawElements to
// make sure we are using the correct 'baseVertex'. This parameter does not exist for the
// direct drawElements.
ANGLE_TRY(drawCallParams.ensureIndexRangeResolved(context));
ANGLE_TRY(prepareForDrawCall(context, drawCallParams));
return mRenderer->drawElements(context, drawCallParams);
}
else
{
const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>();
ASSERT(drawCallParams.isDrawElements() && drawCallParams.isDrawIndirect());
ANGLE_TRY(prepareForDrawCall(context, drawCallParams));
return mRenderer->drawElementsIndirect(context, drawCallParams);
}
}
GLenum Context11::getResetStatus()
......@@ -401,9 +517,10 @@ gl::Error Context11::triggerDrawCallProgramRecompilation(const gl::Context *cont
return gl::NoError();
}
gl::Error Context11::prepareForDrawCall(const gl::Context *context, GLenum drawMode)
gl::Error Context11::prepareForDrawCall(const gl::Context *context,
const gl::DrawCallParams &drawCallParams)
{
ANGLE_TRY(mRenderer->getStateManager()->updateState(context, drawMode));
ANGLE_TRY(mRenderer->getStateManager()->updateState(context, drawCallParams));
return gl::NoError();
}
......
......@@ -149,7 +149,8 @@ class Context11 : public ContextImpl
gl::Error triggerDrawCallProgramRecompilation(const gl::Context *context, GLenum drawMode);
private:
gl::Error prepareForDrawCall(const gl::Context *context, GLenum drawMode);
gl::Error prepareForDrawCall(const gl::Context *context,
const gl::DrawCallParams &drawCallParams);
Renderer11 *mRenderer;
};
......
......@@ -23,7 +23,6 @@
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h"
#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"
#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
namespace rx
......@@ -32,11 +31,6 @@ namespace rx
namespace
{
size_t GetReservedBufferCount(bool usesPointSpriteEmulation)
{
return usesPointSpriteEmulation ? 1 : 0;
}
GLenum GetGLSLAttributeType(const std::vector<sh::Attribute> &shaderAttributes, size_t index)
{
// Count matrices differently
......@@ -106,8 +100,7 @@ bool PackedAttributeLayout::operator==(const PackedAttributeLayout &other) const
(attributeData == other.attributeData);
}
InputLayoutCache::InputLayoutCache()
: mLayoutCache(kDefaultCacheSize * 2), mPointSpriteVertexBuffer(), mPointSpriteIndexBuffer()
InputLayoutCache::InputLayoutCache() : mLayoutCache(kDefaultCacheSize * 2)
{
}
......@@ -118,197 +111,15 @@ InputLayoutCache::~InputLayoutCache()
void InputLayoutCache::clear()
{
mLayoutCache.Clear();
mPointSpriteVertexBuffer.reset();
mPointSpriteIndexBuffer.reset();
}
gl::Error InputLayoutCache::applyVertexBuffers(
const gl::Context *context,
const std::vector<const TranslatedAttribute *> &currentAttributes,
GLenum mode,
GLint start,
bool isIndexedRendering)
{
Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
const gl::State &state = context->getGLState();
auto *stateManager = renderer->getStateManager();
gl::Program *program = state.getProgram();
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
bool programUsesInstancedPointSprites = programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation();
bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS);
// Note that if we use instance emulation, we reserve the first buffer slot.
size_t reservedBuffers = GetReservedBufferCount(programUsesInstancedPointSprites);
for (size_t attribIndex = 0; attribIndex < (gl::MAX_VERTEX_ATTRIBS - reservedBuffers);
++attribIndex)
{
ID3D11Buffer *buffer = nullptr;
UINT vertexStride = 0;
UINT vertexOffset = 0;
if (attribIndex < currentAttributes.size())
{
const auto &attrib = *currentAttributes[attribIndex];
Buffer11 *bufferStorage = attrib.storage ? GetAs<Buffer11>(attrib.storage) : nullptr;
// If indexed pointsprite emulation is active, then we need to take a less efficent code path.
// Emulated indexed pointsprite rendering requires that the vertex buffers match exactly to
// the indices passed by the caller. This could expand or shrink the vertex buffer depending
// on the number of points indicated by the index list or how many duplicates are found on the index list.
if (bufferStorage == nullptr)
{
ASSERT(attrib.vertexBuffer.get());
buffer = GetAs<VertexBuffer11>(attrib.vertexBuffer.get())->getBuffer().get();
}
else if (instancedPointSpritesActive && isIndexedRendering)
{
VertexArray11 *vao11 = GetImplAs<VertexArray11>(state.getVertexArray());
ASSERT(vao11->isCachedIndexInfoValid());
TranslatedIndexData *indexInfo = vao11->getCachedIndexInfo();
if (indexInfo->srcIndexData.srcBuffer != nullptr)
{
const uint8_t *bufferData = nullptr;
ANGLE_TRY(indexInfo->srcIndexData.srcBuffer->getData(context, &bufferData));
ASSERT(bufferData != nullptr);
ptrdiff_t offset =
reinterpret_cast<ptrdiff_t>(indexInfo->srcIndexData.srcIndices);
indexInfo->srcIndexData.srcBuffer = nullptr;
indexInfo->srcIndexData.srcIndices = bufferData + offset;
}
ANGLE_TRY_RESULT(bufferStorage->getEmulatedIndexedBuffer(
context, &indexInfo->srcIndexData, attrib, start),
buffer);
}
else
{
ANGLE_TRY_RESULT(
bufferStorage->getBuffer(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK),
buffer);
}
vertexStride = attrib.stride;
ANGLE_TRY_RESULT(attrib.computeOffset(start), vertexOffset);
}
size_t bufferIndex = reservedBuffers + attribIndex;
stateManager->queueVertexBufferChange(bufferIndex, buffer, vertexStride, vertexOffset);
}
// Instanced PointSprite emulation requires two additional ID3D11Buffers. A vertex buffer needs
// to be created and added to the list of current buffers, strides and offsets collections.
// This buffer contains the vertices for a single PointSprite quad.
// An index buffer also needs to be created and applied because rendering instanced data on
// D3D11 FL9_3 requires DrawIndexedInstanced() to be used. Shaders that contain gl_PointSize and
// used without the GL_POINTS rendering mode require a vertex buffer because some drivers cannot
// handle missing vertex data and will TDR the system.
if (programUsesInstancedPointSprites)
{
const UINT pointSpriteVertexStride = sizeof(float) * 5;
if (!mPointSpriteVertexBuffer.valid())
{
static const float pointSpriteVertices[] =
{
// Position // TexCoord
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f, 0.0f,
};
D3D11_SUBRESOURCE_DATA vertexBufferData = { pointSpriteVertices, 0, 0 };
D3D11_BUFFER_DESC vertexBufferDesc;
vertexBufferDesc.ByteWidth = sizeof(pointSpriteVertices);
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;
vertexBufferDesc.StructureByteStride = 0;
ANGLE_TRY(renderer->allocateResource(vertexBufferDesc, &vertexBufferData,
&mPointSpriteVertexBuffer));
}
// Set the stride to 0 if GL_POINTS mode is not being used to instruct the driver to avoid
// indexing into the vertex buffer.
UINT stride = instancedPointSpritesActive ? pointSpriteVertexStride : 0;
stateManager->queueVertexBufferChange(0, mPointSpriteVertexBuffer.get(), stride, 0);
if (!mPointSpriteIndexBuffer.valid())
{
// Create an index buffer and set it for pointsprite rendering
static const unsigned short pointSpriteIndices[] =
{
0, 1, 2, 3, 4, 5,
};
D3D11_SUBRESOURCE_DATA indexBufferData = { pointSpriteIndices, 0, 0 };
D3D11_BUFFER_DESC indexBufferDesc;
indexBufferDesc.ByteWidth = sizeof(pointSpriteIndices);
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;
indexBufferDesc.StructureByteStride = 0;
ANGLE_TRY(renderer->allocateResource(indexBufferDesc, &indexBufferData,
&mPointSpriteIndexBuffer));
}
if (instancedPointSpritesActive)
{
// The index buffer is applied here because Instanced PointSprite emulation uses the a
// non-indexed rendering path in ANGLE (DrawArrays). This means that applyIndexBuffer()
// on the renderer will not be called and setting this buffer here ensures that the
// rendering path will contain the correct index buffers.
stateManager->setIndexBuffer(mPointSpriteIndexBuffer.get(), DXGI_FORMAT_R16_UINT, 0);
}
}
stateManager->applyVertexBufferChanges();
return gl::NoError();
}
gl::Error InputLayoutCache::updateVertexOffsetsForPointSpritesEmulation(
Renderer11 *renderer,
const std::vector<const TranslatedAttribute *> &currentAttributes,
GLint startVertex,
GLsizei emulatedInstanceId)
{
auto *stateManager = renderer->getStateManager();
size_t reservedBuffers = GetReservedBufferCount(true);
for (size_t attribIndex = 0; attribIndex < currentAttributes.size(); ++attribIndex)
{
const auto &attrib = *currentAttributes[attribIndex];
size_t bufferIndex = reservedBuffers + attribIndex;
if (attrib.divisor > 0)
{
unsigned int offset = 0;
ANGLE_TRY_RESULT(attrib.computeOffset(startVertex), offset);
offset += (attrib.stride * (emulatedInstanceId / attrib.divisor));
stateManager->queueVertexOffsetChange(bufferIndex, offset);
}
}
stateManager->applyVertexBufferChanges();
return gl::NoError();
}
gl::Error InputLayoutCache::updateInputLayout(
gl::Error InputLayoutCache::getInputLayout(
Renderer11 *renderer,
const gl::State &state,
const std::vector<const TranslatedAttribute *> &currentAttributes,
const AttribIndexArray &sortedSemanticIndices,
const gl::DrawCallParams &drawCallParams)
const gl::DrawCallParams &drawCallParams,
const d3d11::InputLayout **inputLayoutOut)
{
gl::Program *program = state.getProgram();
const auto &shaderAttributes = program->getAttributes();
......@@ -358,13 +169,12 @@ gl::Error InputLayoutCache::updateInputLayout(
binding.getDivisor() * divisorMultiplier);
}
const d3d11::InputLayout *inputLayout = nullptr;
if (layout.numAttributes > 0 || layout.flags != 0)
{
auto it = mLayoutCache.Get(layout);
if (it != mLayoutCache.end())
{
inputLayout = &it->second;
*inputLayoutOut = &it->second;
}
else
{
......@@ -375,11 +185,10 @@ gl::Error InputLayoutCache::updateInputLayout(
drawCallParams, &newInputLayout));
auto insertIt = mLayoutCache.Put(layout, std::move(newInputLayout));
inputLayout = &insertIt->second;
*inputLayoutOut = &insertIt->second;
}
}
renderer->getStateManager()->setInputLayout(inputLayout);
return gl::NoError();
}
......
......@@ -85,26 +85,15 @@ class InputLayoutCache : angle::NonCopyable
void clear();
gl::Error applyVertexBuffers(const gl::Context *context,
const std::vector<const TranslatedAttribute *> &currentAttributes,
GLenum mode,
GLint start,
bool isIndexedRendering);
gl::Error updateVertexOffsetsForPointSpritesEmulation(
Renderer11 *renderer,
const std::vector<const TranslatedAttribute *> &currentAttributes,
GLint startVertex,
GLsizei emulatedInstanceId);
// Useful for testing
void setCacheSize(size_t newCacheSize);
gl::Error updateInputLayout(Renderer11 *renderer,
const gl::State &state,
const std::vector<const TranslatedAttribute *> &currentAttributes,
const AttribIndexArray &sortedSemanticIndices,
const gl::DrawCallParams &drawCallParams);
gl::Error getInputLayout(Renderer11 *renderer,
const gl::State &state,
const std::vector<const TranslatedAttribute *> &currentAttributes,
const AttribIndexArray &sortedSemanticIndices,
const gl::DrawCallParams &drawCallParams,
const d3d11::InputLayout **inputLayoutOut);
private:
gl::Error createInputLayout(Renderer11 *renderer,
......@@ -122,9 +111,6 @@ class InputLayoutCache : angle::NonCopyable
using LayoutCache = angle::base::HashingMRUCache<PackedAttributeLayout, d3d11::InputLayout>;
LayoutCache mLayoutCache;
d3d11::Buffer mPointSpriteVertexBuffer;
d3d11::Buffer mPointSpriteIndexBuffer;
};
} // namespace rx
......
......@@ -352,29 +352,6 @@ void GetTriFanIndices(const void *indices,
}
}
bool DrawCallNeedsTranslation(const gl::Context *context, GLenum mode)
{
const auto &glState = context->getGLState();
const gl::VertexArray *vertexArray = glState.getVertexArray();
VertexArray11 *vertexArray11 = GetImplAs<VertexArray11>(vertexArray);
// Direct drawing doesn't support dynamic attribute storage since it needs the first and count
// to translate when applyVertexBuffer. GL_LINE_LOOP and GL_TRIANGLE_FAN are not supported
// either since we need to simulate them in D3D.
if (vertexArray11->hasActiveDynamicAttrib(context) || mode == GL_LINE_LOOP ||
mode == GL_TRIANGLE_FAN)
{
return true;
}
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
if (InstancedPointSpritesActive(programD3D, mode))
{
return true;
}
return false;
}
bool IsArrayRTV(ID3D11RenderTargetView *rtv)
{
D3D11_RENDER_TARGET_VIEW_DESC desc;
......@@ -1497,33 +1474,29 @@ bool Renderer11::applyPrimitiveType(const gl::State &glState, GLenum mode, GLsiz
return count >= minCount;
}
gl::Error Renderer11::drawArrays(const gl::Context *context,
GLenum mode,
GLint startVertex,
GLsizei count,
GLsizei instances)
gl::Error Renderer11::drawArrays(const gl::Context *context, const gl::DrawCallParams &params)
{
const auto &glState = context->getGLState();
if (!applyPrimitiveType(glState, mode, count))
if (!applyPrimitiveType(glState, params.mode(), params.vertexCount()))
{
return gl::NoError();
}
const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>();
ANGLE_TRY(mStateManager.applyVertexBuffer(context, drawCallParams));
if (glState.isTransformFeedbackActiveUnpaused())
{
ANGLE_TRY(markTransformFeedbackUsage(context));
}
ANGLE_TRY(mStateManager.applyVertexBuffer(context, params));
gl::Program *program = glState.getProgram();
ASSERT(program != nullptr);
GLsizei adjustedInstanceCount = GetAdjustedInstanceCount(program, instances);
GLsizei adjustedInstanceCount = GetAdjustedInstanceCount(program, params.instances());
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
if (programD3D->usesGeometryShader(mode) && glState.isTransformFeedbackActiveUnpaused())
if (programD3D->usesGeometryShader(params.mode()) &&
glState.isTransformFeedbackActiveUnpaused())
{
// Since we use a geometry if-and-only-if we rewrite vertex streams, transform feedback
// won't get the correct output. To work around this, draw with *only* the stream out
......@@ -1533,11 +1506,11 @@ gl::Error Renderer11::drawArrays(const gl::Context *context,
if (adjustedInstanceCount > 0)
{
mDeviceContext->DrawInstanced(count, adjustedInstanceCount, 0, 0);
mDeviceContext->DrawInstanced(params.vertexCount(), adjustedInstanceCount, 0, 0);
}
else
{
mDeviceContext->Draw(count, 0);
mDeviceContext->Draw(params.vertexCount(), 0);
}
rx::ShaderExecutableD3D *pixelExe = nullptr;
......@@ -1553,45 +1526,47 @@ gl::Error Renderer11::drawArrays(const gl::Context *context,
// Retrieve the geometry shader.
rx::ShaderExecutableD3D *geometryExe = nullptr;
ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(context, mode, &geometryExe,
nullptr));
ANGLE_TRY(programD3D->getGeometryExecutableForPrimitiveType(context, params.mode(),
&geometryExe, nullptr));
mStateManager.setGeometryShader(
&GetAs<ShaderExecutable11>(geometryExe)->getGeometryShader());
if (adjustedInstanceCount > 0)
{
mDeviceContext->DrawInstanced(count, adjustedInstanceCount, 0, 0);
mDeviceContext->DrawInstanced(params.vertexCount(), adjustedInstanceCount, 0, 0);
}
else
{
mDeviceContext->Draw(count, 0);
mDeviceContext->Draw(params.vertexCount(), 0);
}
return gl::NoError();
}
if (mode == GL_LINE_LOOP)
if (params.mode() == GL_LINE_LOOP)
{
return drawLineLoop(context, count, GL_NONE, nullptr, 0, adjustedInstanceCount);
return drawLineLoop(context, params.vertexCount(), GL_NONE, nullptr, 0,
adjustedInstanceCount);
}
if (mode == GL_TRIANGLE_FAN)
if (params.mode() == GL_TRIANGLE_FAN)
{
return drawTriangleFan(context, count, GL_NONE, nullptr, 0, adjustedInstanceCount);
return drawTriangleFan(context, params.vertexCount(), GL_NONE, nullptr, 0,
adjustedInstanceCount);
}
bool useInstancedPointSpriteEmulation =
programD3D->usesPointSize() && getWorkarounds().useInstancedPointSpriteEmulation;
if (mode != GL_POINTS || !useInstancedPointSpriteEmulation)
if (params.mode() != GL_POINTS || !useInstancedPointSpriteEmulation)
{
if (adjustedInstanceCount == 0)
{
mDeviceContext->Draw(count, 0);
mDeviceContext->Draw(params.vertexCount(), 0);
}
else
{
mDeviceContext->DrawInstanced(count, adjustedInstanceCount, 0, 0);
mDeviceContext->DrawInstanced(params.vertexCount(), adjustedInstanceCount, 0, 0);
}
return gl::NoError();
}
......@@ -1604,7 +1579,7 @@ gl::Error Renderer11::drawArrays(const gl::Context *context,
// D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced is called instead.
if (adjustedInstanceCount == 0)
{
mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
mDeviceContext->DrawIndexedInstanced(6, params.vertexCount(), 0, 0, 0);
return gl::NoError();
}
......@@ -1613,10 +1588,11 @@ gl::Error Renderer11::drawArrays(const gl::Context *context,
// batch of points. An offset into the instanced data buffer is calculated and applied on each
// iteration to ensure all instances are rendered correctly. Each instance being rendered
// requires the inputlayout cache to reapply buffers and offsets.
for (GLsizei i = 0; i < instances; i++)
for (GLsizei i = 0; i < params.instances(); i++)
{
ANGLE_TRY(mStateManager.updateVertexOffsetsForPointSpritesEmulation(startVertex, i));
mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
ANGLE_TRY(
mStateManager.updateVertexOffsetsForPointSpritesEmulation(params.baseVertex(), i));
mDeviceContext->DrawIndexedInstanced(6, params.vertexCount(), 0, 0, 0);
}
// This required by updateVertexOffsets... above but is outside of the loop for speed.
......@@ -1624,16 +1600,11 @@ gl::Error Renderer11::drawArrays(const gl::Context *context,
return gl::NoError();
}
gl::Error Renderer11::drawElements(const gl::Context *context,
GLenum mode,
GLsizei count,
GLenum type,
const void *indices,
GLsizei instances)
gl::Error Renderer11::drawElements(const gl::Context *context, const gl::DrawCallParams &params)
{
const auto &glState = context->getGLState();
if (!applyPrimitiveType(glState, mode, count))
if (!applyPrimitiveType(glState, params.mode(), params.indexCount()))
{
return gl::NoError();
}
......@@ -1642,42 +1613,44 @@ gl::Error Renderer11::drawElements(const gl::Context *context,
// API validation layer.
ASSERT(!glState.isTransformFeedbackActiveUnpaused());
const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>();
bool usePrimitiveRestartWorkaround =
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type);
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), params.type());
ANGLE_TRY(
mStateManager.applyIndexBuffer(context, drawCallParams, usePrimitiveRestartWorkaround));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, drawCallParams));
ANGLE_TRY(mStateManager.applyIndexBuffer(context, params, usePrimitiveRestartWorkaround));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, params));
int startVertex = static_cast<int>(drawCallParams.firstVertex());
// If this draw call is coming from an indirect call, offset by the indirect call's base vertex.
// No base vertex parameter exists for a normal drawElements, so params.baseVertex will be zero.
int startVertex = static_cast<int>(params.firstVertex() - params.baseVertex());
int baseVertex = -startVertex;
const gl::Program *program = glState.getProgram();
GLsizei adjustedInstanceCount = GetAdjustedInstanceCount(program, instances);
GLsizei adjustedInstanceCount = GetAdjustedInstanceCount(program, params.instances());
if (mode == GL_LINE_LOOP)
if (params.mode() == GL_LINE_LOOP)
{
return drawLineLoop(context, count, type, indices, baseVertex, adjustedInstanceCount);
return drawLineLoop(context, params.indexCount(), params.type(), params.indices(),
baseVertex, adjustedInstanceCount);
}
if (mode == GL_TRIANGLE_FAN)
if (params.mode() == GL_TRIANGLE_FAN)
{
return drawTriangleFan(context, count, type, indices, baseVertex, adjustedInstanceCount);
return drawTriangleFan(context, params.indexCount(), params.type(), params.indices(),
baseVertex, adjustedInstanceCount);
}
const ProgramD3D *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
if (mode != GL_POINTS || !programD3D->usesInstancedPointSpriteEmulation())
if (params.mode() != GL_POINTS || !programD3D->usesInstancedPointSpriteEmulation())
{
if (adjustedInstanceCount == 0)
{
mDeviceContext->DrawIndexed(count, 0, baseVertex);
mDeviceContext->DrawIndexed(params.indexCount(), 0, baseVertex);
}
else
{
mDeviceContext->DrawIndexedInstanced(count, adjustedInstanceCount, 0, baseVertex, 0);
mDeviceContext->DrawIndexedInstanced(params.indexCount(), adjustedInstanceCount, 0,
baseVertex, 0);
}
return gl::NoError();
}
......@@ -1695,9 +1668,9 @@ gl::Error Renderer11::drawElements(const gl::Context *context,
// Indexed pointsprite emulation replicates data for duplicate entries found in the index
// buffer. This is not an efficent rendering mechanism and is only used on downlevel renderers
// that do not support geometry shaders.
if (instances == 0)
if (params.instances() == 0)
{
mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
mDeviceContext->DrawIndexedInstanced(6, params.indexCount(), 0, 0, 0);
return gl::NoError();
}
......@@ -1705,10 +1678,10 @@ gl::Error Renderer11::drawElements(const gl::Context *context,
// efficent code path. Instanced rendering of emulated pointsprites requires a loop to draw each
// batch of points. An offset into the instanced data buffer is calculated and applied on each
// iteration to ensure all instances are rendered correctly.
GLsizei elementsToRender = drawCallParams.vertexCount();
GLsizei elementsToRender = params.vertexCount();
// Each instance being rendered requires the inputlayout cache to reapply buffers and offsets.
for (GLsizei i = 0; i < instances; i++)
for (GLsizei i = 0; i < params.instances(); i++)
{
ANGLE_TRY(mStateManager.updateVertexOffsetsForPointSpritesEmulation(startVertex, i));
mDeviceContext->DrawIndexedInstanced(6, elementsToRender, 0, 0, 0);
......@@ -1718,66 +1691,37 @@ gl::Error Renderer11::drawElements(const gl::Context *context,
}
gl::Error Renderer11::drawArraysIndirect(const gl::Context *context,
GLenum mode,
const void *indirect)
const gl::DrawCallParams &params)
{
const auto &glState = context->getGLState();
ASSERT(!glState.isTransformFeedbackActiveUnpaused());
if (!applyPrimitiveType(glState, mode, std::numeric_limits<int>::max() - 1))
if (!applyPrimitiveType(glState, params.mode(), std::numeric_limits<int>::max() - 1))
{
return gl::NoError();
}
ANGLE_TRY(mStateManager.applyVertexBuffer(context, params));
gl::Buffer *drawIndirectBuffer = glState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
ASSERT(drawIndirectBuffer);
Buffer11 *storage = GetImplAs<Buffer11>(drawIndirectBuffer);
uintptr_t offset = reinterpret_cast<uintptr_t>(indirect);
if (!DrawCallNeedsTranslation(context, mode))
{
gl::DrawCallParams drawCallParams(mode, indirect);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, drawCallParams));
ID3D11Buffer *buffer = nullptr;
ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
mDeviceContext->DrawInstancedIndirect(buffer, static_cast<unsigned int>(offset));
return gl::NoError();
}
const uint8_t *bufferData = nullptr;
ANGLE_TRY(storage->getData(context, &bufferData));
ASSERT(bufferData);
const gl::DrawArraysIndirectCommand *args =
reinterpret_cast<const gl::DrawArraysIndirectCommand *>(bufferData + offset);
GLuint count = args->count;
GLuint instances = args->instanceCount;
GLuint first = args->first;
gl::DrawCallParams drawCallParams(mode, first, count, instances);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, drawCallParams));
uintptr_t offset = reinterpret_cast<uintptr_t>(params.indirect());
if (mode == GL_LINE_LOOP)
{
return drawLineLoop(context, count, GL_NONE, nullptr, 0, instances);
}
if (mode == GL_TRIANGLE_FAN)
{
return drawTriangleFan(context, count, GL_NONE, nullptr, 0, instances);
}
mDeviceContext->DrawInstanced(count, instances, 0, 0);
ID3D11Buffer *buffer = nullptr;
ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
mDeviceContext->DrawInstancedIndirect(buffer, static_cast<unsigned int>(offset));
return gl::NoError();
}
gl::Error Renderer11::drawElementsIndirect(const gl::Context *context,
GLenum mode,
GLenum type,
const void *indirect)
const gl::DrawCallParams &params)
{
const auto &glState = context->getGLState();
ASSERT(!glState.isTransformFeedbackActiveUnpaused());
if (!applyPrimitiveType(glState, mode, std::numeric_limits<int>::max() - 1))
if (!applyPrimitiveType(glState, params.mode(), std::numeric_limits<int>::max() - 1))
{
return gl::NoError();
}
......@@ -1785,64 +1729,16 @@ gl::Error Renderer11::drawElementsIndirect(const gl::Context *context,
gl::Buffer *drawIndirectBuffer = glState.getTargetBuffer(gl::BufferBinding::DrawIndirect);
ASSERT(drawIndirectBuffer);
Buffer11 *storage = GetImplAs<Buffer11>(drawIndirectBuffer);
uintptr_t offset = reinterpret_cast<uintptr_t>(indirect);
uintptr_t offset = reinterpret_cast<uintptr_t>(params.indirect());
// TODO(jmadill): Remove the if statement and compute indirect parameters lazily.
bool usePrimitiveRestartWorkaround =
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), type);
if (!DrawCallNeedsTranslation(context, mode) && !IsStreamingIndexData(context, type))
{
gl::DrawCallParams drawCallParams(mode, type, indirect);
ANGLE_TRY(mStateManager.applyVertexBuffer(context, drawCallParams));
ANGLE_TRY(
mStateManager.applyIndexBuffer(context, drawCallParams, usePrimitiveRestartWorkaround));
ID3D11Buffer *buffer = nullptr;
ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
mDeviceContext->DrawIndexedInstancedIndirect(buffer, static_cast<unsigned int>(offset));
return gl::NoError();
}
const uint8_t *bufferData = nullptr;
ANGLE_TRY(storage->getData(context, &bufferData));
ASSERT(bufferData);
const gl::DrawElementsIndirectCommand *cmd =
reinterpret_cast<const gl::DrawElementsIndirectCommand *>(bufferData + offset);
GLsizei count = cmd->count;
GLuint instances = cmd->primCount;
GLuint firstIndex = cmd->firstIndex;
GLint baseVertex = cmd->baseVertex;
const gl::Type &typeInfo = gl::GetTypeInfo(type);
const void *indices =
reinterpret_cast<const void *>(static_cast<uintptr_t>(firstIndex * typeInfo.bytes));
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), params.type());
gl::DrawCallParams drawCallParams(mode, count, type, indices, baseVertex, instances);
// We must explicitly resolve the index range for the slow-path indirect drawElements to make
// sure we are using the correct 'baseVertex'. This parameter does not exist for the direct
// drawElements.
ANGLE_TRY(drawCallParams.ensureIndexRangeResolved(context));
ANGLE_TRY(
mStateManager.applyIndexBuffer(context, drawCallParams, usePrimitiveRestartWorkaround));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, drawCallParams));
int baseVertexLocation = -static_cast<int>(drawCallParams.getIndexRange().start);
if (mode == GL_LINE_LOOP)
{
return drawLineLoop(context, count, type, indices, baseVertexLocation, instances);
}
if (mode == GL_TRIANGLE_FAN)
{
return drawTriangleFan(context, count, type, indices, baseVertexLocation, instances);
}
mDeviceContext->DrawIndexedInstanced(count, instances, 0, baseVertexLocation, 0);
ANGLE_TRY(mStateManager.applyIndexBuffer(context, params, usePrimitiveRestartWorkaround));
ANGLE_TRY(mStateManager.applyVertexBuffer(context, params));
ID3D11Buffer *buffer = nullptr;
ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_INDIRECT), buffer);
mDeviceContext->DrawIndexedInstancedIndirect(buffer, static_cast<unsigned int>(offset));
return gl::NoError();
}
......@@ -3808,6 +3704,8 @@ gl::ErrorOrResult<unsigned int> Renderer11::getVertexSpaceRequired(
elementCount = UnsignedCeilDivide(static_cast<unsigned int>(instances), divisor);
}
ASSERT(elementCount > 0);
gl::VertexFormatType formatType = gl::GetVertexFormatType(attrib);
const D3D_FEATURE_LEVEL featureLevel = mRenderer11DeviceCaps.featureLevel;
const d3d11::VertexFormat &vertexFormatInfo =
......
......@@ -380,24 +380,10 @@ class Renderer11 : public RendererD3D
DeviceImpl *createEGLDevice() override;
gl::Error drawArrays(const gl::Context *context,
GLenum mode,
GLint startVertex,
GLsizei count,
GLsizei instances);
gl::Error drawElements(const gl::Context *context,
GLenum mode,
GLsizei count,
GLenum type,
const void *indices,
GLsizei instances);
gl::Error drawArraysIndirect(const gl::Context *context, GLenum mode, const void *indirect);
gl::Error drawElementsIndirect(const gl::Context *context,
GLenum mode,
GLenum type,
const void *indirect);
gl::Error drawArrays(const gl::Context *context, const gl::DrawCallParams &params);
gl::Error drawElements(const gl::Context *context, const gl::DrawCallParams &params);
gl::Error drawArraysIndirect(const gl::Context *context, const gl::DrawCallParams &params);
gl::Error drawElementsIndirect(const gl::Context *context, const gl::DrawCallParams &params);
// Necessary hack for default framebuffers in D3D.
FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override;
......
......@@ -24,6 +24,7 @@
#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
#include "libANGLE/renderer/d3d/d3d11/TransformFeedback11.h"
#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h"
#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h"
namespace rx
{
......@@ -179,6 +180,10 @@ void UpdateUniformBuffer(ID3D11DeviceContext *deviceContext,
0);
}
size_t GetReservedBufferCount(bool usesPointSpriteEmulation)
{
return usesPointSpriteEmulation ? 1 : 0;
}
} // anonymous namespace
// StateManager11::ViewCache Implementation.
......@@ -1437,6 +1442,7 @@ void StateManager11::invalidateVertexBuffer()
gl::MAX_VERTEX_ATTRIBS);
mDirtyVertexBufferRange = gl::RangeUI(0, limit);
mInputLayoutIsDirty = true;
invalidateShaders();
mInternalDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_ATTRIBS);
invalidateVertexAttributeTranslation();
}
......@@ -1753,6 +1759,9 @@ void StateManager11::deinitialize()
mDriverConstantBufferVS.reset();
mDriverConstantBufferPS.reset();
mDriverConstantBufferCS.reset();
mPointSpriteVertexBuffer.reset();
mPointSpriteIndexBuffer.reset();
}
gl::Error StateManager11::syncFramebuffer(const gl::Context *context, gl::Framebuffer *framebuffer)
......@@ -1841,6 +1850,8 @@ void StateManager11::invalidateCurrentValueAttrib(size_t attribIndex)
{
mDirtyCurrentValueAttribs.set(attribIndex);
mInternalDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_ATTRIBS);
mInputLayoutIsDirty = true;
invalidateShaders();
}
gl::Error StateManager11::syncCurrentValueAttribs(const gl::State &glState)
......@@ -1870,7 +1881,6 @@ gl::Error StateManager11::syncCurrentValueAttribs(const gl::State &glState)
currentValueAttrib->binding = &vertexBindings[attrib->bindingIndex];
mDirtyVertexBufferRange.extend(static_cast<unsigned int>(attribIndex));
mInputLayoutIsDirty = true;
ANGLE_TRY(mVertexDataManager.storeCurrentValue(currentValue, currentValueAttrib,
static_cast<size_t>(attribIndex)));
......@@ -1881,6 +1891,14 @@ gl::Error StateManager11::syncCurrentValueAttribs(const gl::State &glState)
void StateManager11::setInputLayout(const d3d11::InputLayout *inputLayout)
{
if (setInputLayoutInternal(inputLayout))
{
mInputLayoutIsDirty = true;
}
}
bool StateManager11::setInputLayoutInternal(const d3d11::InputLayout *inputLayout)
{
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
if (inputLayout == nullptr)
{
......@@ -1888,15 +1906,17 @@ void StateManager11::setInputLayout(const d3d11::InputLayout *inputLayout)
{
deviceContext->IASetInputLayout(nullptr);
mCurrentInputLayout.clear();
mInputLayoutIsDirty = true;
return true;
}
}
else if (inputLayout->getSerial() != mCurrentInputLayout)
{
deviceContext->IASetInputLayout(inputLayout->get());
mCurrentInputLayout = inputLayout->getSerial();
mInputLayoutIsDirty = true;
return true;
}
return false;
}
bool StateManager11::queueVertexBufferChange(size_t bufferIndex,
......@@ -1908,7 +1928,6 @@ bool StateManager11::queueVertexBufferChange(size_t bufferIndex,
stride != mCurrentVertexStrides[bufferIndex] ||
offset != mCurrentVertexOffsets[bufferIndex])
{
mInputLayoutIsDirty = true;
mDirtyVertexBufferRange.extend(static_cast<unsigned int>(bufferIndex));
mCurrentVertexBuffers[bufferIndex] = buffer;
......@@ -1920,18 +1939,6 @@ bool StateManager11::queueVertexBufferChange(size_t bufferIndex,
return false;
}
bool StateManager11::queueVertexOffsetChange(size_t bufferIndex, UINT offsetOnly)
{
if (offsetOnly != mCurrentVertexOffsets[bufferIndex])
{
mInputLayoutIsDirty = true;
mDirtyVertexBufferRange.extend(static_cast<unsigned int>(bufferIndex));
mCurrentVertexOffsets[bufferIndex] = offsetOnly;
return true;
}
return false;
}
void StateManager11::applyVertexBufferChanges()
{
if (mDirtyVertexBufferRange.empty())
......@@ -1956,11 +1963,13 @@ void StateManager11::setSingleVertexBuffer(const d3d11::Buffer *buffer, UINT str
ID3D11Buffer *native = buffer ? buffer->get() : nullptr;
if (queueVertexBufferChange(0, native, stride, offset))
{
mInputLayoutIsDirty = true;
applyVertexBufferChanges();
}
}
gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMode)
gl::Error StateManager11::updateState(const gl::Context *context,
const gl::DrawCallParams &drawCallParams)
{
const auto &glState = context->getGLState();
auto *programD3D = GetImplAs<ProgramD3D>(glState.getProgram());
......@@ -1991,7 +2000,7 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod
Framebuffer11 *framebuffer11 = GetImplAs<Framebuffer11>(framebuffer);
ANGLE_TRY(framebuffer11->markAttachmentsDirty(context));
bool pointDrawMode = (drawMode == GL_POINTS);
bool pointDrawMode = (drawCallParams.mode() == GL_POINTS);
if (pointDrawMode != mCurRasterState.pointDrawMode)
{
mInternalDirtyBits.set(DIRTY_BIT_RASTERIZER_STATE);
......@@ -2059,7 +2068,7 @@ gl::Error StateManager11::updateState(const gl::Context *context, GLenum drawMod
ANGLE_TRY(syncUniformBuffers(context, programD3D));
break;
case DIRTY_BIT_SHADERS:
ANGLE_TRY(syncProgram(context, drawMode));
ANGLE_TRY(syncProgram(context, drawCallParams.mode()));
break;
case DIRTY_BIT_CURRENT_VALUE_ATTRIBS:
ANGLE_TRY(syncCurrentValueAttribs(glState));
......@@ -2710,13 +2719,13 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
}
// Update the applied input layout by querying the cache.
ANGLE_TRY(mInputLayoutCache.updateInputLayout(mRenderer, state, mCurrentAttributes,
sortedSemanticIndices, drawCallParams));
const d3d11::InputLayout *inputLayout = nullptr;
ANGLE_TRY(mInputLayoutCache.getInputLayout(
mRenderer, state, mCurrentAttributes, sortedSemanticIndices, drawCallParams, &inputLayout));
setInputLayoutInternal(inputLayout);
// Update the applied vertex buffers.
ANGLE_TRY(mInputLayoutCache.applyVertexBuffers(
context, mCurrentAttributes, drawCallParams.mode(), drawCallParams.firstVertex(),
drawCallParams.isDrawElements()));
ANGLE_TRY(applyVertexBuffers(context, drawCallParams));
// InputLayoutCache::applyVertexBuffers calls through to the Bufer11 to get the native vertex
// buffer (ID3D11Buffer *). Because we allocate these buffers lazily, this will trigger
......@@ -2727,7 +2736,162 @@ gl::Error StateManager11::applyVertexBuffer(const gl::Context *context,
// is clean. This is a bit of a hack.
vertexArray11->clearDirtyAndPromoteDynamicAttribs(context, drawCallParams);
// Retrieving ID3D11Buffer handles and promotion can trigger dependent state changes.
// TODO(jmadill): Clean this up.
mInternalDirtyBits.reset(DIRTY_BIT_SHADERS);
mInputLayoutIsDirty = false;
return gl::NoError();
}
gl::Error StateManager11::applyVertexBuffers(const gl::Context *context,
const gl::DrawCallParams &drawCallParams)
{
const gl::State &state = context->getGLState();
gl::Program *program = state.getProgram();
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
bool programUsesInstancedPointSprites =
programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation();
bool instancedPointSpritesActive =
programUsesInstancedPointSprites && (drawCallParams.mode() == GL_POINTS);
// Note that if we use instance emulation, we reserve the first buffer slot.
size_t reservedBuffers = GetReservedBufferCount(programUsesInstancedPointSprites);
for (size_t attribIndex = 0; attribIndex < (gl::MAX_VERTEX_ATTRIBS - reservedBuffers);
++attribIndex)
{
ID3D11Buffer *buffer = nullptr;
UINT vertexStride = 0;
UINT vertexOffset = 0;
if (attribIndex < mCurrentAttributes.size())
{
const TranslatedAttribute &attrib = *mCurrentAttributes[attribIndex];
Buffer11 *bufferStorage = attrib.storage ? GetAs<Buffer11>(attrib.storage) : nullptr;
// If indexed pointsprite emulation is active, then we need to take a less efficent code
// path. Emulated indexed pointsprite rendering requires that the vertex buffers match
// exactly to the indices passed by the caller. This could expand or shrink the vertex
// buffer depending on the number of points indicated by the index list or how many
// duplicates are found on the index list.
if (bufferStorage == nullptr)
{
ASSERT(attrib.vertexBuffer.get());
buffer = GetAs<VertexBuffer11>(attrib.vertexBuffer.get())->getBuffer().get();
}
else if (instancedPointSpritesActive && drawCallParams.isDrawElements())
{
VertexArray11 *vao11 = GetImplAs<VertexArray11>(state.getVertexArray());
ASSERT(vao11->isCachedIndexInfoValid());
TranslatedIndexData *indexInfo = vao11->getCachedIndexInfo();
if (indexInfo->srcIndexData.srcBuffer != nullptr)
{
const uint8_t *bufferData = nullptr;
ANGLE_TRY(indexInfo->srcIndexData.srcBuffer->getData(context, &bufferData));
ASSERT(bufferData != nullptr);
ptrdiff_t offset =
reinterpret_cast<ptrdiff_t>(indexInfo->srcIndexData.srcIndices);
indexInfo->srcIndexData.srcBuffer = nullptr;
indexInfo->srcIndexData.srcIndices = bufferData + offset;
}
ANGLE_TRY_RESULT(
bufferStorage->getEmulatedIndexedBuffer(context, &indexInfo->srcIndexData,
attrib, drawCallParams.firstVertex()),
buffer);
}
else
{
ANGLE_TRY_RESULT(
bufferStorage->getBuffer(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK),
buffer);
}
vertexStride = attrib.stride;
ANGLE_TRY_RESULT(attrib.computeOffset(drawCallParams.firstVertex()), vertexOffset);
}
size_t bufferIndex = reservedBuffers + attribIndex;
queueVertexBufferChange(bufferIndex, buffer, vertexStride, vertexOffset);
}
// Instanced PointSprite emulation requires two additional ID3D11Buffers. A vertex buffer needs
// to be created and added to the list of current buffers, strides and offsets collections.
// This buffer contains the vertices for a single PointSprite quad.
// An index buffer also needs to be created and applied because rendering instanced data on
// D3D11 FL9_3 requires DrawIndexedInstanced() to be used. Shaders that contain gl_PointSize and
// used without the GL_POINTS rendering mode require a vertex buffer because some drivers cannot
// handle missing vertex data and will TDR the system.
if (programUsesInstancedPointSprites)
{
constexpr UINT kPointSpriteVertexStride = sizeof(float) * 5;
if (!mPointSpriteVertexBuffer.valid())
{
static constexpr float kPointSpriteVertices[] = {
// Position | TexCoord
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, /* v0 */
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, /* v1 */
1.0f, 1.0f, 0.0f, 1.0f, 0.0f, /* v2 */
1.0f, -1.0f, 0.0f, 1.0f, 1.0f, /* v3 */
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, /* v4 */
1.0f, 1.0f, 0.0f, 1.0f, 0.0f, /* v5 */
};
D3D11_SUBRESOURCE_DATA vertexBufferData = {kPointSpriteVertices, 0, 0};
D3D11_BUFFER_DESC vertexBufferDesc;
vertexBufferDesc.ByteWidth = sizeof(kPointSpriteVertices);
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;
vertexBufferDesc.StructureByteStride = 0;
ANGLE_TRY(mRenderer->allocateResource(vertexBufferDesc, &vertexBufferData,
&mPointSpriteVertexBuffer));
}
// Set the stride to 0 if GL_POINTS mode is not being used to instruct the driver to avoid
// indexing into the vertex buffer.
UINT stride = instancedPointSpritesActive ? kPointSpriteVertexStride : 0;
queueVertexBufferChange(0, mPointSpriteVertexBuffer.get(), stride, 0);
if (!mPointSpriteIndexBuffer.valid())
{
// Create an index buffer and set it for pointsprite rendering
static constexpr unsigned short kPointSpriteIndices[] = {
0, 1, 2, 3, 4, 5,
};
D3D11_SUBRESOURCE_DATA indexBufferData = {kPointSpriteIndices, 0, 0};
D3D11_BUFFER_DESC indexBufferDesc;
indexBufferDesc.ByteWidth = sizeof(kPointSpriteIndices);
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;
indexBufferDesc.StructureByteStride = 0;
ANGLE_TRY(mRenderer->allocateResource(indexBufferDesc, &indexBufferData,
&mPointSpriteIndexBuffer));
}
if (instancedPointSpritesActive)
{
// The index buffer is applied here because Instanced PointSprite emulation uses the a
// non-indexed rendering path in ANGLE (DrawArrays). This means that applyIndexBuffer()
// on the renderer will not be called and setting this buffer here ensures that the
// rendering path will contain the correct index buffers.
syncIndexBuffer(mPointSpriteIndexBuffer.get(), DXGI_FORMAT_R16_UINT, 0);
}
}
applyVertexBufferChanges();
return gl::NoError();
}
......@@ -2814,8 +2978,28 @@ bool StateManager11::syncIndexBuffer(ID3D11Buffer *buffer,
gl::Error StateManager11::updateVertexOffsetsForPointSpritesEmulation(GLint startVertex,
GLsizei emulatedInstanceId)
{
return mInputLayoutCache.updateVertexOffsetsForPointSpritesEmulation(
mRenderer, mCurrentAttributes, startVertex, emulatedInstanceId);
size_t reservedBuffers = GetReservedBufferCount(true);
for (size_t attribIndex = 0; attribIndex < mCurrentAttributes.size(); ++attribIndex)
{
const auto &attrib = *mCurrentAttributes[attribIndex];
size_t bufferIndex = reservedBuffers + attribIndex;
if (attrib.divisor > 0)
{
unsigned int offset = 0;
ANGLE_TRY_RESULT(attrib.computeOffset(startVertex), offset);
offset += (attrib.stride * (emulatedInstanceId / attrib.divisor));
if (offset != mCurrentVertexOffsets[bufferIndex])
{
mInputLayoutIsDirty = true;
mDirtyVertexBufferRange.extend(static_cast<unsigned int>(bufferIndex));
mCurrentVertexOffsets[bufferIndex] = offset;
}
}
}
applyVertexBufferChanges();
return gl::NoError();
}
gl::Error StateManager11::generateSwizzle(const gl::Context *context, gl::Texture *texture)
......
......@@ -201,17 +201,9 @@ class StateManager11 final : angle::NonCopyable
void setInputLayout(const d3d11::InputLayout *inputLayout);
// TODO(jmadill): Migrate to d3d11::Buffer.
bool queueVertexBufferChange(size_t bufferIndex,
ID3D11Buffer *buffer,
UINT stride,
UINT offset);
bool queueVertexOffsetChange(size_t bufferIndex, UINT offsetOnly);
void applyVertexBufferChanges();
void setSingleVertexBuffer(const d3d11::Buffer *buffer, UINT stride, UINT offset);
gl::Error updateState(const gl::Context *context, GLenum drawMode);
gl::Error updateState(const gl::Context *context, const gl::DrawCallParams &drawCallParams);
void setShaderResourceShared(gl::ShaderType shaderType,
UINT resourceSlot,
......@@ -342,6 +334,17 @@ class StateManager11 final : angle::NonCopyable
bool syncIndexBuffer(ID3D11Buffer *buffer, DXGI_FORMAT indexFormat, unsigned int offset);
bool setInputLayoutInternal(const d3d11::InputLayout *inputLayout);
gl::Error applyVertexBuffers(const gl::Context *context,
const gl::DrawCallParams &drawCallParams);
// TODO(jmadill): Migrate to d3d11::Buffer.
bool queueVertexBufferChange(size_t bufferIndex,
ID3D11Buffer *buffer,
UINT stride,
UINT offset);
void applyVertexBufferChanges();
enum DirtyBitType
{
DIRTY_BIT_RENDER_TARGET,
......@@ -520,6 +523,9 @@ class StateManager11 final : angle::NonCopyable
ResourceSerial mCurrentComputeConstantBuffer;
ResourceSerial mCurrentGeometryConstantBuffer;
d3d11::Buffer mPointSpriteVertexBuffer;
d3d11::Buffer mPointSpriteIndexBuffer;
template <typename T>
using VertexConstantBufferArray =
std::array<T, gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS>;
......
......@@ -50,6 +50,7 @@ VertexArray11::VertexArray11(const gl::VertexArrayState &data)
mLastElementType(GL_NONE),
mLastDrawElementsOffset(0),
mCurrentElementArrayStorage(IndexStorageType::Invalid),
mCachedIndexInfo{0},
mCachedIndexInfoValid(false)
{
for (size_t attribIndex = 0; attribIndex < mCurrentArrayBuffers.size(); ++attribIndex)
......
......@@ -2358,46 +2358,6 @@ bool UsePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled, GLenu
return (!primitiveRestartFixedIndexEnabled && type == GL_UNSIGNED_SHORT);
}
bool IsStreamingIndexData(const gl::Context *context, GLenum srcType)
{
const auto &glState = context->getGLState();
gl::Buffer *glBuffer = glState.getVertexArray()->getElementArrayBuffer().get();
// Case 1: the indices are passed by pointer, which forces the streaming of index data
if (glBuffer == nullptr)
{
return true;
}
bool primitiveRestartWorkaround =
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), srcType);
BufferD3D *buffer = GetImplAs<BufferD3D>(glBuffer);
const GLenum dstType = (srcType == GL_UNSIGNED_INT || primitiveRestartWorkaround)
? GL_UNSIGNED_INT
: GL_UNSIGNED_SHORT;
// Case 2a: the buffer can be used directly
if (buffer->supportsDirectBinding() && dstType == srcType)
{
return false;
}
// Case 2b: use a static translated copy or fall back to streaming
StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer();
if (staticBuffer == nullptr)
{
return true;
}
if ((staticBuffer->getBufferSize() == 0) || (staticBuffer->getIndexType() != dstType))
{
return true;
}
return false;
}
IndexStorageType ClassifyIndexStorage(const gl::State &glState,
const gl::Buffer *elementArrayBuffer,
GLenum elementType,
......
......@@ -397,7 +397,6 @@ enum class StagingAccess
bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachment *colorbuffer);
bool UsePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled, GLenum type);
bool IsStreamingIndexData(const gl::Context *context, GLenum srcType);
enum class IndexStorageType
{
......
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