Commit 08b56293 by James Dong Committed by Commit Bot

Vulkan: add LINE_LOOP with primitive restart

Adds support for GL_LINE_LOOP with primitive restart. Bug: angleproject:3215 Change-Id: Ief1bdf15ef9b108dba025eaf4ce580bba54af623 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1649351Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 2c49d0b0
......@@ -75,6 +75,20 @@ IndexRange ComputeIndexRange(DrawElementsType indexType,
// Get the primitive restart index value for the given index type.
GLuint GetPrimitiveRestartIndex(DrawElementsType indexType);
// Get the primitive restart index value with the given C++ type.
template <typename T>
constexpr T GetPrimitiveRestartIndexFromType()
{
return std::numeric_limits<T>::max();
}
static_assert(GetPrimitiveRestartIndexFromType<uint8_t>() == 0xFF,
"verify restart index for uint8_t values");
static_assert(GetPrimitiveRestartIndexFromType<uint16_t>() == 0xFFFF,
"verify restart index for uint8_t values");
static_assert(GetPrimitiveRestartIndexFromType<uint32_t>() == 0xFFFFFFFF,
"verify restart index for uint8_t values");
bool IsTriangleMode(PrimitiveMode drawMode);
namespace priv
......
......@@ -145,48 +145,6 @@ void SetTriangleFanIndices(GLuint *destPtr, size_t numTris)
}
}
template <typename T>
void CopyLineLoopIndicesWithRestart(const void *indices,
size_t count,
gl::DrawElementsType 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 void *indices,
gl::DrawElementsType indexType,
GLuint count,
......@@ -195,16 +153,25 @@ void GetLineLoopIndices(const void *indices,
{
if (indexType != gl::DrawElementsType::InvalidEnum && usePrimitiveRestartFixedIndex)
{
size_t indexCount = GetLineLoopWithRestartIndexCount(indexType, count,
static_cast<const uint8_t *>(indices));
bufferOut->resize(indexCount);
switch (indexType)
{
case gl::DrawElementsType::UnsignedByte:
CopyLineLoopIndicesWithRestart<GLubyte>(indices, count, indexType, bufferOut);
CopyLineLoopIndicesWithRestart<GLubyte, GLuint>(
count, static_cast<const uint8_t *>(indices),
reinterpret_cast<uint8_t *>(bufferOut->data()));
break;
case gl::DrawElementsType::UnsignedShort:
CopyLineLoopIndicesWithRestart<GLushort>(indices, count, indexType, bufferOut);
CopyLineLoopIndicesWithRestart<GLushort, GLuint>(
count, static_cast<const uint8_t *>(indices),
reinterpret_cast<uint8_t *>(bufferOut->data()));
break;
case gl::DrawElementsType::UnsignedInt:
CopyLineLoopIndicesWithRestart<GLuint>(indices, count, indexType, bufferOut);
CopyLineLoopIndicesWithRestart<GLuint, GLuint>(
count, static_cast<const uint8_t *>(indices),
reinterpret_cast<uint8_t *>(bufferOut->data()));
break;
default:
UNREACHABLE();
......
......@@ -17,6 +17,7 @@
#include <map>
#include "common/angleutils.h"
#include "common/utilities.h"
#include "libANGLE/angletypes.h"
namespace angle
......@@ -307,6 +308,92 @@ gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &r
// Helper method to intialize a FeatureSet with overrides from the DisplayState
void OverrideFeaturesWithDisplayState(angle::FeatureSetBase *features,
const egl::DisplayState &state);
template <typename In>
size_t LineLoopRestartIndexCountHelper(GLsizei indexCount, const uint8_t *srcPtr)
{
constexpr In restartIndex = gl::GetPrimitiveRestartIndexFromType<In>();
const In *inIndices = reinterpret_cast<const In *>(srcPtr);
size_t numIndices = 0;
// See CopyLineLoopIndicesWithRestart() below for more info on how
// numIndices is calculated.
GLsizei loopStartIndex = 0;
for (GLsizei curIndex = 0; curIndex < indexCount; curIndex++)
{
In vertex = inIndices[curIndex];
if (vertex != restartIndex)
{
numIndices++;
}
else
{
if (curIndex > loopStartIndex)
{
numIndices += 2;
}
loopStartIndex = curIndex + 1;
}
}
if (indexCount > loopStartIndex)
{
numIndices++;
}
return numIndices;
}
inline size_t GetLineLoopWithRestartIndexCount(gl::DrawElementsType glIndexType,
GLsizei indexCount,
const uint8_t *srcPtr)
{
switch (glIndexType)
{
case gl::DrawElementsType::UnsignedByte:
return LineLoopRestartIndexCountHelper<uint8_t>(indexCount, srcPtr);
case gl::DrawElementsType::UnsignedShort:
return LineLoopRestartIndexCountHelper<uint16_t>(indexCount, srcPtr);
case gl::DrawElementsType::UnsignedInt:
return LineLoopRestartIndexCountHelper<uint32_t>(indexCount, srcPtr);
default:
UNREACHABLE();
return 0;
}
}
// Writes the line-strip vertices for a line loop to outPtr,
// where outLimit is calculated as in GetPrimitiveRestartIndexCount.
template <typename In, typename Out>
void CopyLineLoopIndicesWithRestart(GLsizei indexCount, const uint8_t *srcPtr, uint8_t *outPtr)
{
constexpr In restartIndex = gl::GetPrimitiveRestartIndexFromType<In>();
constexpr Out outRestartIndex = gl::GetPrimitiveRestartIndexFromType<Out>();
const In *inIndices = reinterpret_cast<const In *>(srcPtr);
Out *outIndices = reinterpret_cast<Out *>(outPtr);
GLsizei loopStartIndex = 0;
for (GLsizei curIndex = 0; curIndex < indexCount; curIndex++)
{
In vertex = inIndices[curIndex];
if (vertex != restartIndex)
{
*(outIndices++) = static_cast<Out>(vertex);
}
else
{
if (curIndex > loopStartIndex)
{
// Emit an extra vertex only if the loop is not empty.
*(outIndices++) = inIndices[loopStartIndex];
// Then restart the strip.
*(outIndices++) = outRestartIndex;
}
loopStartIndex = curIndex + 1;
}
}
if (indexCount > loopStartIndex)
{
// Close the last loop if not empty.
*(outIndices++) = inIndices[loopStartIndex];
}
}
} // namespace rx
#endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_
......@@ -509,10 +509,11 @@ angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context,
GLsizei vertexOrIndexCount,
gl::DrawElementsType indexTypeOrInvalid,
const void *indices,
vk::CommandBuffer **commandBufferOut)
vk::CommandBuffer **commandBufferOut,
size_t *numIndicesOut)
{
ANGLE_TRY(mVertexArray->handleLineLoop(this, firstVertex, vertexOrIndexCount,
indexTypeOrInvalid, indices));
indexTypeOrInvalid, indices, numIndicesOut));
mDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
mCurrentDrawElementsType = indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum
? indexTypeOrInvalid
......@@ -1114,9 +1115,10 @@ angle::Result ContextVk::drawArrays(const gl::Context *context,
if (mode == gl::PrimitiveMode::LineLoop)
{
size_t numIndices;
ANGLE_TRY(setupLineLoopDraw(context, mode, first, count, gl::DrawElementsType::InvalidEnum,
nullptr, &commandBuffer));
vk::LineLoopHelper::Draw(clampedVertexCount, commandBuffer);
nullptr, &commandBuffer, &numIndices));
vk::LineLoopHelper::Draw(numIndices, commandBuffer);
}
else
{
......@@ -1157,8 +1159,10 @@ angle::Result ContextVk::drawElements(const gl::Context *context,
vk::CommandBuffer *commandBuffer = nullptr;
if (mode == gl::PrimitiveMode::LineLoop)
{
ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &commandBuffer));
vk::LineLoopHelper::Draw(count, commandBuffer);
size_t indexCount;
ANGLE_TRY(
setupLineLoopDraw(context, mode, 0, count, type, indices, &commandBuffer, &indexCount));
vk::LineLoopHelper::Draw(indexCount, commandBuffer);
}
else
{
......
......@@ -352,7 +352,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
GLsizei vertexOrIndexCount,
gl::DrawElementsType indexTypeOrInvalid,
const void *indices,
vk::CommandBuffer **commandBufferOut);
vk::CommandBuffer **commandBufferOut,
size_t *numIndicesOut);
void updateViewport(FramebufferVk *framebufferVk,
const gl::Rectangle &viewport,
......
......@@ -601,7 +601,8 @@ angle::Result VertexArrayVk::handleLineLoop(ContextVk *contextVk,
GLint firstVertex,
GLsizei vertexOrIndexCount,
gl::DrawElementsType indexTypeOrInvalid,
const void *indices)
const void *indices,
size_t *indexCountOut)
{
if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum)
{
......@@ -615,7 +616,7 @@ angle::Result VertexArrayVk::handleLineLoop(ContextVk *contextVk,
ANGLE_TRY(mLineLoopHelper.streamIndices(
contextVk, indexTypeOrInvalid, vertexOrIndexCount,
reinterpret_cast<const uint8_t *>(indices), &mCurrentElementArrayBuffer,
&mCurrentElementArrayBufferOffset));
&mCurrentElementArrayBufferOffset, indexCountOut));
}
else
{
......@@ -624,7 +625,7 @@ angle::Result VertexArrayVk::handleLineLoop(ContextVk *contextVk,
BufferVk *elementArrayBufferVk = vk::GetImpl(elementArrayBuffer);
ANGLE_TRY(mLineLoopHelper.getIndexBufferForElementArrayBuffer(
contextVk, elementArrayBufferVk, indexTypeOrInvalid, vertexOrIndexCount, offset,
&mCurrentElementArrayBuffer, &mCurrentElementArrayBufferOffset));
&mCurrentElementArrayBuffer, &mCurrentElementArrayBufferOffset, indexCountOut));
}
}
......@@ -651,6 +652,7 @@ angle::Result VertexArrayVk::handleLineLoop(ContextVk *contextVk,
mLineLoopBufferFirstIndex = firstVertex;
mLineLoopBufferLastIndex = lastVertex;
}
*indexCountOut = vertexOrIndexCount + 1;
return angle::Result::Continue;
}
......
......@@ -48,7 +48,8 @@ class VertexArrayVk : public VertexArrayImpl
GLint firstVertex,
GLsizei vertexOrIndexCount,
gl::DrawElementsType indexTypeOrInvalid,
const void *indices);
const void *indices,
size_t *indexCountOut);
const gl::AttribArray<VkBuffer> &getCurrentArrayBufferHandles() const
{
......
......@@ -10,6 +10,7 @@
#include "common/utilities.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/renderer_utils.h"
#include "libANGLE/renderer/vulkan/BufferVk.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
......@@ -212,6 +213,27 @@ VkImageCreateFlags GetImageCreateFlags(gl::TextureType textureType)
return 0;
}
}
void HandlePrimitiveRestart(gl::DrawElementsType glIndexType,
GLsizei indexCount,
const uint8_t *srcPtr,
uint8_t *outPtr)
{
switch (glIndexType)
{
case gl::DrawElementsType::UnsignedByte:
CopyLineLoopIndicesWithRestart<uint8_t, uint16_t>(indexCount, srcPtr, outPtr);
break;
case gl::DrawElementsType::UnsignedShort:
CopyLineLoopIndicesWithRestart<uint16_t, uint16_t>(indexCount, srcPtr, outPtr);
break;
case gl::DrawElementsType::UnsignedInt:
CopyLineLoopIndicesWithRestart<uint32_t, uint32_t>(indexCount, srcPtr, outPtr);
break;
default:
UNREACHABLE();
}
}
} // anonymous namespace
// DynamicBuffer implementation.
......@@ -1017,9 +1039,11 @@ angle::Result LineLoopHelper::getIndexBufferForElementArrayBuffer(ContextVk *con
int indexCount,
intptr_t elementArrayOffset,
vk::BufferHelper **bufferOut,
VkDeviceSize *bufferOffsetOut)
VkDeviceSize *bufferOffsetOut,
size_t *indexCountOut)
{
if (glIndexType == gl::DrawElementsType::UnsignedByte)
if (glIndexType == gl::DrawElementsType::UnsignedByte ||
contextVk->getState().isPrimitiveRestartEnabled())
{
TRACE_EVENT0("gpu.angle", "LineLoopHelper::getIndexBufferForElementArrayBuffer");
// Needed before reading buffer or we could get stale data.
......@@ -1029,11 +1053,13 @@ angle::Result LineLoopHelper::getIndexBufferForElementArrayBuffer(ContextVk *con
ANGLE_TRY(elementArrayBufferVk->mapImpl(contextVk, &srcDataMapping));
ANGLE_TRY(streamIndices(contextVk, glIndexType, indexCount,
static_cast<const uint8_t *>(srcDataMapping) + elementArrayOffset,
bufferOut, bufferOffsetOut));
bufferOut, bufferOffsetOut, indexCountOut));
ANGLE_TRY(elementArrayBufferVk->unmapImpl(contextVk));
return angle::Result::Continue;
}
*indexCountOut = indexCount + 1;
VkIndexType indexType = gl_vk::kIndexTypeMap[glIndexType];
ASSERT(indexType == VK_INDEX_TYPE_UINT16 || indexType == VK_INDEX_TYPE_UINT32);
uint32_t *indices = nullptr;
......@@ -1067,35 +1093,49 @@ angle::Result LineLoopHelper::streamIndices(ContextVk *contextVk,
GLsizei indexCount,
const uint8_t *srcPtr,
vk::BufferHelper **bufferOut,
VkDeviceSize *bufferOffsetOut)
VkDeviceSize *bufferOffsetOut,
size_t *indexCountOut)
{
VkIndexType indexType = gl_vk::kIndexTypeMap[glIndexType];
uint8_t *indices = nullptr;
auto unitSize = (indexType == VK_INDEX_TYPE_UINT16 ? sizeof(uint16_t) : sizeof(uint32_t));
size_t allocateBytes = unitSize * (indexCount + 1);
size_t numOutIndices = static_cast<size_t>(indexCount) + 1;
if (contextVk->getState().isPrimitiveRestartEnabled())
{
numOutIndices = GetLineLoopWithRestartIndexCount(glIndexType, indexCount, srcPtr);
}
*indexCountOut = numOutIndices;
size_t allocateBytes = unitSize * numOutIndices;
ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes,
reinterpret_cast<uint8_t **>(&indices), nullptr,
bufferOffsetOut, nullptr));
*bufferOut = mDynamicIndexBuffer.getCurrentBuffer();
if (glIndexType == gl::DrawElementsType::UnsignedByte)
if (contextVk->getState().isPrimitiveRestartEnabled())
{
// Vulkan doesn't support uint8 index types, so we need to emulate it.
ASSERT(indexType == VK_INDEX_TYPE_UINT16);
uint16_t *indicesDst = reinterpret_cast<uint16_t *>(indices);
for (int i = 0; i < indexCount; i++)
{
indicesDst[i] = srcPtr[i];
}
indicesDst[indexCount] = srcPtr[0];
HandlePrimitiveRestart(glIndexType, indexCount, srcPtr, indices);
}
else
{
memcpy(indices, srcPtr, unitSize * indexCount);
memcpy(indices + unitSize * indexCount, srcPtr, unitSize);
if (glIndexType == gl::DrawElementsType::UnsignedByte)
{
// Vulkan doesn't support uint8 index types, so we need to emulate it.
ASSERT(indexType == VK_INDEX_TYPE_UINT16);
uint16_t *indicesDst = reinterpret_cast<uint16_t *>(indices);
for (int i = 0; i < indexCount; i++)
{
indicesDst[i] = srcPtr[i];
}
indicesDst[indexCount] = srcPtr[0];
}
else
{
memcpy(indices, srcPtr, unitSize * indexCount);
memcpy(indices + unitSize * indexCount, srcPtr, unitSize);
}
}
ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk));
......@@ -1116,8 +1156,7 @@ void LineLoopHelper::destroy(VkDevice device)
void LineLoopHelper::Draw(uint32_t count, vk::CommandBuffer *commandBuffer)
{
// Our first index is always 0 because that's how we set it up in createIndexBuffer*.
// Note: this could theoretically overflow and wrap to zero.
commandBuffer->drawIndexed(count + 1);
commandBuffer->drawIndexed(count);
}
// BufferHelper implementation.
......
......@@ -392,14 +392,16 @@ class LineLoopHelper final : angle::NonCopyable
int indexCount,
intptr_t elementArrayOffset,
vk::BufferHelper **bufferOut,
VkDeviceSize *bufferOffsetOut);
VkDeviceSize *bufferOffsetOut,
size_t *indexCountOut);
angle::Result streamIndices(ContextVk *contextVk,
gl::DrawElementsType glIndexType,
GLsizei indexCount,
const uint8_t *srcPtr,
vk::BufferHelper **bufferOut,
VkDeviceSize *bufferOffsetOut);
VkDeviceSize *bufferOffsetOut,
size_t *indexCountOut);
void release(ContextVk *contextVk);
void destroy(VkDevice device);
......
......@@ -662,14 +662,30 @@
2950 VULKAN : dEQP-GLES3.functional.fbo.invalidate.* = SKIP
// - Primitive restart with line loops:
3215 VULKAN : dEQP-GLES3.functional.primitive_restart.basic.line_loop.* = SKIP
3215 VULKAN : dEQP-GLES3.functional.primitive_restart.duplicate_restarts.line_loop.* = SKIP
3215 VULKAN : dEQP-GLES3.functional.primitive_restart.end_restart.line_loop.* = SKIP
3215 VULKAN : dEQP-GLES3.functional.primitive_restart.end_restart_duplicate_restarts.line_loop.* = SKIP
3215 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart.line_loop.* = SKIP
3215 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart_duplicate_restarts.line_loop.* = SKIP
3215 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart_end_restart.line_loop.* = SKIP
3215 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart_end_restart_duplicate_restarts.line_loop.* = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.basic.line_loop.unsigned_byte.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.basic.line_loop.unsigned_short.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.basic.line_loop.unsigned_int.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.duplicate_restarts.line_loop.unsigned_byte.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.duplicate_restarts.line_loop.unsigned_short.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.duplicate_restarts.line_loop.unsigned_int.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.end_restart.line_loop.unsigned_byte.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.end_restart.line_loop.unsigned_short.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.end_restart.line_loop.unsigned_int.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.end_restart_duplicate_restarts.line_loop.unsigned_byte.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.end_restart_duplicate_restarts.line_loop.unsigned_short.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.end_restart_duplicate_restarts.line_loop.unsigned_int.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart.line_loop.unsigned_byte.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart.line_loop.unsigned_short.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart.line_loop.unsigned_int.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart_duplicate_restarts.line_loop.unsigned_byte.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart_duplicate_restarts.line_loop.unsigned_short.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart_duplicate_restarts.line_loop.unsigned_int.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart_end_restart.line_loop.unsigned_byte.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart_end_restart.line_loop.unsigned_short.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart_end_restart.line_loop.unsigned_int.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart_end_restart_duplicate_restarts.line_loop.unsigned_byte.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart_end_restart_duplicate_restarts.line_loop.unsigned_short.draw_elements_instanced = SKIP
2672 VULKAN : dEQP-GLES3.functional.primitive_restart.begin_restart_end_restart_duplicate_restarts.line_loop.unsigned_int.draw_elements_instanced = SKIP
// - BufferVk::copySubData:
2950 VULKAN : dEQP-GLES3.functional.negative_api.buffer.copy_buffer_sub_data = SKIP
......
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