Commit 4dd1e55f by Jamie Madill

D3D11: Implement basic primitive restart.

D3D11 handles primitive restart similarly to OpenGL's fixed index, with a couple differences. It can't be toggled off, so we need to restrict the max element index (handled in a prior patch), and for smaller buffer types we need to rewrite the index data. BUG=angleproject:597 Change-Id: Ib890ce9b3f5511784138ea3953a384b1c483ca9e Reviewed-on: https://chromium-review.googlesource.com/309639Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org>
parent c4c74422
......@@ -18,57 +18,82 @@
namespace rx
{
static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input,
GLsizei count, void *output)
namespace
{
if (sourceType == GL_UNSIGNED_BYTE)
{
ASSERT(destinationType == GL_UNSIGNED_SHORT);
const GLubyte *in = static_cast<const GLubyte*>(input);
GLushort *out = static_cast<GLushort*>(output);
template <typename InputT, typename DestT>
void ConvertIndexArray(const void *input,
GLenum sourceType,
void *output,
GLenum destinationType,
GLsizei count,
bool usePrimitiveRestartFixedIndex)
{
const InputT *in = static_cast<const InputT *>(input);
DestT *out = static_cast<DestT *>(output);
if (usePrimitiveRestartFixedIndex)
{
InputT srcRestartIndex = static_cast<InputT>(gl::GetPrimitiveRestartIndex(sourceType));
DestT destRestartIndex = static_cast<DestT>(gl::GetPrimitiveRestartIndex(destinationType));
for (GLsizei i = 0; i < count; i++)
{
out[i] = in[i];
out[i] = (in[i] == srcRestartIndex ? destRestartIndex : static_cast<DestT>(in[i]));
}
}
else if (sourceType == GL_UNSIGNED_INT)
{
ASSERT(destinationType == GL_UNSIGNED_INT);
memcpy(output, input, count * sizeof(GLuint));
}
else if (sourceType == GL_UNSIGNED_SHORT)
else
{
if (destinationType == GL_UNSIGNED_SHORT)
for (GLsizei i = 0; i < count; i++)
{
memcpy(output, input, count * sizeof(GLushort));
out[i] = static_cast<DestT>(in[i]);
}
else if (destinationType == GL_UNSIGNED_INT)
{
const GLushort *in = static_cast<const GLushort*>(input);
GLuint *out = static_cast<GLuint*>(output);
}
}
for (GLsizei i = 0; i < count; i++)
{
out[i] = in[i];
}
}
else UNREACHABLE();
void ConvertIndices(GLenum sourceType,
GLenum destinationType,
const void *input,
GLsizei count,
void *output,
bool usePrimitiveRestartFixedIndex)
{
if (sourceType == destinationType)
{
const gl::Type &typeInfo = gl::GetTypeInfo(destinationType);
memcpy(output, input, count * typeInfo.bytes);
return;
}
if (sourceType == GL_UNSIGNED_BYTE)
{
ASSERT(destinationType == GL_UNSIGNED_SHORT);
ConvertIndexArray<GLubyte, GLushort>(input, sourceType, output, destinationType, count,
usePrimitiveRestartFixedIndex);
}
else if (sourceType == GL_UNSIGNED_SHORT)
{
ASSERT(destinationType == GL_UNSIGNED_INT);
ConvertIndexArray<GLushort, GLuint>(input, sourceType, output, destinationType, count,
usePrimitiveRestartFixedIndex);
}
else UNREACHABLE();
}
static gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer, const GLvoid *data,
unsigned int count, GLenum srcType, GLenum dstType,
unsigned int *offset)
gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer,
const GLvoid *data,
unsigned int count,
GLenum srcType,
GLenum dstType,
bool usePrimitiveRestartFixedIndex,
unsigned int *offset)
{
const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
if (count > (std::numeric_limits<unsigned int>::max() >> dstTypeInfo.bytesShift))
{
return gl::Error(GL_OUT_OF_MEMORY,
"Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
count, dstTypeInfo.bytes);
"Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
count, dstTypeInfo.bytes);
}
unsigned int bufferSizeRequired = count << dstTypeInfo.bytesShift;
......@@ -85,7 +110,7 @@ static gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer, const GLvoid
return error;
}
ConvertIndices(srcType, dstType, data, count, output);
ConvertIndices(srcType, dstType, data, count, output, usePrimitiveRestartFixedIndex);
error = buffer->unmapBuffer();
if (error.isError())
......@@ -96,6 +121,8 @@ static gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer, const GLvoid
return gl::Error(GL_NO_ERROR);
}
} // anonymous namespace
IndexDataManager::IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass)
: mFactory(factory),
mRendererClass(rendererClass),
......@@ -118,9 +145,13 @@ IndexDataManager::~IndexDataManager()
// When we have a buffer with an unsupported format (subcase b) then we need to do some translation:
// we will start by falling back to streaming, and after a while will start using a static translated
// copy of the index buffer.
gl::Error IndexDataManager::prepareIndexData(GLenum srcType, GLsizei count, gl::Buffer *glBuffer,
const GLvoid *indices, TranslatedIndexData *translated,
SourceIndexData *sourceData)
gl::Error IndexDataManager::prepareIndexData(GLenum srcType,
GLsizei count,
gl::Buffer *glBuffer,
const GLvoid *indices,
TranslatedIndexData *translated,
SourceIndexData *sourceData,
bool primitiveRestartFixedIndexEnabled)
{
// Avoid D3D11's primitive restart index value
// see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
......@@ -128,8 +159,14 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType, GLsizei count, gl::
translated->indexRange.vertexIndexCount < static_cast<size_t>(count) ||
translated->indexRange.end == gl::GetPrimitiveRestartIndex(srcType);
bool primitiveRestartWorkaround = mRendererClass == RENDERER_D3D11 &&
!primitiveRestartFixedIndexEnabled &&
hasPrimitiveRestartIndex && srcType == GL_UNSIGNED_SHORT;
// We should never have to deal with MAX_UINT indices, since we restrict it via
// MAX_ELEMENT_INDEX.
ASSERT(!(mRendererClass == RENDERER_D3D11 && !primitiveRestartFixedIndexEnabled &&
hasPrimitiveRestartIndex && srcType == GL_UNSIGNED_INT));
const GLenum dstType = (srcType == GL_UNSIGNED_INT || primitiveRestartWorkaround) ?
GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
......@@ -151,7 +188,8 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType, GLsizei count, gl::
if (glBuffer == nullptr)
{
translated->storage = nullptr;
return streamIndexData(indices, count, srcType, dstType, translated);
return streamIndexData(indices, count, srcType, dstType, primitiveRestartFixedIndexEnabled,
translated);
}
// Case 2: the indices are already in a buffer
......@@ -207,7 +245,8 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType, GLsizei count, gl::
}
ASSERT(bufferData != nullptr);
error = streamIndexData(bufferData + offset, count, srcType, dstType, translated);
error = streamIndexData(bufferData + offset, count, srcType, dstType,
primitiveRestartFixedIndexEnabled, translated);
if (error.isError())
{
return error;
......@@ -227,8 +266,8 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType, GLsizei count, gl::
unsigned int convertCount =
static_cast<unsigned int>(buffer->getSize()) >> srcTypeInfo.bytesShift;
error = StreamInIndexBuffer(staticBuffer, bufferData, convertCount,
srcType, dstType, nullptr);
error = StreamInIndexBuffer(staticBuffer, bufferData, convertCount, srcType, dstType,
primitiveRestartFixedIndexEnabled, nullptr);
if (error.isError())
{
return error;
......@@ -245,8 +284,12 @@ gl::Error IndexDataManager::prepareIndexData(GLenum srcType, GLsizei count, gl::
return gl::Error(GL_NO_ERROR);
}
gl::Error IndexDataManager::streamIndexData(const GLvoid *data, unsigned int count, GLenum srcType,
GLenum dstType, TranslatedIndexData *translated)
gl::Error IndexDataManager::streamIndexData(const GLvoid *data,
unsigned int count,
GLenum srcType,
GLenum dstType,
bool usePrimitiveRestartFixedIndex,
TranslatedIndexData *translated)
{
const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
......@@ -259,7 +302,8 @@ gl::Error IndexDataManager::streamIndexData(const GLvoid *data, unsigned int cou
ASSERT(indexBuffer != nullptr);
unsigned int offset;
StreamInIndexBuffer(indexBuffer, data, count, srcType, dstType, &offset);
StreamInIndexBuffer(indexBuffer, data, count, srcType, dstType, usePrimitiveRestartFixedIndex,
&offset);
translated->indexBuffer = indexBuffer->getIndexBuffer();
translated->serial = indexBuffer->getSerial();
......
......@@ -63,13 +63,21 @@ class IndexDataManager : angle::NonCopyable
explicit IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass);
virtual ~IndexDataManager();
gl::Error prepareIndexData(GLenum srcType, GLsizei count, gl::Buffer *glBuffer,
const GLvoid *indices, TranslatedIndexData *translated,
SourceIndexData *sourceData);
gl::Error prepareIndexData(GLenum srcType,
GLsizei count,
gl::Buffer *glBuffer,
const GLvoid *indices,
TranslatedIndexData *translated,
SourceIndexData *sourceData,
bool primitiveRestartFixedIndexEnabled);
private:
gl::Error streamIndexData(const GLvoid *data, unsigned int count, GLenum srcType,
GLenum dstType, TranslatedIndexData *translated);
gl::Error streamIndexData(const GLvoid *data,
unsigned int count,
GLenum srcType,
GLenum dstType,
bool usePrimitiveRestartFixedIndex,
TranslatedIndexData *translated);
gl::Error getStreamingIndexBuffer(GLenum destinationIndexType,
IndexBufferInterface **outBuffer);
......
......@@ -134,12 +134,6 @@ gl::Error RendererD3D::genericDrawElements(const gl::Data &data,
GLsizei instances,
const gl::IndexRange &indexRange)
{
if (data.state->isPrimitiveRestartEnabled())
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION, "Primitive restart not implemented");
}
gl::Program *program = data.state->getProgram();
ASSERT(program != nullptr);
ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program);
......@@ -170,13 +164,12 @@ gl::Error RendererD3D::genericDrawElements(const gl::Data &data,
return error;
}
gl::VertexArray *vao = data.state->getVertexArray();
TranslatedIndexData indexInfo;
indexInfo.indexRange = indexRange;
SourceIndexData sourceIndexInfo;
error = applyIndexBuffer(indices, vao->getElementArrayBuffer().get(), count, mode, type, &indexInfo, &sourceIndexInfo);
error = applyIndexBuffer(data, indices, count, mode, type, &indexInfo, &sourceIndexInfo);
if (error.isError())
{
return error;
......@@ -215,8 +208,7 @@ gl::Error RendererD3D::genericDrawElements(const gl::Data &data,
if (!skipDraw(data, mode))
{
error = drawElementsImpl(mode, count, type, indices, vao->getElementArrayBuffer().get(),
indexInfo, instances, usesPointSize);
error = drawElementsImpl(data, indexInfo, mode, count, type, indices, instances);
if (error.isError())
{
return error;
......
......@@ -165,7 +165,13 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
const std::vector<D3DUniform *> &uniformArray) = 0;
virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize) = 0;
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceIndexInfo) = 0;
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo) = 0;
virtual gl::Error applyIndexBuffer(const gl::Data &data,
const GLvoid *indices,
GLsizei count,
GLenum mode,
GLenum type,
TranslatedIndexData *indexInfo,
SourceIndexData *sourceIndexInfo) = 0;
virtual void applyTransformFeedbackBuffers(const gl::State& state) = 0;
virtual void markAllStateDirty() = 0;
......@@ -279,14 +285,13 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
GLenum mode,
GLsizei count,
GLsizei instances) = 0;
virtual gl::Error drawElementsImpl(GLenum mode,
virtual gl::Error drawElementsImpl(const gl::Data &data,
const TranslatedIndexData &indexInfo,
GLenum mode,
GLsizei count,
GLenum type,
const GLvoid *indices,
gl::Buffer *elementArrayBuffer,
const TranslatedIndexData &indexInfo,
GLsizei instances,
bool usesPointSize) = 0;
GLsizei instances) = 0;
//FIXME(jmadill): std::array is currently prohibited by Chromium style guide
typedef std::array<gl::Texture*, gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS> FramebufferTextureArray;
......
......@@ -136,7 +136,13 @@ class Renderer11 : public RendererD3D
GLenum drawMode,
const std::vector<D3DUniform *> &uniformArray) override;
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceIndexInfo);
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo);
gl::Error applyIndexBuffer(const gl::Data &data,
const GLvoid *indices,
GLsizei count,
GLenum mode,
GLenum type,
TranslatedIndexData *indexInfo,
SourceIndexData *sourceIndexInfo) override;
void applyTransformFeedbackBuffers(const gl::State &state) override;
virtual void markAllStateDirty();
......@@ -276,14 +282,13 @@ class Renderer11 : public RendererD3D
GLenum mode,
GLsizei count,
GLsizei instances) override;
gl::Error drawElementsImpl(GLenum mode,
gl::Error drawElementsImpl(const gl::Data &data,
const TranslatedIndexData &indexInfo,
GLenum mode,
GLsizei count,
GLenum type,
const GLvoid *indices,
gl::Buffer *elementArrayBuffer,
const TranslatedIndexData &indexInfo,
GLsizei instances,
bool usesPointSize) override;
GLsizei instances) override;
void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps,
gl::Extensions *outExtensions,
......@@ -291,8 +296,17 @@ class Renderer11 : public RendererD3D
WorkaroundsD3D generateWorkarounds() const override;
gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
gl::Error drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances);
gl::Error drawLineLoop(const gl::Data &data,
GLsizei count,
GLenum type,
const GLvoid *indices,
int minIndex);
gl::Error drawTriangleFan(const gl::Data &data,
GLsizei count,
GLenum type,
const GLvoid *indices,
int minIndex,
int instances);
ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource);
void unsetConflictingSRVs(gl::SamplerType shaderType, uintptr_t resource, const gl::ImageIndex &index);
......
......@@ -1455,9 +1455,18 @@ gl::Error Renderer9::applyVertexBuffer(const gl::State &state, GLenum mode, GLin
}
// Applies the indices and element array bindings to the Direct3D 9 device
gl::Error Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo)
gl::Error Renderer9::applyIndexBuffer(const gl::Data &data,
const GLvoid *indices,
GLsizei count,
GLenum mode,
GLenum type,
TranslatedIndexData *indexInfo,
SourceIndexData *sourceIndexInfo)
{
gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo, sourceIndexInfo);
gl::VertexArray *vao = data.state->getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices,
indexInfo, sourceIndexInfo, false);
if (error.isError())
{
return error;
......@@ -1526,19 +1535,21 @@ gl::Error Renderer9::drawArraysImpl(const gl::Data &data,
}
}
gl::Error Renderer9::drawElementsImpl(GLenum mode,
gl::Error Renderer9::drawElementsImpl(const gl::Data &data,
const TranslatedIndexData &indexInfo,
GLenum mode,
GLsizei count,
GLenum type,
const GLvoid *indices,
gl::Buffer *elementArrayBuffer,
const TranslatedIndexData &indexInfo,
GLsizei /*instances*/,
bool /*usesPointSize*/)
GLsizei /*instances*/)
{
startScene();
int minIndex = static_cast<int>(indexInfo.indexRange.start);
gl::VertexArray *vao = data.state->getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
if (mode == GL_POINTS)
{
return drawIndexedPoints(count, type, indices, minIndex, elementArrayBuffer);
......
......@@ -114,7 +114,13 @@ class Renderer9 : public RendererD3D
const std::vector<D3DUniform *> &uniformArray) override;
virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize);
virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances, SourceIndexData *sourceInfo);
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo, SourceIndexData *sourceIndexInfo);
gl::Error applyIndexBuffer(const gl::Data &data,
const GLvoid *indices,
GLsizei count,
GLenum mode,
GLenum type,
TranslatedIndexData *indexInfo,
SourceIndexData *sourceIndexInfo) override;
void applyTransformFeedbackBuffers(const gl::State &state) override;
......@@ -243,14 +249,13 @@ class Renderer9 : public RendererD3D
GLenum mode,
GLsizei count,
GLsizei instances) override;
gl::Error drawElementsImpl(GLenum mode,
gl::Error drawElementsImpl(const gl::Data &data,
const TranslatedIndexData &indexInfo,
GLenum mode,
GLsizei count,
GLenum type,
const GLvoid *indices,
gl::Buffer *elementArrayBuffer,
const TranslatedIndexData &indexInfo,
GLsizei instances,
bool usesPointSize) override;
GLsizei instances) override;
void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps,
gl::Extensions *outExtensions,
......
......@@ -159,7 +159,8 @@ void IndexDataManagerPerfTest::step(float dt, double totalTime)
{
mIndexBuffer.getIndexRange(GL_UNSIGNED_SHORT, 0, mIndexCount, false,
&translatedIndexData.indexRange);
mIndexDataManager.prepareIndexData(GL_UNSIGNED_SHORT, mIndexCount, &mIndexBuffer, nullptr, &translatedIndexData, &sourceIndexData);
mIndexDataManager.prepareIndexData(GL_UNSIGNED_SHORT, mIndexCount, &mIndexBuffer, nullptr,
&translatedIndexData, &sourceIndexData, false);
}
if (mTimer->getElapsedTime() >= 5.0)
......
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