Commit 0d3537c2 by Jamie Madill

D3D11: Implement ES3 primitive restart with line loops.

Unpack the index data into line strips, which can result in a dynamically number of indices. To this end use a scratch vector in Renderer11 so we don't end up allocating memory every draw call. BUG=angleproject:597 Change-Id: Id3270611023cb6d163cd024e078d30ba5556e2ad Reviewed-on: https://chromium-review.googlesource.com/310500Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 4dd1e55f
...@@ -225,6 +225,98 @@ void SetTriangleFanIndices(GLuint *destPtr, size_t numTris) ...@@ -225,6 +225,98 @@ void SetTriangleFanIndices(GLuint *destPtr, size_t numTris)
} }
template <typename T> template <typename T>
void CopyLineLoopIndicesWithRestart(const GLvoid *indices,
size_t count,
GLenum indexType,
std::vector<GLuint> *bufferOut)
{
GLuint restartIndex = gl::GetPrimitiveRestartIndex(indexType);
GLuint d3dRestartIndex = static_cast<GLuint>(d3d11::GetPrimitiveRestartIndex());
const T *srcPtr = static_cast<const T *>(indices);
Optional<GLuint> currentLoopStart;
bufferOut->clear();
for (size_t indexIdx = 0; indexIdx < count; ++indexIdx)
{
GLuint value = static_cast<GLuint>(srcPtr[indexIdx]);
if (value == restartIndex)
{
if (currentLoopStart.valid())
{
bufferOut->push_back(currentLoopStart.value());
bufferOut->push_back(d3dRestartIndex);
currentLoopStart.reset();
}
}
else
{
bufferOut->push_back(value);
if (!currentLoopStart.valid())
{
currentLoopStart = value;
}
}
}
if (currentLoopStart.valid())
{
bufferOut->push_back(currentLoopStart.value());
}
}
void GetLineLoopIndices(const GLvoid *indices,
GLenum indexType,
GLuint count,
bool usePrimitiveRestartFixedIndex,
std::vector<GLuint> *bufferOut)
{
if (indexType != GL_NONE && usePrimitiveRestartFixedIndex)
{
switch (indexType)
{
case GL_UNSIGNED_BYTE:
CopyLineLoopIndicesWithRestart<GLubyte>(indices, count, indexType, bufferOut);
break;
case GL_UNSIGNED_SHORT:
CopyLineLoopIndicesWithRestart<GLushort>(indices, count, indexType, bufferOut);
break;
case GL_UNSIGNED_INT:
CopyLineLoopIndicesWithRestart<GLuint>(indices, count, indexType, bufferOut);
break;
default:
UNREACHABLE();
break;
}
return;
}
// For non-primitive-restart draws, the index count is static.
bufferOut->resize(static_cast<size_t>(count) + 1);
switch (indexType)
{
// Non-indexed draw
case GL_NONE:
SetLineLoopIndices(&(*bufferOut)[0], count);
break;
case GL_UNSIGNED_BYTE:
CopyLineLoopIndices<GLubyte>(indices, &(*bufferOut)[0], count);
break;
case GL_UNSIGNED_SHORT:
CopyLineLoopIndices<GLushort>(indices, &(*bufferOut)[0], count);
break;
case GL_UNSIGNED_INT:
CopyLineLoopIndices<GLuint>(indices, &(*bufferOut)[0], count);
break;
default:
UNREACHABLE();
break;
}
}
template <typename T>
void CopyTriangleFanIndices(const GLvoid *indices, GLuint *destPtr, size_t numTris) void CopyTriangleFanIndices(const GLvoid *indices, GLuint *destPtr, size_t numTris)
{ {
const T *srcPtr = static_cast<const T *>(indices); const T *srcPtr = static_cast<const T *>(indices);
...@@ -1791,7 +1883,7 @@ gl::Error Renderer11::drawArraysImpl(const gl::Data &data, ...@@ -1791,7 +1883,7 @@ gl::Error Renderer11::drawArraysImpl(const gl::Data &data,
if (mode == GL_LINE_LOOP) if (mode == GL_LINE_LOOP)
{ {
return drawLineLoop(data, count, GL_NONE, nullptr, 0); return drawLineLoop(data, count, GL_NONE, nullptr, nullptr);
} }
if (mode == GL_TRIANGLE_FAN) if (mode == GL_TRIANGLE_FAN)
...@@ -1834,7 +1926,7 @@ gl::Error Renderer11::drawElementsImpl(const gl::Data &data, ...@@ -1834,7 +1926,7 @@ gl::Error Renderer11::drawElementsImpl(const gl::Data &data,
if (mode == GL_LINE_LOOP) if (mode == GL_LINE_LOOP)
{ {
return drawLineLoop(data, count, type, indices, minIndex); return drawLineLoop(data, count, type, indices, &indexInfo);
} }
if (mode == GL_TRIANGLE_FAN) if (mode == GL_TRIANGLE_FAN)
...@@ -1874,12 +1966,14 @@ gl::Error Renderer11::drawElementsImpl(const gl::Data &data, ...@@ -1874,12 +1966,14 @@ gl::Error Renderer11::drawElementsImpl(const gl::Data &data,
gl::Error Renderer11::drawLineLoop(const gl::Data &data, gl::Error Renderer11::drawLineLoop(const gl::Data &data,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indexPointer,
int minIndex) const TranslatedIndexData *indexInfo)
{ {
gl::VertexArray *vao = data.state->getVertexArray(); gl::VertexArray *vao = data.state->getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get(); gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
const GLvoid *indices = indexPointer;
// Get the raw indices for an indexed draw // Get the raw indices for an indexed draw
if (type != GL_NONE && elementArrayBuffer) if (type != GL_NONE && elementArrayBuffer)
{ {
...@@ -1915,7 +2009,11 @@ gl::Error Renderer11::drawLineLoop(const gl::Data &data, ...@@ -1915,7 +2009,11 @@ gl::Error Renderer11::drawLineLoop(const gl::Data &data,
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required.");
} }
const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned int); GetLineLoopIndices(indices, type, static_cast<GLuint>(count),
data.state->isPrimitiveRestartEnabled(), &mScratchIndexDataBuffer);
unsigned int spaceNeeded =
static_cast<unsigned int>(sizeof(GLuint) * mScratchIndexDataBuffer.size());
gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
if (error.isError()) if (error.isError())
{ {
...@@ -1930,35 +2028,9 @@ gl::Error Renderer11::drawLineLoop(const gl::Data &data, ...@@ -1930,35 +2028,9 @@ gl::Error Renderer11::drawLineLoop(const gl::Data &data,
return error; return error;
} }
unsigned int *mappedInts = reinterpret_cast<unsigned int *>(mappedMemory); // Copy over the converted index data.
unsigned int indexBufferOffset = offset; memcpy(mappedMemory, &mScratchIndexDataBuffer[0],
sizeof(GLuint) * mScratchIndexDataBuffer.size());
if (type != GL_NONE && data.state->isPrimitiveRestartEnabled())
{
// TODO(jmadill): Implement this.
return gl::Error(GL_INVALID_OPERATION,
"Primitive restart not yet supported for line loops.");
}
// Non-indexed draw
switch (type)
{
case GL_NONE:
SetLineLoopIndices(mappedInts, count);
break;
case GL_UNSIGNED_BYTE:
CopyLineLoopIndices<GLubyte>(indices, mappedInts, count);
break;
case GL_UNSIGNED_SHORT:
CopyLineLoopIndices<GLushort>(indices, mappedInts, count);
break;
case GL_UNSIGNED_INT:
CopyLineLoopIndices<GLuint>(indices, mappedInts, count);
break;
default:
UNREACHABLE();
break;
}
error = mLineLoopIB->unmapBuffer(); error = mLineLoopIB->unmapBuffer();
if (error.isError()) if (error.isError())
...@@ -1970,15 +2042,18 @@ gl::Error Renderer11::drawLineLoop(const gl::Data &data, ...@@ -1970,15 +2042,18 @@ gl::Error Renderer11::drawLineLoop(const gl::Data &data,
ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer();
DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat();
if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat ||
mAppliedIBOffset != offset)
{ {
mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, indexBufferOffset); mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, offset);
mAppliedIB = d3dIndexBuffer; mAppliedIB = d3dIndexBuffer;
mAppliedIBFormat = indexFormat; mAppliedIBFormat = indexFormat;
mAppliedIBOffset = indexBufferOffset; mAppliedIBOffset = offset;
} }
mDeviceContext->DrawIndexed(count + 1, 0, -minIndex); INT baseVertexLocation = (indexInfo ? -static_cast<int>(indexInfo->indexRange.start) : 0);
UINT indexCount = static_cast<UINT>(mScratchIndexDataBuffer.size());
mDeviceContext->DrawIndexed(indexCount, 0, baseVertexLocation);
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
......
...@@ -300,7 +300,7 @@ class Renderer11 : public RendererD3D ...@@ -300,7 +300,7 @@ class Renderer11 : public RendererD3D
GLsizei count, GLsizei count,
GLenum type, GLenum type,
const GLvoid *indices, const GLvoid *indices,
int minIndex); const TranslatedIndexData *indexInfo);
gl::Error drawTriangleFan(const gl::Data &data, gl::Error drawTriangleFan(const gl::Data &data,
GLsizei count, GLsizei count,
GLenum type, GLenum type,
...@@ -498,6 +498,8 @@ class Renderer11 : public RendererD3D ...@@ -498,6 +498,8 @@ class Renderer11 : public RendererD3D
char mDescription[128]; char mDescription[128];
DXGIFactory *mDxgiFactory; DXGIFactory *mDxgiFactory;
ID3D11Debug *mDebug; ID3D11Debug *mDebug;
std::vector<GLuint> mScratchIndexDataBuffer;
}; };
} }
......
...@@ -1300,6 +1300,11 @@ void GenerateInitialTextureData(GLint internalFormat, const Renderer11DeviceCaps ...@@ -1300,6 +1300,11 @@ void GenerateInitialTextureData(GLint internalFormat, const Renderer11DeviceCaps
} }
} }
UINT GetPrimitiveRestartIndex()
{
return std::numeric_limits<UINT>::max();
}
void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v) void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v)
{ {
vertex->x = x; vertex->x = x;
......
...@@ -71,6 +71,8 @@ void GenerateInitialTextureData(GLint internalFormat, const Renderer11DeviceCaps ...@@ -71,6 +71,8 @@ void GenerateInitialTextureData(GLint internalFormat, const Renderer11DeviceCaps
GLuint mipLevels, std::vector<D3D11_SUBRESOURCE_DATA> *outSubresourceData, GLuint mipLevels, std::vector<D3D11_SUBRESOURCE_DATA> *outSubresourceData,
std::vector< std::vector<BYTE> > *outData); std::vector< std::vector<BYTE> > *outData);
UINT GetPrimitiveRestartIndex();
struct PositionTexCoordVertex struct PositionTexCoordVertex
{ {
float x, y; float x, y;
......
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