Commit 484dd7b1 by Qin Jiajia Committed by Commit Bot

ES31: Implement DrawElementsIndirect D3D part

The implementation of DrawElementsIndirect is similar with DrawArraysIndirect except that it needs to apply IndexBuffer. BUG=angleproject:1595 TEST=dEQP-GLES31.functional.draw_indirect.draw_elements_indirect* dEQP-GLES31.functional.draw_indirect.instancing.* dEQP-GLES31.functional.draw_indirect.random.* Change-Id: I5d2c8a7485b18b724fdda6fd964013c941e45b4f Reviewed-on: https://chromium-review.googlesource.com/455520 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 795e7573
...@@ -137,6 +137,52 @@ IndexDataManager::~IndexDataManager() ...@@ -137,6 +137,52 @@ IndexDataManager::~IndexDataManager()
SafeDelete(mStreamingBufferInt); SafeDelete(mStreamingBufferInt);
} }
bool IndexDataManager::usePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled,
GLenum type)
{
// We should never have to deal with primitive restart workaround issue with GL_UNSIGNED_INT
// indices, since we restrict it via MAX_ELEMENT_INDEX.
return (!primitiveRestartFixedIndexEnabled && type == GL_UNSIGNED_SHORT &&
mRendererClass == RENDERER_D3D11);
}
bool IndexDataManager::isStreamingIndexData(bool primitiveRestartWorkaround,
GLenum srcType,
gl::Buffer *glBuffer)
{
BufferD3D *buffer = glBuffer ? GetImplAs<BufferD3D>(glBuffer) : nullptr;
// Case 1: the indices are passed by pointer, which forces the streaming of index data
if (glBuffer == nullptr)
{
return true;
}
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;
}
// This function translates a GL-style indices into DX-style indices, with their description // This function translates a GL-style indices into DX-style indices, with their description
// returned in translated. // returned in translated.
// GL can specify vertex data in immediate mode (pointer to CPU array of indices), which is not // GL can specify vertex data in immediate mode (pointer to CPU array of indices), which is not
...@@ -157,9 +203,9 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType, ...@@ -157,9 +203,9 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType,
bool hasPrimitiveRestartIndex = bool hasPrimitiveRestartIndex =
translated->indexRange.vertexIndexCount < static_cast<size_t>(count) || translated->indexRange.vertexIndexCount < static_cast<size_t>(count) ||
translated->indexRange.end == gl::GetPrimitiveRestartIndex(srcType); translated->indexRange.end == gl::GetPrimitiveRestartIndex(srcType);
bool primitiveRestartWorkaround = mRendererClass == RENDERER_D3D11 && bool primitiveRestartWorkaround =
!primitiveRestartFixedIndexEnabled && usePrimitiveRestartWorkaround(primitiveRestartFixedIndexEnabled, srcType) &&
hasPrimitiveRestartIndex && srcType == GL_UNSIGNED_SHORT; hasPrimitiveRestartIndex;
// We should never have to deal with MAX_UINT indices, since we restrict it via // We should never have to deal with MAX_UINT indices, since we restrict it via
// MAX_ELEMENT_INDEX. // MAX_ELEMENT_INDEX.
...@@ -202,8 +248,7 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType, ...@@ -202,8 +248,7 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType,
} }
// Case 2a: the buffer can be used directly // Case 2a: the buffer can be used directly
if (offsetAligned && buffer->supportsDirectBinding() && if (offsetAligned && buffer->supportsDirectBinding() && dstType == srcType)
dstType == srcType && !primitiveRestartWorkaround)
{ {
translated->storage = buffer; translated->storage = buffer;
translated->indexBuffer = nullptr; translated->indexBuffer = nullptr;
......
...@@ -65,6 +65,10 @@ class IndexDataManager : angle::NonCopyable ...@@ -65,6 +65,10 @@ class IndexDataManager : angle::NonCopyable
explicit IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass); explicit IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass);
virtual ~IndexDataManager(); virtual ~IndexDataManager();
bool usePrimitiveRestartWorkaround(bool primitiveRestartFixedIndexEnabled, GLenum type);
bool isStreamingIndexData(bool primitiveRestartWorkaround,
GLenum srcType,
gl::Buffer *glBuffer);
gl::Error prepareIndexData(GLenum srcType, gl::Error prepareIndexData(GLenum srcType,
GLsizei count, GLsizei count,
gl::Buffer *glBuffer, gl::Buffer *glBuffer,
......
...@@ -2016,6 +2016,34 @@ gl::Error Renderer11::drawElementsImpl(const gl::ContextState &data, ...@@ -2016,6 +2016,34 @@ gl::Error Renderer11::drawElementsImpl(const gl::ContextState &data,
return gl::NoError(); return gl::NoError();
} }
bool Renderer11::supportsFastIndirectDraw(const gl::State &state, GLenum mode, GLenum type)
{
const auto &vertexArray = state.getVertexArray();
auto *vertexArray11 = GetImplAs<VertexArray11>(vertexArray);
// Indirect 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->hasDynamicAttrib(state) || mode == GL_LINE_LOOP || mode == GL_TRIANGLE_FAN)
{
return false;
}
if (type != GL_NONE)
{
gl::Buffer *elementArrayBuffer = vertexArray->getElementArrayBuffer().get();
ASSERT(elementArrayBuffer);
// Only non-streaming index data can be directly used to do indirect draw since they don't
// need the indices and count informations. Here we don't check whether it really has
// primitive restart index in it since it also needs to know the index range and count.
// So, for all other situations, we fall back to normal draw instead of indirect draw.
bool primitiveRestartWorkaround = mIndexDataManager->usePrimitiveRestartWorkaround(
state.isPrimitiveRestartEnabled(), type);
return !mIndexDataManager->isStreamingIndexData(primitiveRestartWorkaround, type,
elementArrayBuffer);
}
return true;
}
gl::Error Renderer11::drawArraysIndirectImpl(const gl::ContextState &data, gl::Error Renderer11::drawArraysIndirectImpl(const gl::ContextState &data,
GLenum mode, GLenum mode,
const GLvoid *indirect) const GLvoid *indirect)
...@@ -2031,11 +2059,7 @@ gl::Error Renderer11::drawArraysIndirectImpl(const gl::ContextState &data, ...@@ -2031,11 +2059,7 @@ gl::Error Renderer11::drawArraysIndirectImpl(const gl::ContextState &data,
Buffer11 *storage = GetImplAs<Buffer11>(drawIndirectBuffer); Buffer11 *storage = GetImplAs<Buffer11>(drawIndirectBuffer);
uintptr_t offset = reinterpret_cast<uintptr_t>(indirect); uintptr_t offset = reinterpret_cast<uintptr_t>(indirect);
const auto &vertexArray = glState.getVertexArray(); if (supportsFastIndirectDraw(glState, mode, GL_NONE))
auto *vertexArray11 = GetImplAs<VertexArray11>(vertexArray);
// If there is no dynamic attribute, we can directly use the indirect buffer.
if (!vertexArray11->hasDynamicAttrib(glState) && mode != GL_LINE_LOOP &&
mode != GL_TRIANGLE_FAN)
{ {
applyVertexBuffer(glState, mode, 0, 0, 0, nullptr); applyVertexBuffer(glState, mode, 0, 0, 0, nullptr);
ID3D11Buffer *buffer = nullptr; ID3D11Buffer *buffer = nullptr;
...@@ -2073,8 +2097,67 @@ gl::Error Renderer11::drawElementsIndirectImpl(const gl::ContextState &data, ...@@ -2073,8 +2097,67 @@ gl::Error Renderer11::drawElementsIndirectImpl(const gl::ContextState &data,
GLenum type, GLenum type,
const GLvoid *indirect) const GLvoid *indirect)
{ {
UNIMPLEMENTED(); if (skipDraw(data, mode))
return gl::InternalError() << "DrawElementsIndirect hasn't been implemented for D3D11 backend."; {
return gl::NoError();
}
const auto &glState = data.getState();
gl::Buffer *drawIndirectBuffer = glState.getDrawIndirectBuffer();
ASSERT(drawIndirectBuffer);
Buffer11 *storage = GetImplAs<Buffer11>(drawIndirectBuffer);
uintptr_t offset = reinterpret_cast<uintptr_t>(indirect);
TranslatedIndexData indexInfo;
if (supportsFastIndirectDraw(glState, mode, type))
{
ANGLE_TRY(applyIndexBuffer(data, nullptr, 0, mode, type, &indexInfo));
ANGLE_TRY(applyVertexBuffer(glState, mode, 0, 0, 0, &indexInfo));
ID3D11Buffer *buffer = nullptr;
ANGLE_TRY_RESULT(storage->getBuffer(BUFFER_USAGE_INDIRECT), buffer);
mDeviceContext->DrawIndexedInstancedIndirect(buffer, static_cast<unsigned int>(offset));
return gl::NoError();
}
const uint8_t *bufferData = nullptr;
ANGLE_TRY(storage->getData(&bufferData));
ASSERT(bufferData);
const gl::DrawElementsIndirectCommand *cmd =
reinterpret_cast<const gl::DrawElementsIndirectCommand *>(bufferData + offset);
GLuint count = cmd->count;
GLuint instances = cmd->primCount;
GLuint firstIndex = cmd->firstIndex;
GLint baseVertex = cmd->baseVertex;
const gl::Type &typeInfo = gl::GetTypeInfo(type);
uint8_t *indices = static_cast<uint8_t *>(0) + firstIndex * typeInfo.bytes;
gl::Buffer *elementArrayBuffer = glState.getVertexArray()->getElementArrayBuffer().get();
ASSERT(elementArrayBuffer);
gl::IndexRange indexRange;
ANGLE_TRY(elementArrayBuffer->getIndexRange(type, reinterpret_cast<size_t>(indices), count,
glState.isPrimitiveRestartEnabled(), &indexRange));
indexInfo.indexRange = indexRange;
ANGLE_TRY(applyIndexBuffer(data, indices, count, mode, type, &indexInfo));
size_t vertexCount = indexRange.vertexCount();
ANGLE_TRY(applyVertexBuffer(glState, mode, static_cast<GLsizei>(indexRange.start) + baseVertex,
static_cast<GLsizei>(vertexCount), instances, &indexInfo));
int baseVertexLocation = -static_cast<int>(indexRange.start);
if (mode == GL_LINE_LOOP)
{
return drawLineLoop(data, count, type, indices, baseVertexLocation, instances);
}
if (mode == GL_TRIANGLE_FAN)
{
return drawTriangleFan(data, count, type, indices, baseVertexLocation, instances);
}
mDeviceContext->DrawIndexedInstanced(count, instances, 0, baseVertexLocation, 0);
return gl::NoError();
} }
gl::Error Renderer11::drawLineLoop(const gl::ContextState &data, gl::Error Renderer11::drawLineLoop(const gl::ContextState &data,
......
...@@ -411,6 +411,9 @@ class Renderer11 : public RendererD3D ...@@ -411,6 +411,9 @@ class Renderer11 : public RendererD3D
GLenum type, GLenum type,
const GLvoid *indirect); const GLvoid *indirect);
// Support directly using indirect draw buffer.
bool supportsFastIndirectDraw(const gl::State &state, GLenum mode, GLenum type);
void generateCaps(gl::Caps *outCaps, void generateCaps(gl::Caps *outCaps,
gl::TextureCapsMap *outTextureCaps, gl::TextureCapsMap *outTextureCaps,
gl::Extensions *outExtensions, gl::Extensions *outExtensions,
......
...@@ -104,9 +104,6 @@ ...@@ -104,9 +104,6 @@
1442 OPENGL : dEQP-GLES31.functional.shaders.builtin_functions.texture_size.samples_4_texture_uint_2d_array = FAIL 1442 OPENGL : dEQP-GLES31.functional.shaders.builtin_functions.texture_size.samples_4_texture_uint_2d_array = FAIL
// D3D11 Failing Tests // D3D11 Failing Tests
1595 D3D11 : dEQP-GLES31.functional.draw_indirect.draw_elements_indirect.* = FAIL
1595 D3D11 : dEQP-GLES31.functional.draw_indirect.instancing.* = FAIL
1595 D3D11 : dEQP-GLES31.functional.draw_indirect.random.* = FAIL
1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_functions.texture_size.* = FAIL 1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_functions.texture_size.* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_color_texture_samples_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_color_texture_samples_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_depth_texture_samples_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_depth_texture_samples_* = FAIL
......
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