Commit cb6176f3 by Le Hoang Quyen Committed by Commit Bot

Metal: Support tri-fan & line-loop with primitive restart

Triangle fan: - If primitive restart is NOT enabled and there is no active render pass, use Compute Shader to generate indices. - If primitive restart is enabled, use CPU to generate indices. Line loop: - If draw non-instanced without primitive restart, generate and draw only one additional last segment (fastest). - If draw instanced, primitive restart is NOT enabled, and there is no active render pass, use Compute Shader to generate indices (OK). - Otherwise, use CPU to generate indices (slowest). Also Disable OcclusionQueriesTest.ClearNotCounted failure on NVIDIA. Bug: angleproject:2634 Bug: angleproject:5307 Change-Id: Ia5529825807a964f5fcb2a4af8844778896cd42a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2435859 Commit-Queue: Le Hoang Quyen <le.hoang.q@gmail.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent 945791e1
...@@ -74,6 +74,12 @@ struct FeaturesMtl : FeatureSetBase ...@@ -74,6 +74,12 @@ struct FeaturesMtl : FeatureSetBase
Feature allowGenMultipleMipsPerPass = { Feature allowGenMultipleMipsPerPass = {
"gen_multiple_mips_per_pass", FeatureCategory::MetalFeatures, "gen_multiple_mips_per_pass", FeatureCategory::MetalFeatures,
"The renderer supports generating multiple mipmaps per pass", &members}; "The renderer supports generating multiple mipmaps per pass", &members};
Feature forceBufferGPUStorage = {
"force_buffer_gpu_storage_mtl", FeatureCategory::MetalFeatures,
"On systems that support both buffer's memory allocation on GPU and shared memory (such as "
"macOS), force using GPU memory allocation for buffers.",
&members};
}; };
} // namespace angle } // namespace angle
......
...@@ -18,13 +18,13 @@ ...@@ -18,13 +18,13 @@
"src/libANGLE/renderer/metal/shaders/format_autogen.h": "src/libANGLE/renderer/metal/shaders/format_autogen.h":
"b1d6512b904a7eb151b0095b7898b0e5", "b1d6512b904a7eb151b0095b7898b0e5",
"src/libANGLE/renderer/metal/shaders/gen_indices.metal": "src/libANGLE/renderer/metal/shaders/gen_indices.metal":
"add45aa44305b1a64c4bb8ece1e3d2fc", "06e2b6f259fe019b46e2a9710eb11bff",
"src/libANGLE/renderer/metal/shaders/gen_mipmap.metal": "src/libANGLE/renderer/metal/shaders/gen_mipmap.metal":
"54dca94c48bead446624079070b9b309", "54dca94c48bead446624079070b9b309",
"src/libANGLE/renderer/metal/shaders/gen_mtl_internal_shaders.py": "src/libANGLE/renderer/metal/shaders/gen_mtl_internal_shaders.py":
"b48af61c8b02dda646b4c8febce50227", "b48af61c8b02dda646b4c8febce50227",
"src/libANGLE/renderer/metal/shaders/mtl_default_shaders_src_autogen.inc": "src/libANGLE/renderer/metal/shaders/mtl_default_shaders_src_autogen.inc":
"a0164451469303a462fd777c289c36ee", "0658278106de1fe5147e1367ecc896b9",
"src/libANGLE/renderer/metal/shaders/visibility.metal": "src/libANGLE/renderer/metal/shaders/visibility.metal":
"b82aa740cf4b0aed606aacef1024beea" "b82aa740cf4b0aed606aacef1024beea"
} }
\ No newline at end of file
...@@ -57,10 +57,14 @@ struct VertexConversionBufferMtl : public ConversionBufferMtl ...@@ -57,10 +57,14 @@ struct VertexConversionBufferMtl : public ConversionBufferMtl
struct IndexConversionBufferMtl : public ConversionBufferMtl struct IndexConversionBufferMtl : public ConversionBufferMtl
{ {
IndexConversionBufferMtl(ContextMtl *context, gl::DrawElementsType elemType, size_t offsetIn); IndexConversionBufferMtl(ContextMtl *context,
gl::DrawElementsType elemType,
bool primitiveRestartEnabled,
size_t offsetIn);
const gl::DrawElementsType elemType; const gl::DrawElementsType elemType;
const size_t offset; const size_t offset;
bool primitiveRestartEnabled;
}; };
struct UniformConversionBufferMtl : public ConversionBufferMtl struct UniformConversionBufferMtl : public ConversionBufferMtl
...@@ -143,6 +147,7 @@ class BufferMtl : public BufferImpl, public BufferHolderMtl ...@@ -143,6 +147,7 @@ class BufferMtl : public BufferImpl, public BufferHolderMtl
IndexConversionBufferMtl *getIndexConversionBuffer(ContextMtl *context, IndexConversionBufferMtl *getIndexConversionBuffer(ContextMtl *context,
gl::DrawElementsType elemType, gl::DrawElementsType elemType,
bool primitiveRestartEnabled,
size_t offset); size_t offset);
ConversionBufferMtl *getUniformConversionBuffer(ContextMtl *context, size_t offset); ConversionBufferMtl *getUniformConversionBuffer(ContextMtl *context, size_t offset);
......
...@@ -55,12 +55,14 @@ ConversionBufferMtl::~ConversionBufferMtl() = default; ...@@ -55,12 +55,14 @@ ConversionBufferMtl::~ConversionBufferMtl() = default;
// IndexConversionBufferMtl implementation. // IndexConversionBufferMtl implementation.
IndexConversionBufferMtl::IndexConversionBufferMtl(ContextMtl *context, IndexConversionBufferMtl::IndexConversionBufferMtl(ContextMtl *context,
gl::DrawElementsType elemTypeIn, gl::DrawElementsType elemTypeIn,
bool primitiveRestartEnabledIn,
size_t offsetIn) size_t offsetIn)
: ConversionBufferMtl(context, : ConversionBufferMtl(context,
kConvertedElementArrayBufferInitialSize, kConvertedElementArrayBufferInitialSize,
mtl::kIndexBufferOffsetAlignment), mtl::kIndexBufferOffsetAlignment),
elemType(elemTypeIn), elemType(elemTypeIn),
offset(offsetIn) offset(offsetIn),
primitiveRestartEnabled(primitiveRestartEnabledIn)
{} {}
// UniformConversionBufferMtl implementation // UniformConversionBufferMtl implementation
...@@ -331,17 +333,19 @@ ConversionBufferMtl *BufferMtl::getVertexConversionBuffer(ContextMtl *context, ...@@ -331,17 +333,19 @@ ConversionBufferMtl *BufferMtl::getVertexConversionBuffer(ContextMtl *context,
IndexConversionBufferMtl *BufferMtl::getIndexConversionBuffer(ContextMtl *context, IndexConversionBufferMtl *BufferMtl::getIndexConversionBuffer(ContextMtl *context,
gl::DrawElementsType elemType, gl::DrawElementsType elemType,
bool primitiveRestartEnabled,
size_t offset) size_t offset)
{ {
for (auto &buffer : mIndexConversionBuffers) for (auto &buffer : mIndexConversionBuffers)
{ {
if (buffer.elemType == elemType && buffer.offset == offset) if (buffer.elemType == elemType && buffer.offset == offset &&
buffer.primitiveRestartEnabled == primitiveRestartEnabled)
{ {
return &buffer; return &buffer;
} }
} }
mIndexConversionBuffers.emplace_back(context, elemType, offset); mIndexConversionBuffers.emplace_back(context, elemType, primitiveRestartEnabled, offset);
return &mIndexConversionBuffers.back(); return &mIndexConversionBuffers.back();
} }
......
...@@ -368,13 +368,6 @@ class ContextMtl : public ContextImpl, public mtl::Context ...@@ -368,13 +368,6 @@ class ContextMtl : public ContextImpl, public mtl::Context
gl::DrawElementsType indexTypeOrNone, gl::DrawElementsType indexTypeOrNone,
const void *indices, const void *indices,
bool xfbPass); bool xfbPass);
angle::Result genLineLoopLastSegment(const gl::Context *context,
GLint firstVertex,
GLsizei vertexOrIndexCount,
GLsizei instanceCount,
gl::DrawElementsType indexTypeOrNone,
const void *indices,
mtl::BufferRef *lastSegmentIndexBufferOut);
angle::Result drawTriFanArrays(const gl::Context *context, angle::Result drawTriFanArrays(const gl::Context *context,
GLint first, GLint first,
...@@ -394,6 +387,23 @@ class ContextMtl : public ContextImpl, public mtl::Context ...@@ -394,6 +387,23 @@ class ContextMtl : public ContextImpl, public mtl::Context
const void *indices, const void *indices,
GLsizei instances); GLsizei instances);
angle::Result drawLineLoopArraysNonInstanced(const gl::Context *context,
GLint first,
GLsizei count);
angle::Result drawLineLoopArrays(const gl::Context *context,
GLint first,
GLsizei count,
GLsizei instances);
angle::Result drawLineLoopElementsNonInstancedNoPrimitiveRestart(const gl::Context *context,
GLsizei count,
gl::DrawElementsType type,
const void *indices);
angle::Result drawLineLoopElements(const gl::Context *context,
GLsizei count,
gl::DrawElementsType type,
const void *indices,
GLsizei instances);
angle::Result drawArraysImpl(const gl::Context *context, angle::Result drawArraysImpl(const gl::Context *context,
gl::PrimitiveMode mode, gl::PrimitiveMode mode,
GLint first, GLint first,
...@@ -540,6 +550,7 @@ class ContextMtl : public ContextImpl, public mtl::Context ...@@ -540,6 +550,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
// Lineloop and TriFan index buffer // Lineloop and TriFan index buffer
mtl::BufferPool mLineLoopIndexBuffer; mtl::BufferPool mLineLoopIndexBuffer;
mtl::BufferPool mLineLoopLastSegmentIndexBuffer;
mtl::BufferPool mTriFanIndexBuffer; mtl::BufferPool mTriFanIndexBuffer;
// one buffer can be reused for any starting vertex in DrawArrays() // one buffer can be reused for any starting vertex in DrawArrays()
mtl::BufferRef mTriFanArraysIndexBuffer; mtl::BufferRef mTriFanArraysIndexBuffer;
......
...@@ -63,33 +63,6 @@ constexpr uint32_t kMaxTriFanLineLoopBuffersPerFrame = 10; ...@@ -63,33 +63,6 @@ constexpr uint32_t kMaxTriFanLineLoopBuffersPerFrame = 10;
} \ } \
} }
angle::Result TriangleFanBoundCheck(ContextMtl *context, size_t numTris)
{
bool indexCheck =
(numTris > std::numeric_limits<unsigned int>::max() / (sizeof(unsigned int) * 3));
ANGLE_CHECK(context, !indexCheck,
"Failed to create a scratch index buffer for GL_TRIANGLE_FAN, "
"too many indices required.",
GL_OUT_OF_MEMORY);
return angle::Result::Continue;
}
angle::Result GetTriangleFanIndicesCount(ContextMtl *context,
GLsizei vetexCount,
uint32_t *numElemsOut)
{
size_t numTris = vetexCount - 2;
ANGLE_TRY(TriangleFanBoundCheck(context, numTris));
size_t numIndices = numTris * 3;
ANGLE_CHECK(context, numIndices <= std::numeric_limits<uint32_t>::max(),
"Failed to create a scratch index buffer for GL_TRIANGLE_FAN, "
"too many indices required.",
GL_OUT_OF_MEMORY);
*numElemsOut = static_cast<uint32_t>(numIndices);
return angle::Result::Continue;
}
angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context, angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context,
GLsizei vertexCount, GLsizei vertexCount,
mtl::BufferPool *pool, mtl::BufferPool *pool,
...@@ -98,7 +71,7 @@ angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context, ...@@ -98,7 +71,7 @@ angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context,
uint32_t *numElemsOut) uint32_t *numElemsOut)
{ {
uint32_t numIndices; uint32_t numIndices;
ANGLE_TRY(GetTriangleFanIndicesCount(context, vertexCount, &numIndices)); ANGLE_TRY(mtl::GetTriangleFanIndicesCount(context, vertexCount, &numIndices));
size_t offset; size_t offset;
pool->releaseInFlightBuffers(context); pool->releaseInFlightBuffers(context);
...@@ -111,6 +84,22 @@ angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context, ...@@ -111,6 +84,22 @@ angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result AllocateLineLoopBufferFromPool(ContextMtl *context,
GLsizei indicesToReserve,
mtl::BufferPool *pool,
mtl::BufferRef *bufferOut,
uint32_t *offsetOut)
{
size_t offset;
pool->releaseInFlightBuffers(context);
ANGLE_TRY(pool->allocate(context, indicesToReserve * sizeof(uint32_t), nullptr, bufferOut,
&offset, nullptr));
*offsetOut = static_cast<uint32_t>(offset);
return angle::Result::Continue;
}
bool NeedToInvertDepthRange(float near, float far) bool NeedToInvertDepthRange(float near, float far)
{ {
return near > far; return near > far;
...@@ -135,6 +124,65 @@ std::string ConvertMarkerToString(GLsizei length, const char *marker) ...@@ -135,6 +124,65 @@ std::string ConvertMarkerToString(GLsizei length, const char *marker)
return cppString; return cppString;
} }
// This class constructs line loop's last segment buffer inside begin() method
// and perform the draw of the line loop's last segment inside destructor
class LineLoopLastSegmentHelper
{
public:
LineLoopLastSegmentHelper() {}
~LineLoopLastSegmentHelper()
{
if (!mLineLoopIndexBuffer)
{
return;
}
// Draw last segment of line loop here
mtl::RenderCommandEncoder *encoder = mContextMtl->getRenderCommandEncoder();
ASSERT(encoder);
encoder->drawIndexed(MTLPrimitiveTypeLine, 2, MTLIndexTypeUInt32, mLineLoopIndexBuffer, 0);
}
angle::Result begin(const gl::Context *context,
mtl::BufferPool *indexBufferPool,
GLint firstVertex,
GLsizei vertexOrIndexCount,
gl::DrawElementsType indexTypeOrNone,
const void *indices)
{
mContextMtl = mtl::GetImpl(context);
indexBufferPool->releaseInFlightBuffers(mContextMtl);
ANGLE_TRY(indexBufferPool->allocate(mContextMtl, 2 * sizeof(uint32_t), nullptr,
&mLineLoopIndexBuffer, nullptr, nullptr));
if (indexTypeOrNone == gl::DrawElementsType::InvalidEnum)
{
ANGLE_TRY(mContextMtl->getDisplay()->getUtils().generateLineLoopLastSegment(
mContextMtl, firstVertex, firstVertex + vertexOrIndexCount - 1,
mLineLoopIndexBuffer, 0));
}
else
{
ASSERT(firstVertex == 0);
ANGLE_TRY(
mContextMtl->getDisplay()->getUtils().generateLineLoopLastSegmentFromElementsArray(
mContextMtl,
{indexTypeOrNone, vertexOrIndexCount, indices, mLineLoopIndexBuffer, 0}));
}
ANGLE_TRY(indexBufferPool->commit(mContextMtl));
return angle::Result::Continue;
}
private:
ContextMtl *mContextMtl = nullptr;
mtl::BufferRef mLineLoopIndexBuffer;
};
} // namespace } // namespace
ContextMtl::ContextMtl(const gl::State &state, gl::ErrorSet *errorSet, DisplayMtl *display) ContextMtl::ContextMtl(const gl::State &state, gl::ErrorSet *errorSet, DisplayMtl *display)
...@@ -155,9 +203,11 @@ angle::Result ContextMtl::initialize() ...@@ -155,9 +203,11 @@ angle::Result ContextMtl::initialize()
mTriFanIndexBuffer.initialize(this, 0, mtl::kIndexBufferOffsetAlignment, mTriFanIndexBuffer.initialize(this, 0, mtl::kIndexBufferOffsetAlignment,
kMaxTriFanLineLoopBuffersPerFrame); kMaxTriFanLineLoopBuffersPerFrame);
mLineLoopIndexBuffer.initialize(this, 2 * sizeof(uint32_t), mtl::kIndexBufferOffsetAlignment, mLineLoopIndexBuffer.initialize(this, 0, mtl::kIndexBufferOffsetAlignment,
kMaxTriFanLineLoopBuffersPerFrame); kMaxTriFanLineLoopBuffersPerFrame);
mLineLoopIndexBuffer.setAlwaysAllocateNewBuffer(true); mLineLoopLastSegmentIndexBuffer.initialize(this, 2 * sizeof(uint32_t),
mtl::kIndexBufferOffsetAlignment,
kMaxTriFanLineLoopBuffersPerFrame);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -166,6 +216,7 @@ void ContextMtl::onDestroy(const gl::Context *context) ...@@ -166,6 +216,7 @@ void ContextMtl::onDestroy(const gl::Context *context)
{ {
mTriFanIndexBuffer.destroy(this); mTriFanIndexBuffer.destroy(this);
mLineLoopIndexBuffer.destroy(this); mLineLoopIndexBuffer.destroy(this);
mLineLoopLastSegmentIndexBuffer.destroy(this);
mOcclusionQueryPool.destroy(this); mOcclusionQueryPool.destroy(this);
mIncompleteTextures.onDestroy(context); mIncompleteTextures.onDestroy(context);
...@@ -217,7 +268,7 @@ angle::Result ContextMtl::drawTriFanArraysWithBaseVertex(const gl::Context *cont ...@@ -217,7 +268,7 @@ angle::Result ContextMtl::drawTriFanArraysWithBaseVertex(const gl::Context *cont
ASSERT((getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled)); ASSERT((getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled));
uint32_t genIndicesCount; uint32_t genIndicesCount;
ANGLE_TRY(GetTriangleFanIndicesCount(this, count, &genIndicesCount)); ANGLE_TRY(mtl::GetTriangleFanIndicesCount(this, count, &genIndicesCount));
size_t indexBufferSize = genIndicesCount * sizeof(uint32_t); size_t indexBufferSize = genIndicesCount * sizeof(uint32_t);
// We can reuse the previously generated index buffer if it has more than enough indices // We can reuse the previously generated index buffer if it has more than enough indices
...@@ -289,6 +340,54 @@ angle::Result ContextMtl::drawTriFanArrays(const gl::Context *context, ...@@ -289,6 +340,54 @@ angle::Result ContextMtl::drawTriFanArrays(const gl::Context *context,
return drawTriFanArraysLegacy(context, first, count, instances); return drawTriFanArraysLegacy(context, first, count, instances);
} }
angle::Result ContextMtl::drawLineLoopArraysNonInstanced(const gl::Context *context,
GLint first,
GLsizei count)
{
// Generate line loop's last segment. It will be rendered when this function exits.
LineLoopLastSegmentHelper lineloopHelper;
// Line loop helper needs to generate last segment indices before rendering command encoder
// starts.
ANGLE_TRY(lineloopHelper.begin(context, &mLineLoopLastSegmentIndexBuffer, first, count,
gl::DrawElementsType::InvalidEnum, nullptr));
return drawArraysImpl(context, gl::PrimitiveMode::LineStrip, first, count, 0);
}
angle::Result ContextMtl::drawLineLoopArrays(const gl::Context *context,
GLint first,
GLsizei count,
GLsizei instances)
{
if (instances <= 1)
{
return drawLineLoopArraysNonInstanced(context, first, count);
}
mtl::BufferRef genIdxBuffer;
uint32_t genIdxBufferOffset;
uint32_t genIndicesCount = count + 1;
ANGLE_TRY(AllocateLineLoopBufferFromPool(this, genIndicesCount, &mLineLoopIndexBuffer,
&genIdxBuffer, &genIdxBufferOffset));
ANGLE_TRY(getDisplay()->getUtils().generateLineLoopBufferFromArrays(
this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer,
genIdxBufferOffset}));
ANGLE_TRY(mLineLoopIndexBuffer.commit(this));
ASSERT(!getState().isTransformFeedbackActiveUnpaused());
ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, first, count, instances,
gl::DrawElementsType::InvalidEnum, nullptr, false));
mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount,
MTLIndexTypeUInt32, genIdxBuffer, genIdxBufferOffset,
instances);
return angle::Result::Continue;
}
angle::Result ContextMtl::drawArraysImpl(const gl::Context *context, angle::Result ContextMtl::drawArraysImpl(const gl::Context *context,
gl::PrimitiveMode mode, gl::PrimitiveMode mode,
GLint first, GLint first,
...@@ -307,6 +406,10 @@ angle::Result ContextMtl::drawArraysImpl(const gl::Context *context, ...@@ -307,6 +406,10 @@ angle::Result ContextMtl::drawArraysImpl(const gl::Context *context,
{ {
return drawTriFanArrays(context, first, count, instanceCount); return drawTriFanArrays(context, first, count, instanceCount);
} }
else if (mode == gl::PrimitiveMode::LineLoop)
{
return drawLineLoopArrays(context, first, count, instanceCount);
}
MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode); MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode);
...@@ -372,11 +475,12 @@ angle::Result ContextMtl::drawTriFanElements(const gl::Context *context, ...@@ -372,11 +475,12 @@ angle::Result ContextMtl::drawTriFanElements(const gl::Context *context,
mtl::BufferRef genIdxBuffer; mtl::BufferRef genIdxBuffer;
uint32_t genIdxBufferOffset; uint32_t genIdxBufferOffset;
uint32_t genIndicesCount; uint32_t genIndicesCount;
bool primitiveRestart = getState().isPrimitiveRestartEnabled();
ANGLE_TRY(AllocateTriangleFanBufferFromPool(this, count, &mTriFanIndexBuffer, &genIdxBuffer, ANGLE_TRY(AllocateTriangleFanBufferFromPool(this, count, &mTriFanIndexBuffer, &genIdxBuffer,
&genIdxBufferOffset, &genIndicesCount)); &genIdxBufferOffset, &genIndicesCount));
ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromElementsArray( ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromElementsArray(
this, {type, count, indices, genIdxBuffer, genIdxBufferOffset})); this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart}));
ANGLE_TRY(mTriFanIndexBuffer.commit(this)); ANGLE_TRY(mTriFanIndexBuffer.commit(this));
...@@ -393,6 +497,63 @@ angle::Result ContextMtl::drawTriFanElements(const gl::Context *context, ...@@ -393,6 +497,63 @@ angle::Result ContextMtl::drawTriFanElements(const gl::Context *context,
instances); instances);
} }
angle::Result ContextMtl::drawLineLoopElementsNonInstancedNoPrimitiveRestart(
const gl::Context *context,
GLsizei count,
gl::DrawElementsType type,
const void *indices)
{
// Generate line loop's last segment. It will be rendered when this function exits.
LineLoopLastSegmentHelper lineloopHelper;
// Line loop helper needs to generate index before rendering command encoder starts.
ANGLE_TRY(
lineloopHelper.begin(context, &mLineLoopLastSegmentIndexBuffer, 0, count, type, indices));
return drawElementsImpl(context, gl::PrimitiveMode::LineStrip, count, type, indices, 0);
}
angle::Result ContextMtl::drawLineLoopElements(const gl::Context *context,
GLsizei count,
gl::DrawElementsType type,
const void *indices,
GLsizei instances)
{
if (count >= 2)
{
bool primitiveRestart = getState().isPrimitiveRestartEnabled();
if (instances <= 1 && !primitiveRestart)
{
// Non instanced draw and no primitive restart, just use faster version.
return drawLineLoopElementsNonInstancedNoPrimitiveRestart(context, count, type,
indices);
}
mtl::BufferRef genIdxBuffer;
uint32_t genIdxBufferOffset;
uint32_t reservedIndices = count * 2;
uint32_t genIndicesCount;
ANGLE_TRY(AllocateLineLoopBufferFromPool(this, reservedIndices, &mLineLoopIndexBuffer,
&genIdxBuffer, &genIdxBufferOffset));
ANGLE_TRY(getDisplay()->getUtils().generateLineLoopBufferFromElementsArray(
this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart},
&genIndicesCount));
ANGLE_TRY(mLineLoopIndexBuffer.commit(this));
ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, 0, count, instances, type,
indices, false));
mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount,
MTLIndexTypeUInt32, genIdxBuffer, genIdxBufferOffset,
instances);
return angle::Result::Continue;
} // if (count >= 2)
return drawElementsInstanced(context, gl::PrimitiveMode::Lines, count, type, indices,
instances);
}
angle::Result ContextMtl::drawElementsImpl(const gl::Context *context, angle::Result ContextMtl::drawElementsImpl(const gl::Context *context,
gl::PrimitiveMode mode, gl::PrimitiveMode mode,
GLsizei count, GLsizei count,
...@@ -412,6 +573,10 @@ angle::Result ContextMtl::drawElementsImpl(const gl::Context *context, ...@@ -412,6 +573,10 @@ angle::Result ContextMtl::drawElementsImpl(const gl::Context *context,
{ {
return drawTriFanElements(context, count, type, indices, instanceCount); return drawTriFanElements(context, count, type, indices, instanceCount);
} }
else if (mode == gl::PrimitiveMode::LineLoop)
{
return drawLineLoopElements(context, count, type, indices, instanceCount);
}
mtl::BufferRef idxBuffer; mtl::BufferRef idxBuffer;
size_t convertedOffset = 0; size_t convertedOffset = 0;
...@@ -513,9 +678,7 @@ angle::Result ContextMtl::drawRangeElements(const gl::Context *context, ...@@ -513,9 +678,7 @@ angle::Result ContextMtl::drawRangeElements(const gl::Context *context,
gl::DrawElementsType type, gl::DrawElementsType type,
const void *indices) const void *indices)
{ {
// NOTE(hqle): ES 3.0 return drawElementsImpl(context, mode, count, type, indices, 0);
UNIMPLEMENTED();
return angle::Result::Stop;
} }
angle::Result ContextMtl::drawRangeElementsBaseVertex(const gl::Context *context, angle::Result ContextMtl::drawRangeElementsBaseVertex(const gl::Context *context,
...@@ -1686,16 +1849,6 @@ angle::Result ContextMtl::setupDraw(const gl::Context *context, ...@@ -1686,16 +1849,6 @@ angle::Result ContextMtl::setupDraw(const gl::Context *context,
// instances=0 means no instanced draw. // instances=0 means no instanced draw.
GLsizei instanceCount = instances ? instances : 1; GLsizei instanceCount = instances ? instances : 1;
mtl::BufferRef lineLoopLastSegmentIndexBuffer;
if (mode == gl::PrimitiveMode::LineLoop)
{
// Generate line loop last segment before render command encoder is created
ANGLE_TRY(genLineLoopLastSegment(context, firstVertex, vertexOrIndexCount, instanceCount,
indexTypeOrNone, indices,
&lineLoopLastSegmentIndexBuffer));
}
// Must be called before the render command encoder is started.
if (context->getStateCache().hasAnyActiveClientAttrib()) if (context->getStateCache().hasAnyActiveClientAttrib())
{ {
ANGLE_TRY(mVertexArray->updateClientAttribs(context, firstVertex, vertexOrIndexCount, ANGLE_TRY(mVertexArray->updateClientAttribs(context, firstVertex, vertexOrIndexCount,
...@@ -1823,56 +1976,6 @@ angle::Result ContextMtl::setupDraw(const gl::Context *context, ...@@ -1823,56 +1976,6 @@ angle::Result ContextMtl::setupDraw(const gl::Context *context,
ANGLE_TRY(mProgram->setupDraw(context, &mRenderEncoder, mRenderPipelineDesc, ANGLE_TRY(mProgram->setupDraw(context, &mRenderEncoder, mRenderPipelineDesc,
isPipelineDescChanged, textureChanged, uniformBuffersDirty)); isPipelineDescChanged, textureChanged, uniformBuffersDirty));
if (mode == gl::PrimitiveMode::LineLoop)
{
// Draw last segment of line loop here
if (instances == 0)
{
mRenderEncoder.drawIndexed(MTLPrimitiveTypeLine, 2, MTLIndexTypeUInt32,
lineLoopLastSegmentIndexBuffer, 0);
}
else
{
mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeLine, 2, MTLIndexTypeUInt32,
lineLoopLastSegmentIndexBuffer, 0, instanceCount);
}
}
return angle::Result::Continue;
}
angle::Result ContextMtl::genLineLoopLastSegment(const gl::Context *context,
GLint firstVertex,
GLsizei vertexOrIndexCount,
GLsizei instanceCount,
gl::DrawElementsType indexTypeOrNone,
const void *indices,
mtl::BufferRef *lastSegmentIndexBufferOut)
{
mLineLoopIndexBuffer.releaseInFlightBuffers(this);
mtl::BufferRef newBuffer;
ANGLE_TRY(mLineLoopIndexBuffer.allocate(this, 2 * sizeof(uint32_t), nullptr, &newBuffer,
nullptr, nullptr));
if (indexTypeOrNone == gl::DrawElementsType::InvalidEnum)
{
ANGLE_TRY(getDisplay()->getUtils().generateLineLoopLastSegment(
this, firstVertex, firstVertex + vertexOrIndexCount - 1, newBuffer, 0));
}
else
{
// NOTE(hqle): Support drawRangeElements & instanced draw, which means firstVertex has to be
// taken into account
ASSERT(firstVertex == 0);
ANGLE_TRY(getDisplay()->getUtils().generateLineLoopLastSegmentFromElementsArray(
this, {indexTypeOrNone, vertexOrIndexCount, indices, newBuffer, 0}));
}
ANGLE_TRY(mLineLoopIndexBuffer.commit(this));
*lastSegmentIndexBufferOut = newBuffer;
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -728,22 +728,18 @@ void DisplayMtl::initializeFeatures() ...@@ -728,22 +728,18 @@ void DisplayMtl::initializeFeatures()
isMetal2_2 = true; isMetal2_2 = true;
} }
// default values: bool isOSX = TARGET_OS_OSX;
mFeatures.hasBaseVertexInstancedDraw.enabled = true; bool isCatalyst = TARGET_OS_MACCATALYST;
mFeatures.hasDepthTextureFiltering.enabled = false; bool isSimulator = TARGET_OS_SIMULATOR;
mFeatures.hasExplicitMemBarrier.enabled = false; bool isARM = ANGLE_MTL_ARM;
mFeatures.hasNonUniformDispatch.enabled = true;
mFeatures.hasStencilOutput.enabled = false; ANGLE_FEATURE_CONDITION((&mFeatures), allowGenMultipleMipsPerPass, true);
mFeatures.hasTextureSwizzle.enabled = false; ANGLE_FEATURE_CONDITION((&mFeatures), forceBufferGPUStorage, false);
mFeatures.allowSeparatedDepthStencilBuffers.enabled = false;
mFeatures.allowGenMultipleMipsPerPass.enabled = true;
mFeatures.hasCheapRenderPass.enabled = false;
ANGLE_FEATURE_CONDITION((&mFeatures), hasDepthTextureFiltering, ANGLE_FEATURE_CONDITION((&mFeatures), hasDepthTextureFiltering,
TARGET_OS_OSX || TARGET_OS_MACCATALYST); (isOSX || isCatalyst) && !isARM);
ANGLE_FEATURE_CONDITION( ANGLE_FEATURE_CONDITION((&mFeatures), hasExplicitMemBarrier,
(&mFeatures), hasExplicitMemBarrier, isMetal2_1 && (isOSX || isCatalyst) && !isARM);
isMetal2_1 && (TARGET_OS_OSX || TARGET_OS_MACCATALYST) && !ANGLE_MTL_ARM);
ANGLE_FEATURE_CONDITION((&mFeatures), hasDepthAutoResolve, supportsEitherGPUFamily(3, 2)); ANGLE_FEATURE_CONDITION((&mFeatures), hasDepthAutoResolve, supportsEitherGPUFamily(3, 2));
ANGLE_FEATURE_CONDITION((&mFeatures), hasStencilAutoResolve, supportsEitherGPUFamily(5, 2)); ANGLE_FEATURE_CONDITION((&mFeatures), hasStencilAutoResolve, supportsEitherGPUFamily(5, 2));
ANGLE_FEATURE_CONDITION((&mFeatures), allowMultisampleStoreAndResolve, ANGLE_FEATURE_CONDITION((&mFeatures), allowMultisampleStoreAndResolve,
...@@ -761,19 +757,17 @@ void DisplayMtl::initializeFeatures() ...@@ -761,19 +757,17 @@ void DisplayMtl::initializeFeatures()
// Fence sync is flaky on Nvidia // Fence sync is flaky on Nvidia
ANGLE_FEATURE_CONDITION((&mFeatures), hasEvents, isMetal2_1 && !isNVIDIA()); ANGLE_FEATURE_CONDITION((&mFeatures), hasEvents, isMetal2_1 && !isNVIDIA());
ANGLE_FEATURE_CONDITION((&mFeatures), hasCheapRenderPass, ANGLE_FEATURE_CONDITION((&mFeatures), hasCheapRenderPass, (isOSX || isCatalyst) && !isARM);
(TARGET_OS_OSX || TARGET_OS_MACCATALYST) && !ANGLE_MTL_ARM);
#if !TARGET_OS_MACCATALYST && (TARGET_OS_IOS || TARGET_OS_TV)
// Base Vertex drawing is only supported since GPU family 3. // Base Vertex drawing is only supported since GPU family 3.
ANGLE_FEATURE_CONDITION((&mFeatures), hasBaseVertexInstancedDraw, supportsIOSGPUFamily(3)); ANGLE_FEATURE_CONDITION((&mFeatures), hasBaseVertexInstancedDraw,
isOSX || isCatalyst || supportsIOSGPUFamily(3));
ANGLE_FEATURE_CONDITION((&mFeatures), hasNonUniformDispatch, ANGLE_FEATURE_CONDITION((&mFeatures), hasNonUniformDispatch,
TARGET_OS_IOS && supportsIOSGPUFamily(4)); isOSX || isCatalyst || supportsIOSGPUFamily(4));
ANGLE_FEATURE_CONDITION((&mFeatures), allowSeparatedDepthStencilBuffers, !TARGET_OS_SIMULATOR);
#endif ANGLE_FEATURE_CONDITION((&mFeatures), allowSeparatedDepthStencilBuffers,
!isOSX && !isCatalyst && !isSimulator);
angle::PlatformMethods *platform = ANGLEPlatformCurrent(); angle::PlatformMethods *platform = ANGLEPlatformCurrent();
platform->overrideFeaturesMtl(platform, &mFeatures); platform->overrideFeaturesMtl(platform, &mFeatures);
......
...@@ -76,6 +76,7 @@ angle::Result StreamIndexData(ContextMtl *contextMtl, ...@@ -76,6 +76,7 @@ angle::Result StreamIndexData(ContextMtl *contextMtl,
const uint8_t *sourcePointer, const uint8_t *sourcePointer,
gl::DrawElementsType indexType, gl::DrawElementsType indexType,
size_t indexCount, size_t indexCount,
bool primitiveRestartEnabled,
mtl::BufferRef *bufferOut, mtl::BufferRef *bufferOut,
size_t *bufferOffsetOut) size_t *bufferOffsetOut)
{ {
...@@ -94,13 +95,27 @@ angle::Result StreamIndexData(ContextMtl *contextMtl, ...@@ -94,13 +95,27 @@ angle::Result StreamIndexData(ContextMtl *contextMtl,
const GLubyte *in = static_cast<const GLubyte *>(sourcePointer); const GLubyte *in = static_cast<const GLubyte *>(sourcePointer);
GLushort *expandedDst = reinterpret_cast<GLushort *>(dst); GLushort *expandedDst = reinterpret_cast<GLushort *>(dst);
// NOTE(hqle): May need to handle primitive restart index in future when ES 3.0 if (primitiveRestartEnabled)
// is supported.
// Fast path for common case.
for (size_t index = 0; index < indexCount; index++)
{ {
expandedDst[index] = static_cast<GLushort>(in[index]); for (size_t index = 0; index < indexCount; index++)
} {
if (in[index] == 0xFF)
{
expandedDst[index] = 0xFFFF;
}
else
{
expandedDst[index] = static_cast<GLushort>(in[index]);
}
}
} // if (primitiveRestartEnabled)
else
{
for (size_t index = 0; index < indexCount; index++)
{
expandedDst[index] = static_cast<GLushort>(in[index]);
}
} // if (primitiveRestartEnabled)
} }
else else
{ {
...@@ -606,11 +621,12 @@ angle::Result VertexArrayMtl::convertIndexBuffer(const gl::Context *glContext, ...@@ -606,11 +621,12 @@ angle::Result VertexArrayMtl::convertIndexBuffer(const gl::Context *glContext,
alignedOffset = alignedOffset << 1; alignedOffset = alignedOffset << 1;
} }
ContextMtl *contextMtl = mtl::GetImpl(glContext); ContextMtl *contextMtl = mtl::GetImpl(glContext);
BufferMtl *idxBuffer = mtl::GetImpl(getState().getElementArrayBuffer()); const gl::State &glState = glContext->getState();
BufferMtl *idxBuffer = mtl::GetImpl(getState().getElementArrayBuffer());
IndexConversionBufferMtl *conversion = IndexConversionBufferMtl *conversion = idxBuffer->getIndexConversionBuffer(
idxBuffer->getIndexConversionBuffer(contextMtl, indexType, offsetModulo); contextMtl, indexType, glState.isPrimitiveRestartEnabled(), offsetModulo);
// Has the content of the buffer has changed since last conversion? // Has the content of the buffer has changed since last conversion?
if (!conversion->dirty) if (!conversion->dirty)
...@@ -629,8 +645,8 @@ angle::Result VertexArrayMtl::convertIndexBuffer(const gl::Context *glContext, ...@@ -629,8 +645,8 @@ angle::Result VertexArrayMtl::convertIndexBuffer(const gl::Context *glContext,
// We shouldn't use GPU to convert when we are in a middle of a render pass. // We shouldn't use GPU to convert when we are in a middle of a render pass.
ANGLE_TRY(StreamIndexData(contextMtl, &conversion->data, ANGLE_TRY(StreamIndexData(contextMtl, &conversion->data,
idxBuffer->getClientShadowCopyData(contextMtl) + offsetModulo, idxBuffer->getClientShadowCopyData(contextMtl) + offsetModulo,
indexType, indexCount, &conversion->convertedBuffer, indexType, indexCount, glState.isPrimitiveRestartEnabled(),
&conversion->convertedOffset)); &conversion->convertedBuffer, &conversion->convertedOffset));
} }
else else
{ {
...@@ -664,10 +680,10 @@ angle::Result VertexArrayMtl::convertIndexBufferGPU(const gl::Context *glContext ...@@ -664,10 +680,10 @@ angle::Result VertexArrayMtl::convertIndexBufferGPU(const gl::Context *glContext
// Do the conversion on GPU. // Do the conversion on GPU.
ANGLE_TRY(display->getUtils().convertIndexBufferGPU( ANGLE_TRY(display->getUtils().convertIndexBufferGPU(
mtl::GetImpl(glContext), contextMtl, {indexType, static_cast<uint32_t>(indexCount), idxBuffer->getCurrentBuffer(),
{indexType, static_cast<uint32_t>(indexCount), idxBuffer->getCurrentBuffer(), static_cast<uint32_t>(offset), conversion->convertedBuffer,
static_cast<uint32_t>(offset), conversion->convertedBuffer, static_cast<uint32_t>(conversion->convertedOffset),
static_cast<uint32_t>(conversion->convertedOffset)})); glContext->getState().isPrimitiveRestartEnabled()}));
ANGLE_TRY(conversion->data.commit(contextMtl)); ANGLE_TRY(conversion->data.commit(contextMtl));
...@@ -689,7 +705,8 @@ angle::Result VertexArrayMtl::streamIndexBufferFromClient(const gl::Context *con ...@@ -689,7 +705,8 @@ angle::Result VertexArrayMtl::streamIndexBufferFromClient(const gl::Context *con
auto srcData = static_cast<const uint8_t *>(sourcePointer); auto srcData = static_cast<const uint8_t *>(sourcePointer);
ANGLE_TRY(StreamIndexData(contextMtl, &mDynamicIndexData, srcData, indexType, indexCount, ANGLE_TRY(StreamIndexData(contextMtl, &mDynamicIndexData, srcData, indexType, indexCount,
idxBufferOut, idxBufferOffsetOut)); context->getState().isPrimitiveRestartEnabled(), idxBufferOut,
idxBufferOffsetOut));
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -112,6 +112,11 @@ BufferPool::~BufferPool() {} ...@@ -112,6 +112,11 @@ BufferPool::~BufferPool() {}
bool BufferPool::shouldAllocateInSharedMem(ContextMtl *contextMtl) const bool BufferPool::shouldAllocateInSharedMem(ContextMtl *contextMtl) const
{ {
if (ANGLE_UNLIKELY(contextMtl->getDisplay()->getFeatures().forceBufferGPUStorage.enabled))
{
return false;
}
switch (mMemPolicy) switch (mMemPolicy)
{ {
case BufferPoolMemPolicy::AlwaysSharedMem: case BufferPoolMemPolicy::AlwaysSharedMem:
......
...@@ -104,7 +104,7 @@ struct StencilBlitViaBufferParams : public DepthStencilBlitParams ...@@ -104,7 +104,7 @@ struct StencilBlitViaBufferParams : public DepthStencilBlitParams
bool dstPackedDepthStencilFormat = false; bool dstPackedDepthStencilFormat = false;
}; };
struct TriFanFromArrayParams struct TriFanOrLineLoopFromArrayParams
{ {
uint32_t firstVertex; uint32_t firstVertex;
uint32_t vertexCount; uint32_t vertexCount;
...@@ -123,6 +123,7 @@ struct IndexConversionParams ...@@ -123,6 +123,7 @@ struct IndexConversionParams
const BufferRef &dstBuffer; const BufferRef &dstBuffer;
// Must be multiples of kIndexBufferOffsetAlignment // Must be multiples of kIndexBufferOffsetAlignment
uint32_t dstOffset; uint32_t dstOffset;
bool primitiveRestartEnabled = false;
}; };
struct IndexGenerationParams struct IndexGenerationParams
...@@ -132,6 +133,7 @@ struct IndexGenerationParams ...@@ -132,6 +133,7 @@ struct IndexGenerationParams
const void *indices; const void *indices;
BufferRef dstBuffer; BufferRef dstBuffer;
uint32_t dstOffset; uint32_t dstOffset;
bool primitiveRestartEnabled = false;
}; };
struct CopyPixelsCommonParams struct CopyPixelsCommonParams
...@@ -312,18 +314,29 @@ class IndexGeneratorUtils final : angle::NonCopyable ...@@ -312,18 +314,29 @@ class IndexGeneratorUtils final : angle::NonCopyable
const IndexConversionParams &params); const IndexConversionParams &params);
// Generate triangle fan index buffer for glDrawArrays(). // Generate triangle fan index buffer for glDrawArrays().
angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl, angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
const TriFanFromArrayParams &params); const TriFanOrLineLoopFromArrayParams &params);
// Generate triangle fan index buffer for glDrawElements(). // Generate triangle fan index buffer for glDrawElements().
angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl, angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
const IndexGenerationParams &params); const IndexGenerationParams &params);
// Generate line loop index buffer for glDrawArrays().
angle::Result generateLineLoopBufferFromArrays(ContextMtl *contextMtl,
const TriFanOrLineLoopFromArrayParams &params);
// Generate line loop's last segment index buffer for glDrawArrays(). // Generate line loop's last segment index buffer for glDrawArrays().
// This is used when primitive restart is not enabled.
angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl, angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl,
uint32_t firstVertex, uint32_t firstVertex,
uint32_t lastVertex, uint32_t lastVertex,
const BufferRef &dstBuffer, const BufferRef &dstBuffer,
uint32_t dstOffset); uint32_t dstOffset);
// Generate line loop index buffer for glDrawElements().
// Destination buffer must have at least 2x the number of original indices if primitive restart
// is enabled.
angle::Result generateLineLoopBufferFromElementsArray(ContextMtl *contextMtl,
const IndexGenerationParams &params,
uint32_t *indicesGenerated);
// Generate line loop's last segment index buffer for glDrawElements(). // Generate line loop's last segment index buffer for glDrawElements().
// NOTE: this function assumes primitive restart is not enabled.
angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl, angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl,
const IndexGenerationParams &params); const IndexGenerationParams &params);
...@@ -340,13 +353,17 @@ class IndexGeneratorUtils final : angle::NonCopyable ...@@ -340,13 +353,17 @@ class IndexGeneratorUtils final : angle::NonCopyable
ContextMtl *contextMtl, ContextMtl *contextMtl,
gl::DrawElementsType srcType, gl::DrawElementsType srcType,
uint32_t srcOffset); uint32_t srcOffset);
// Get compute pipeline to generate tri fan index for glDrawElements(). // Get compute pipeline to generate tri fan/line loop index for glDrawElements().
AutoObjCPtr<id<MTLComputePipelineState>> getTriFanFromElemArrayGeneratorPipeline( AutoObjCPtr<id<MTLComputePipelineState>> getIndicesFromElemArrayGeneratorPipeline(
ContextMtl *contextMtl, ContextMtl *contextMtl,
gl::DrawElementsType srcType, gl::DrawElementsType srcType,
uint32_t srcOffset); uint32_t srcOffset,
NSString *shaderName,
IndexConversionPipelineArray *pipelineCacheArray);
// Defer loading of compute pipeline to generate tri fan index for glDrawArrays(). // Defer loading of compute pipeline to generate tri fan index for glDrawArrays().
void ensureTriFanFromArrayGeneratorInitialized(ContextMtl *contextMtl); void ensureTriFanFromArrayGeneratorInitialized(ContextMtl *contextMtl);
// Defer loading of compute pipeline to generate line loop index for glDrawArrays().
void ensureLineLoopFromArrayGeneratorInitialized(ContextMtl *contextMtl);
angle::Result generateTriFanBufferFromElementsArrayGPU( angle::Result generateTriFanBufferFromElementsArrayGPU(
ContextMtl *contextMtl, ContextMtl *contextMtl,
...@@ -360,6 +377,18 @@ class IndexGeneratorUtils final : angle::NonCopyable ...@@ -360,6 +377,18 @@ class IndexGeneratorUtils final : angle::NonCopyable
angle::Result generateTriFanBufferFromElementsArrayCPU(ContextMtl *contextMtl, angle::Result generateTriFanBufferFromElementsArrayCPU(ContextMtl *contextMtl,
const IndexGenerationParams &params); const IndexGenerationParams &params);
angle::Result generateLineLoopBufferFromElementsArrayGPU(
ContextMtl *contextMtl,
gl::DrawElementsType srcType,
uint32_t indexCount,
const BufferRef &srcBuffer,
uint32_t srcOffset,
const BufferRef &dstBuffer,
// Must be multiples of kIndexBufferOffsetAlignment
uint32_t dstOffset);
angle::Result generateLineLoopBufferFromElementsArrayCPU(ContextMtl *contextMtl,
const IndexGenerationParams &params,
uint32_t *indicesGenerated);
angle::Result generateLineLoopLastSegmentFromElementsArrayCPU( angle::Result generateLineLoopLastSegmentFromElementsArrayCPU(
ContextMtl *contextMtl, ContextMtl *contextMtl,
const IndexGenerationParams &params); const IndexGenerationParams &params);
...@@ -368,6 +397,9 @@ class IndexGeneratorUtils final : angle::NonCopyable ...@@ -368,6 +397,9 @@ class IndexGeneratorUtils final : angle::NonCopyable
IndexConversionPipelineArray mTriFanFromElemArrayGeneratorPipelineCaches; IndexConversionPipelineArray mTriFanFromElemArrayGeneratorPipelineCaches;
AutoObjCPtr<id<MTLComputePipelineState>> mTriFanFromArraysGeneratorPipeline; AutoObjCPtr<id<MTLComputePipelineState>> mTriFanFromArraysGeneratorPipeline;
IndexConversionPipelineArray mLineLoopFromElemArrayGeneratorPipelineCaches;
AutoObjCPtr<id<MTLComputePipelineState>> mLineLoopFromArraysGeneratorPipeline;
}; };
// Util class for handling visibility query result // Util class for handling visibility query result
...@@ -553,14 +585,20 @@ class RenderUtils : public Context, angle::NonCopyable ...@@ -553,14 +585,20 @@ class RenderUtils : public Context, angle::NonCopyable
angle::Result convertIndexBufferGPU(ContextMtl *contextMtl, angle::Result convertIndexBufferGPU(ContextMtl *contextMtl,
const IndexConversionParams &params); const IndexConversionParams &params);
angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl, angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
const TriFanFromArrayParams &params); const TriFanOrLineLoopFromArrayParams &params);
angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl, angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
const IndexGenerationParams &params); const IndexGenerationParams &params);
angle::Result generateLineLoopBufferFromArrays(ContextMtl *contextMtl,
const TriFanOrLineLoopFromArrayParams &params);
angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl, angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl,
uint32_t firstVertex, uint32_t firstVertex,
uint32_t lastVertex, uint32_t lastVertex,
const BufferRef &dstBuffer, const BufferRef &dstBuffer,
uint32_t dstOffset); uint32_t dstOffset);
angle::Result generateLineLoopBufferFromElementsArray(ContextMtl *contextMtl,
const IndexGenerationParams &params,
uint32_t *indicesGenerated);
angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl, angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl,
const IndexGenerationParams &params); const IndexGenerationParams &params);
......
...@@ -74,11 +74,20 @@ struct BlitStencilToBufferParamsUniform ...@@ -74,11 +74,20 @@ struct BlitStencilToBufferParamsUniform
uint8_t padding[11]; uint8_t padding[11];
}; };
// See libANGLE/renderer/metal/shaders/genIndices.metal
struct TriFanOrLineLoopArrayParams
{
uint firstVertex;
uint vertexCount;
uint padding[2];
};
struct IndexConversionUniform struct IndexConversionUniform
{ {
uint32_t srcOffset; uint32_t srcOffset;
uint32_t indexCount; uint32_t indexCount;
uint32_t padding[2]; uint8_t primitiveRestartEnabled;
uint8_t padding[7];
}; };
// See libANGLE/renderer/metal/shaders/visibility.metal // See libANGLE/renderer/metal/shaders/visibility.metal
...@@ -207,31 +216,195 @@ void GetBlitTexCoords(uint32_t srcWidth, ...@@ -207,31 +216,195 @@ void GetBlitTexCoords(uint32_t srcWidth,
template <typename T> template <typename T>
angle::Result GenTriFanFromClientElements(ContextMtl *contextMtl, angle::Result GenTriFanFromClientElements(ContextMtl *contextMtl,
GLsizei count, GLsizei count,
bool primitiveRestartEnabled,
const T *indices, const T *indices,
const BufferRef &dstBuffer, const BufferRef &dstBuffer,
uint32_t dstOffset) uint32_t dstOffset)
{ {
ASSERT(count > 2); ASSERT(count > 2);
uint32_t genIndicesCount;
ANGLE_TRY(mtl::GetTriangleFanIndicesCount(contextMtl, count, &genIndicesCount));
constexpr T kSrcPrimitiveRestartIndex = std::numeric_limits<T>::max();
const uint32_t kDstPrimitiveRestartIndex = std::numeric_limits<uint32_t>::max();
uint32_t *dstPtr = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset);
T triFirstIdx = 0; // Vertex index of trianlge's 1st vertex
T srcPrevIdx = 0; // Vertex index of trianlge's 2nd vertex
memcpy(&triFirstIdx, indices, sizeof(triFirstIdx));
if (primitiveRestartEnabled)
{
// triFirstIdxLoc: Location of current triangle's fist vertex in source buffer.
GLsizei triFirstIdxLoc = 0;
while (triFirstIdx == kSrcPrimitiveRestartIndex)
{
memcpy(&dstPtr[triFirstIdxLoc++], &kDstPrimitiveRestartIndex,
sizeof(kDstPrimitiveRestartIndex));
memcpy(&triFirstIdx, indices + triFirstIdxLoc, sizeof(triFirstIdx));
}
if (triFirstIdxLoc + 2 >= count)
{
// Not enough indices.
for (GLsizei i = triFirstIdxLoc; i < count; ++i)
{
memcpy(&dstPtr[i], &kDstPrimitiveRestartIndex, sizeof(kDstPrimitiveRestartIndex));
}
}
else if (triFirstIdxLoc + 1 < count)
{
memcpy(&srcPrevIdx, indices + triFirstIdxLoc + 1, sizeof(srcPrevIdx));
}
for (GLsizei i = triFirstIdxLoc + 2; i < count; ++i)
{
uint32_t triIndices[3];
T srcIdx;
memcpy(&srcIdx, indices + i, sizeof(srcIdx));
if (srcPrevIdx == kSrcPrimitiveRestartIndex || srcIdx == kSrcPrimitiveRestartIndex)
{
// Incomplete triangle.
triIndices[0] = kDstPrimitiveRestartIndex;
triIndices[1] = kDstPrimitiveRestartIndex;
triIndices[2] = kDstPrimitiveRestartIndex;
triFirstIdx = srcIdx;
triFirstIdxLoc = i;
}
else if (i < triFirstIdxLoc + 2)
{
// Incomplete triangle
triIndices[0] = kDstPrimitiveRestartIndex;
triIndices[1] = kDstPrimitiveRestartIndex;
triIndices[2] = kDstPrimitiveRestartIndex;
}
else
{
triIndices[0] = triFirstIdx;
triIndices[1] = srcPrevIdx;
triIndices[2] = srcIdx;
}
srcPrevIdx = srcIdx;
memcpy(dstPtr + 3 * (i - 2), triIndices, sizeof(triIndices));
}
}
else
{
memcpy(&srcPrevIdx, indices + 1, sizeof(srcPrevIdx));
for (GLsizei i = 2; i < count; ++i)
{
T srcIdx;
memcpy(&srcIdx, indices + i, sizeof(srcIdx));
uint32_t triIndices[3];
triIndices[0] = triFirstIdx;
triIndices[1] = srcPrevIdx;
triIndices[2] = srcIdx;
srcPrevIdx = srcIdx;
memcpy(dstPtr + 3 * (i - 2), triIndices, sizeof(triIndices));
}
}
dstBuffer->unmapAndFlushSubset(contextMtl, dstOffset, genIndicesCount * sizeof(uint32_t));
return angle::Result::Continue;
}
template <typename T>
angle::Result GenLineLoopFromClientElements(ContextMtl *contextMtl,
GLsizei count,
bool primitiveRestartEnabled,
const T *indices,
const BufferRef &dstBuffer,
uint32_t dstOffset,
uint32_t *indicesGenerated)
{
ASSERT(count >= 2);
constexpr T kSrcPrimitiveRestartIndex = std::numeric_limits<T>::max();
const uint32_t kDstPrimitiveRestartIndex = std::numeric_limits<uint32_t>::max();
uint32_t *dstPtr = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset); uint32_t *dstPtr = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset);
T firstIdx; // lineLoopFirstIdx: value of of current line loop's first vertex index. Can change when
memcpy(&firstIdx, indices, sizeof(firstIdx)); // encounter a primitive restart index.
for (GLsizei i = 2; i < count; ++i) T lineLoopFirstIdx;
memcpy(&lineLoopFirstIdx, indices, sizeof(lineLoopFirstIdx));
if (primitiveRestartEnabled)
{
// lineLoopFirstIdxLoc: location of current line loop's first vertex in the source buffer.
GLsizei lineLoopFirstIdxLoc = 0;
while (lineLoopFirstIdx == kSrcPrimitiveRestartIndex)
{
memcpy(&dstPtr[lineLoopFirstIdxLoc++], &kDstPrimitiveRestartIndex,
sizeof(kDstPrimitiveRestartIndex));
memcpy(&lineLoopFirstIdx, indices + lineLoopFirstIdxLoc, sizeof(lineLoopFirstIdx));
}
// dstIdx : value of index to be written to dest buffer
uint32_t dstIdx = lineLoopFirstIdx;
memcpy(&dstPtr[lineLoopFirstIdxLoc], &dstIdx, sizeof(dstIdx));
// dstWritten: number of indices written to dest buffer
uint32_t dstWritten = lineLoopFirstIdxLoc + 1;
for (GLsizei i = lineLoopFirstIdxLoc + 1; i < count; ++i)
{
// srcIdx : value of index from source buffer
T srcIdx;
memcpy(&srcIdx, indices + i, sizeof(srcIdx));
if (srcIdx == kSrcPrimitiveRestartIndex)
{
// breaking line strip
dstIdx = lineLoopFirstIdx;
memcpy(&dstPtr[dstWritten++], &dstIdx, sizeof(dstIdx));
memcpy(&dstPtr[dstWritten++], &kDstPrimitiveRestartIndex,
sizeof(kDstPrimitiveRestartIndex));
lineLoopFirstIdxLoc = i + 1;
}
else
{
dstIdx = srcIdx;
memcpy(&dstPtr[dstWritten++], &dstIdx, sizeof(dstIdx));
if (lineLoopFirstIdxLoc == i)
{
lineLoopFirstIdx = srcIdx;
}
}
}
if (lineLoopFirstIdxLoc < count)
{
// last segment
dstIdx = lineLoopFirstIdx;
memcpy(&dstPtr[dstWritten++], &dstIdx, sizeof(dstIdx));
}
*indicesGenerated = dstWritten;
}
else
{ {
T srcPrevIdx, srcIdx; uint32_t dstIdx = lineLoopFirstIdx;
memcpy(&srcPrevIdx, indices + i - 1, sizeof(srcPrevIdx)); memcpy(dstPtr, &dstIdx, sizeof(dstIdx));
memcpy(&srcIdx, indices + i, sizeof(srcIdx)); memcpy(dstPtr + count, &dstIdx, sizeof(dstIdx));
for (GLsizei i = 1; i < count; ++i)
{
T srcIdx;
memcpy(&srcIdx, indices + i, sizeof(srcIdx));
uint32_t triIndices[3]; dstIdx = srcIdx;
triIndices[0] = firstIdx; memcpy(dstPtr + i, &dstIdx, sizeof(dstIdx));
triIndices[1] = srcPrevIdx; }
triIndices[2] = srcIdx;
memcpy(dstPtr + 3 * (i - 2), triIndices, sizeof(triIndices)); *indicesGenerated = count + 1;
} }
dstBuffer->unmap(contextMtl); dstBuffer->unmapAndFlushSubset(contextMtl, dstOffset, (*indicesGenerated) * sizeof(uint32_t));
return angle::Result::Continue; return angle::Result::Continue;
} }
template <typename T> template <typename T>
void GetFirstLastIndicesFromClientElements(GLsizei count, void GetFirstLastIndicesFromClientElements(GLsizei count,
const T *indices, const T *indices,
...@@ -835,8 +1008,9 @@ angle::Result RenderUtils::convertIndexBufferGPU(ContextMtl *contextMtl, ...@@ -835,8 +1008,9 @@ angle::Result RenderUtils::convertIndexBufferGPU(ContextMtl *contextMtl,
{ {
return mIndexUtils.convertIndexBufferGPU(contextMtl, params); return mIndexUtils.convertIndexBufferGPU(contextMtl, params);
} }
angle::Result RenderUtils::generateTriFanBufferFromArrays(ContextMtl *contextMtl, angle::Result RenderUtils::generateTriFanBufferFromArrays(
const TriFanFromArrayParams &params) ContextMtl *contextMtl,
const TriFanOrLineLoopFromArrayParams &params)
{ {
return mIndexUtils.generateTriFanBufferFromArrays(contextMtl, params); return mIndexUtils.generateTriFanBufferFromArrays(contextMtl, params);
} }
...@@ -847,6 +1021,12 @@ angle::Result RenderUtils::generateTriFanBufferFromElementsArray( ...@@ -847,6 +1021,12 @@ angle::Result RenderUtils::generateTriFanBufferFromElementsArray(
return mIndexUtils.generateTriFanBufferFromElementsArray(contextMtl, params); return mIndexUtils.generateTriFanBufferFromElementsArray(contextMtl, params);
} }
angle::Result RenderUtils::generateLineLoopBufferFromArrays(
ContextMtl *contextMtl,
const TriFanOrLineLoopFromArrayParams &params)
{
return mIndexUtils.generateLineLoopBufferFromArrays(contextMtl, params);
}
angle::Result RenderUtils::generateLineLoopLastSegment(ContextMtl *contextMtl, angle::Result RenderUtils::generateLineLoopLastSegment(ContextMtl *contextMtl,
uint32_t firstVertex, uint32_t firstVertex,
uint32_t lastVertex, uint32_t lastVertex,
...@@ -856,6 +1036,14 @@ angle::Result RenderUtils::generateLineLoopLastSegment(ContextMtl *contextMtl, ...@@ -856,6 +1036,14 @@ angle::Result RenderUtils::generateLineLoopLastSegment(ContextMtl *contextMtl,
return mIndexUtils.generateLineLoopLastSegment(contextMtl, firstVertex, lastVertex, dstBuffer, return mIndexUtils.generateLineLoopLastSegment(contextMtl, firstVertex, lastVertex, dstBuffer,
dstOffset); dstOffset);
} }
angle::Result RenderUtils::generateLineLoopBufferFromElementsArray(
ContextMtl *contextMtl,
const IndexGenerationParams &params,
uint32_t *indicesGenerated)
{
return mIndexUtils.generateLineLoopBufferFromElementsArray(contextMtl, params,
indicesGenerated);
}
angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArray( angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArray(
ContextMtl *contextMtl, ContextMtl *contextMtl,
const IndexGenerationParams &params) const IndexGenerationParams &params)
...@@ -1629,8 +1817,10 @@ void IndexGeneratorUtils::onDestroy() ...@@ -1629,8 +1817,10 @@ void IndexGeneratorUtils::onDestroy()
{ {
ClearPipelineState2DArray(&mIndexConversionPipelineCaches); ClearPipelineState2DArray(&mIndexConversionPipelineCaches);
ClearPipelineState2DArray(&mTriFanFromElemArrayGeneratorPipelineCaches); ClearPipelineState2DArray(&mTriFanFromElemArrayGeneratorPipelineCaches);
ClearPipelineState2DArray(&mLineLoopFromElemArrayGeneratorPipelineCaches);
mTriFanFromArraysGeneratorPipeline = nil; mTriFanFromArraysGeneratorPipeline = nil;
mLineLoopFromArraysGeneratorPipeline = nil;
} }
AutoObjCPtr<id<MTLComputePipelineState>> IndexGeneratorUtils::getIndexConversionPipeline( AutoObjCPtr<id<MTLComputePipelineState>> IndexGeneratorUtils::getIndexConversionPipeline(
...@@ -1681,16 +1871,19 @@ AutoObjCPtr<id<MTLComputePipelineState>> IndexGeneratorUtils::getIndexConversion ...@@ -1681,16 +1871,19 @@ AutoObjCPtr<id<MTLComputePipelineState>> IndexGeneratorUtils::getIndexConversion
} }
AutoObjCPtr<id<MTLComputePipelineState>> AutoObjCPtr<id<MTLComputePipelineState>>
IndexGeneratorUtils::getTriFanFromElemArrayGeneratorPipeline(ContextMtl *contextMtl, IndexGeneratorUtils::getIndicesFromElemArrayGeneratorPipeline(
gl::DrawElementsType srcType, ContextMtl *contextMtl,
uint32_t srcOffset) gl::DrawElementsType srcType,
uint32_t srcOffset,
NSString *shaderName,
IndexConversionPipelineArray *pipelineCacheArray)
{ {
size_t elementSize = gl::GetDrawElementsTypeSize(srcType); size_t elementSize = gl::GetDrawElementsTypeSize(srcType);
BOOL aligned = (srcOffset % elementSize) == 0; BOOL aligned = (srcOffset % elementSize) == 0;
int srcTypeKey = static_cast<int>(srcType); int srcTypeKey = static_cast<int>(srcType);
AutoObjCPtr<id<MTLComputePipelineState>> &cache = AutoObjCPtr<id<MTLComputePipelineState>> &cache =
mTriFanFromElemArrayGeneratorPipelineCaches[srcTypeKey][aligned ? 1 : 0]; (*pipelineCacheArray)[srcTypeKey][aligned ? 1 : 0];
if (!cache) if (!cache)
{ {
...@@ -1730,8 +1923,8 @@ IndexGeneratorUtils::getTriFanFromElemArrayGeneratorPipeline(ContextMtl *context ...@@ -1730,8 +1923,8 @@ IndexGeneratorUtils::getTriFanFromElemArrayGeneratorPipeline(ContextMtl *context
type:MTLDataTypeBool type:MTLDataTypeBool
withName:SOURCE_IDX_IS_U32_CONSTANT_NAME]; withName:SOURCE_IDX_IS_U32_CONSTANT_NAME];
EnsureSpecializedComputePipelineInitialized( EnsureSpecializedComputePipelineInitialized(contextMtl->getDisplay(), shaderName,
contextMtl->getDisplay(), @"genTriFanIndicesFromElements", funcConstants, &cache); funcConstants, &cache);
} }
} }
...@@ -1744,6 +1937,12 @@ void IndexGeneratorUtils::ensureTriFanFromArrayGeneratorInitialized(ContextMtl * ...@@ -1744,6 +1937,12 @@ void IndexGeneratorUtils::ensureTriFanFromArrayGeneratorInitialized(ContextMtl *
&mTriFanFromArraysGeneratorPipeline); &mTriFanFromArraysGeneratorPipeline);
} }
void IndexGeneratorUtils::ensureLineLoopFromArrayGeneratorInitialized(ContextMtl *contextMtl)
{
EnsureComputePipelineInitialized(contextMtl->getDisplay(), @"genLineLoopIndicesFromArray",
&mLineLoopFromArraysGeneratorPipeline);
}
angle::Result IndexGeneratorUtils::convertIndexBufferGPU(ContextMtl *contextMtl, angle::Result IndexGeneratorUtils::convertIndexBufferGPU(ContextMtl *contextMtl,
const IndexConversionParams &params) const IndexConversionParams &params)
{ {
...@@ -1760,8 +1959,9 @@ angle::Result IndexGeneratorUtils::convertIndexBufferGPU(ContextMtl *contextMtl, ...@@ -1760,8 +1959,9 @@ angle::Result IndexGeneratorUtils::convertIndexBufferGPU(ContextMtl *contextMtl,
ASSERT((params.dstOffset % kIndexBufferOffsetAlignment) == 0); ASSERT((params.dstOffset % kIndexBufferOffsetAlignment) == 0);
IndexConversionUniform uniform; IndexConversionUniform uniform;
uniform.srcOffset = params.srcOffset; uniform.srcOffset = params.srcOffset;
uniform.indexCount = params.indexCount; uniform.indexCount = params.indexCount;
uniform.primitiveRestartEnabled = params.primitiveRestartEnabled;
cmdEncoder->setData(uniform, 0); cmdEncoder->setData(uniform, 0);
cmdEncoder->setBuffer(params.srcBuffer, 0, 1); cmdEncoder->setBuffer(params.srcBuffer, 0, 1);
...@@ -1774,7 +1974,7 @@ angle::Result IndexGeneratorUtils::convertIndexBufferGPU(ContextMtl *contextMtl, ...@@ -1774,7 +1974,7 @@ angle::Result IndexGeneratorUtils::convertIndexBufferGPU(ContextMtl *contextMtl,
angle::Result IndexGeneratorUtils::generateTriFanBufferFromArrays( angle::Result IndexGeneratorUtils::generateTriFanBufferFromArrays(
ContextMtl *contextMtl, ContextMtl *contextMtl,
const TriFanFromArrayParams &params) const TriFanOrLineLoopFromArrayParams &params)
{ {
ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
ASSERT(cmdEncoder); ASSERT(cmdEncoder);
...@@ -1786,21 +1986,16 @@ angle::Result IndexGeneratorUtils::generateTriFanBufferFromArrays( ...@@ -1786,21 +1986,16 @@ angle::Result IndexGeneratorUtils::generateTriFanBufferFromArrays(
ASSERT((params.dstOffset % kIndexBufferOffsetAlignment) == 0); ASSERT((params.dstOffset % kIndexBufferOffsetAlignment) == 0);
struct TriFanArrayParams TriFanOrLineLoopArrayParams uniform;
{
uint firstVertex;
uint vertexCountFrom3rd;
uint padding[2];
} uniform;
uniform.firstVertex = params.firstVertex; uniform.firstVertex = params.firstVertex;
uniform.vertexCountFrom3rd = params.vertexCount - 2; uniform.vertexCount = params.vertexCount - 2;
cmdEncoder->setData(uniform, 0); cmdEncoder->setData(uniform, 0);
cmdEncoder->setBufferForWrite(params.dstBuffer, params.dstOffset, 2); cmdEncoder->setBufferForWrite(params.dstBuffer, params.dstOffset, 2);
DispatchCompute(contextMtl, cmdEncoder, mTriFanFromArraysGeneratorPipeline, DispatchCompute(contextMtl, cmdEncoder, mTriFanFromArraysGeneratorPipeline,
uniform.vertexCountFrom3rd); uniform.vertexCount);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1817,9 +2012,21 @@ angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArray( ...@@ -1817,9 +2012,21 @@ angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArray(
size_t srcOffset = reinterpret_cast<size_t>(params.indices); size_t srcOffset = reinterpret_cast<size_t>(params.indices);
ANGLE_CHECK(contextMtl, srcOffset <= std::numeric_limits<uint32_t>::max(), ANGLE_CHECK(contextMtl, srcOffset <= std::numeric_limits<uint32_t>::max(),
"Index offset is too large", GL_INVALID_VALUE); "Index offset is too large", GL_INVALID_VALUE);
return generateTriFanBufferFromElementsArrayGPU( if (params.primitiveRestartEnabled ||
contextMtl, params.srcType, params.indexCount, elementBufferMtl->getCurrentBuffer(), (!contextMtl->getDisplay()->getFeatures().hasCheapRenderPass.enabled &&
static_cast<uint32_t>(srcOffset), params.dstBuffer, params.dstOffset); contextMtl->getRenderCommandEncoder()))
{
IndexGenerationParams cpuPathParams = params;
cpuPathParams.indices =
elementBufferMtl->getClientShadowCopyData(contextMtl) + srcOffset;
return generateTriFanBufferFromElementsArrayCPU(contextMtl, cpuPathParams);
}
else
{
return generateTriFanBufferFromElementsArrayGPU(
contextMtl, params.srcType, params.indexCount, elementBufferMtl->getCurrentBuffer(),
static_cast<uint32_t>(srcOffset), params.dstBuffer, params.dstOffset);
}
} }
else else
{ {
...@@ -1841,7 +2048,9 @@ angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayGPU( ...@@ -1841,7 +2048,9 @@ angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayGPU(
ASSERT(cmdEncoder); ASSERT(cmdEncoder);
AutoObjCPtr<id<MTLComputePipelineState>> pipelineState = AutoObjCPtr<id<MTLComputePipelineState>> pipelineState =
getTriFanFromElemArrayGeneratorPipeline(contextMtl, srcType, srcOffset); getIndicesFromElemArrayGeneratorPipeline(contextMtl, srcType, srcOffset,
@"genTriFanIndicesFromElements",
&mTriFanFromElemArrayGeneratorPipelineCaches);
ASSERT(pipelineState); ASSERT(pipelineState);
...@@ -1870,17 +2079,147 @@ angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayCPU( ...@@ -1870,17 +2079,147 @@ angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayCPU(
switch (params.srcType) switch (params.srcType)
{ {
case gl::DrawElementsType::UnsignedByte: case gl::DrawElementsType::UnsignedByte:
return GenTriFanFromClientElements(contextMtl, params.indexCount, return GenTriFanFromClientElements(
static_cast<const uint8_t *>(params.indices), contextMtl, params.indexCount, params.primitiveRestartEnabled,
params.dstBuffer, params.dstOffset); static_cast<const uint8_t *>(params.indices), params.dstBuffer, params.dstOffset);
case gl::DrawElementsType::UnsignedShort: case gl::DrawElementsType::UnsignedShort:
return GenTriFanFromClientElements(contextMtl, params.indexCount, return GenTriFanFromClientElements(
static_cast<const uint16_t *>(params.indices), contextMtl, params.indexCount, params.primitiveRestartEnabled,
params.dstBuffer, params.dstOffset); static_cast<const uint16_t *>(params.indices), params.dstBuffer, params.dstOffset);
case gl::DrawElementsType::UnsignedInt: case gl::DrawElementsType::UnsignedInt:
return GenTriFanFromClientElements(contextMtl, params.indexCount, return GenTriFanFromClientElements(
static_cast<const uint32_t *>(params.indices), contextMtl, params.indexCount, params.primitiveRestartEnabled,
params.dstBuffer, params.dstOffset); static_cast<const uint32_t *>(params.indices), params.dstBuffer, params.dstOffset);
default:
UNREACHABLE();
}
return angle::Result::Stop;
}
angle::Result IndexGeneratorUtils::generateLineLoopBufferFromArrays(
ContextMtl *contextMtl,
const TriFanOrLineLoopFromArrayParams &params)
{
ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
ASSERT(cmdEncoder);
ensureLineLoopFromArrayGeneratorInitialized(contextMtl);
cmdEncoder->setComputePipelineState(mLineLoopFromArraysGeneratorPipeline);
ASSERT((params.dstOffset % kIndexBufferOffsetAlignment) == 0);
TriFanOrLineLoopArrayParams uniform;
uniform.firstVertex = params.firstVertex;
uniform.vertexCount = params.vertexCount;
cmdEncoder->setData(uniform, 0);
cmdEncoder->setBufferForWrite(params.dstBuffer, params.dstOffset, 2);
DispatchCompute(contextMtl, cmdEncoder, mLineLoopFromArraysGeneratorPipeline,
uniform.vertexCount + 1);
return angle::Result::Continue;
}
angle::Result IndexGeneratorUtils::generateLineLoopBufferFromElementsArray(
ContextMtl *contextMtl,
const IndexGenerationParams &params,
uint32_t *indicesGenerated)
{
const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray();
const gl::Buffer *elementBuffer = vertexArray->getElementArrayBuffer();
if (elementBuffer)
{
BufferMtl *elementBufferMtl = GetImpl(elementBuffer);
size_t srcOffset = reinterpret_cast<size_t>(params.indices);
ANGLE_CHECK(contextMtl, srcOffset <= std::numeric_limits<uint32_t>::max(),
"Index offset is too large", GL_INVALID_VALUE);
if (params.primitiveRestartEnabled ||
(!contextMtl->getDisplay()->getFeatures().hasCheapRenderPass.enabled &&
contextMtl->getRenderCommandEncoder()))
{
IndexGenerationParams cpuPathParams = params;
cpuPathParams.indices =
elementBufferMtl->getClientShadowCopyData(contextMtl) + srcOffset;
return generateLineLoopBufferFromElementsArrayCPU(contextMtl, cpuPathParams,
indicesGenerated);
}
else
{
*indicesGenerated = params.indexCount + 1;
return generateLineLoopBufferFromElementsArrayGPU(
contextMtl, params.srcType, params.indexCount, elementBufferMtl->getCurrentBuffer(),
static_cast<uint32_t>(srcOffset), params.dstBuffer, params.dstOffset);
}
}
else
{
return generateLineLoopBufferFromElementsArrayCPU(contextMtl, params, indicesGenerated);
}
}
angle::Result IndexGeneratorUtils::generateLineLoopBufferFromElementsArrayGPU(
ContextMtl *contextMtl,
gl::DrawElementsType srcType,
uint32_t indexCount,
const BufferRef &srcBuffer,
uint32_t srcOffset,
const BufferRef &dstBuffer,
// Must be multiples of kIndexBufferOffsetAlignment
uint32_t dstOffset)
{
ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
ASSERT(cmdEncoder);
AutoObjCPtr<id<MTLComputePipelineState>> pipelineState =
getIndicesFromElemArrayGeneratorPipeline(contextMtl, srcType, srcOffset,
@"genLineLoopIndicesFromElements",
&mLineLoopFromElemArrayGeneratorPipelineCaches);
ASSERT(pipelineState);
cmdEncoder->setComputePipelineState(pipelineState);
ASSERT((dstOffset % kIndexBufferOffsetAlignment) == 0);
ASSERT(indexCount >= 2);
IndexConversionUniform uniform;
uniform.srcOffset = srcOffset;
uniform.indexCount = indexCount;
cmdEncoder->setData(uniform, 0);
cmdEncoder->setBuffer(srcBuffer, 0, 1);
cmdEncoder->setBufferForWrite(dstBuffer, dstOffset, 2);
DispatchCompute(contextMtl, cmdEncoder, pipelineState, uniform.indexCount + 1);
return angle::Result::Continue;
}
angle::Result IndexGeneratorUtils::generateLineLoopBufferFromElementsArrayCPU(
ContextMtl *contextMtl,
const IndexGenerationParams &params,
uint32_t *indicesGenerated)
{
switch (params.srcType)
{
case gl::DrawElementsType::UnsignedByte:
return GenLineLoopFromClientElements(
contextMtl, params.indexCount, params.primitiveRestartEnabled,
static_cast<const uint8_t *>(params.indices), params.dstBuffer, params.dstOffset,
indicesGenerated);
case gl::DrawElementsType::UnsignedShort:
return GenLineLoopFromClientElements(
contextMtl, params.indexCount, params.primitiveRestartEnabled,
static_cast<const uint16_t *>(params.indices), params.dstBuffer, params.dstOffset,
indicesGenerated);
case gl::DrawElementsType::UnsignedInt:
return GenLineLoopFromClientElements(
contextMtl, params.indexCount, params.primitiveRestartEnabled,
static_cast<const uint32_t *>(params.indices), params.dstBuffer, params.dstOffset,
indicesGenerated);
default: default:
UNREACHABLE(); UNREACHABLE();
} }
...@@ -1899,7 +2238,7 @@ angle::Result IndexGeneratorUtils::generateLineLoopLastSegment(ContextMtl *conte ...@@ -1899,7 +2238,7 @@ angle::Result IndexGeneratorUtils::generateLineLoopLastSegment(ContextMtl *conte
uint32_t indices[2] = {lastVertex, firstVertex}; uint32_t indices[2] = {lastVertex, firstVertex};
memcpy(ptr, indices, sizeof(indices)); memcpy(ptr, indices, sizeof(indices));
dstBuffer->unmap(contextMtl); dstBuffer->unmapAndFlushSubset(contextMtl, dstOffset, sizeof(indices));
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1908,6 +2247,7 @@ angle::Result IndexGeneratorUtils::generateLineLoopLastSegmentFromElementsArray( ...@@ -1908,6 +2247,7 @@ angle::Result IndexGeneratorUtils::generateLineLoopLastSegmentFromElementsArray(
ContextMtl *contextMtl, ContextMtl *contextMtl,
const IndexGenerationParams &params) const IndexGenerationParams &params)
{ {
ASSERT(!params.primitiveRestartEnabled);
const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray(); const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray();
const gl::Buffer *elementBuffer = vertexArray->getElementArrayBuffer(); const gl::Buffer *elementBuffer = vertexArray->getElementArrayBuffer();
if (elementBuffer) if (elementBuffer)
...@@ -1935,6 +2275,8 @@ angle::Result IndexGeneratorUtils::generateLineLoopLastSegmentFromElementsArrayC ...@@ -1935,6 +2275,8 @@ angle::Result IndexGeneratorUtils::generateLineLoopLastSegmentFromElementsArrayC
ContextMtl *contextMtl, ContextMtl *contextMtl,
const IndexGenerationParams &params) const IndexGenerationParams &params)
{ {
ASSERT(!params.primitiveRestartEnabled);
uint32_t first, last; uint32_t first, last;
switch (params.srcType) switch (params.srcType)
......
...@@ -756,7 +756,7 @@ angle::Result Buffer::resetWithSharedMemOpt(ContextMtl *context, ...@@ -756,7 +756,7 @@ angle::Result Buffer::resetWithSharedMemOpt(ContextMtl *context,
options = 0; options = 0;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
if (!forceUseSharedMem) if (!forceUseSharedMem || context->getDisplay()->getFeatures().forceBufferGPUStorage.enabled)
{ {
options |= MTLResourceStorageModeManaged; options |= MTLResourceStorageModeManaged;
} }
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
namespace rx namespace rx
{ {
class ContextMtl;
namespace mtl namespace mtl
{ {
...@@ -146,6 +149,12 @@ gl::Box MTLRegionToGLBox(const MTLRegion &mtlRegion); ...@@ -146,6 +149,12 @@ gl::Box MTLRegionToGLBox(const MTLRegion &mtlRegion);
MipmapNativeLevel GetNativeMipLevel(GLuint level, GLuint base); MipmapNativeLevel GetNativeMipLevel(GLuint level, GLuint base);
GLuint GetGLMipLevel(const MipmapNativeLevel &nativeLevel, GLuint base); GLuint GetGLMipLevel(const MipmapNativeLevel &nativeLevel, GLuint base);
angle::Result TriangleFanBoundCheck(ContextMtl *context, size_t numTris);
angle::Result GetTriangleFanIndicesCount(ContextMtl *context,
GLsizei vetexCount,
uint32_t *numElemsOut);
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
} // namespace mtl } // namespace mtl
} // namespace rx } // namespace rx
......
...@@ -855,5 +855,32 @@ GLuint GetGLMipLevel(const MipmapNativeLevel &nativeLevel, GLuint base) ...@@ -855,5 +855,32 @@ GLuint GetGLMipLevel(const MipmapNativeLevel &nativeLevel, GLuint base)
return nativeLevel.get() + base; return nativeLevel.get() + base;
} }
angle::Result TriangleFanBoundCheck(ContextMtl *context, size_t numTris)
{
bool indexCheck =
(numTris > std::numeric_limits<unsigned int>::max() / (sizeof(unsigned int) * 3));
ANGLE_CHECK(context, !indexCheck,
"Failed to create a scratch index buffer for GL_TRIANGLE_FAN, "
"too many indices required.",
GL_OUT_OF_MEMORY);
return angle::Result::Continue;
}
angle::Result GetTriangleFanIndicesCount(ContextMtl *context,
GLsizei vetexCount,
uint32_t *numElemsOut)
{
size_t numTris = vetexCount - 2;
ANGLE_TRY(TriangleFanBoundCheck(context, numTris));
size_t numIndices = numTris * 3;
ANGLE_CHECK(context, numIndices <= std::numeric_limits<uint32_t>::max(),
"Failed to create a scratch index buffer for GL_TRIANGLE_FAN, "
"too many indices required.",
GL_OUT_OF_MEMORY);
*numElemsOut = static_cast<uint32_t>(numIndices);
return angle::Result::Continue;
}
} // namespace mtl } // namespace mtl
} // namespace rx } // namespace rx
...@@ -22,6 +22,7 @@ struct IndexConversionParams ...@@ -22,6 +22,7 @@ struct IndexConversionParams
{ {
uint32_t srcOffset; // offset in bytes uint32_t srcOffset; // offset in bytes
uint32_t indexCount; uint32_t indexCount;
bool primitiveRestartEnabled;
}; };
#define ANGLE_IDX_CONVERSION_GUARD(IDX, OPTS) ANGLE_KERNEL_GUARD(IDX, OPTS.indexCount) #define ANGLE_IDX_CONVERSION_GUARD(IDX, OPTS) ANGLE_KERNEL_GUARD(IDX, OPTS.indexCount)
...@@ -61,7 +62,17 @@ kernel void convertIndexU8ToU16(uint idx[[thread_position_in_grid]], ...@@ -61,7 +62,17 @@ kernel void convertIndexU8ToU16(uint idx[[thread_position_in_grid]],
device ushort *output[[buffer(2)]]) device ushort *output[[buffer(2)]])
{ {
ANGLE_IDX_CONVERSION_GUARD(idx, options); ANGLE_IDX_CONVERSION_GUARD(idx, options);
output[idx] = getIndexAligned(input, options.srcOffset, idx);
uchar value = getIndexAligned(input, options.srcOffset, idx);
if (options.primitiveRestartEnabled && value == 0xff)
{
output[idx] = 0xffff;
}
else
{
output[idx] = value;
}
} }
kernel void convertIndexU16( kernel void convertIndexU16(
...@@ -106,16 +117,19 @@ kernel void convertIndexU32( ...@@ -106,16 +117,19 @@ kernel void convertIndexU32(
output[idx] = value; output[idx] = value;
} }
struct TriFanArrayParams struct IndexFromArrayParams
{ {
uint firstVertex; uint firstVertex;
uint vertexCountFrom3rd; // vertex count excluding the 1st & 2nd vertices. // For triangle fan: vertex count excluding the 1st & 2nd vertices.
uint vertexCount;
}; };
kernel void genTriFanIndicesFromArray(uint idx[[thread_position_in_grid]],
constant TriFanArrayParams &options[[buffer(0)]], // Generate triangle fan indices for glDrawArray()
device uint *output[[buffer(2)]]) kernel void genTriFanIndicesFromArray(uint idx [[thread_position_in_grid]],
constant IndexFromArrayParams &options [[buffer(0)]],
device uint *output [[buffer(2)]])
{ {
ANGLE_KERNEL_GUARD(idx, options.vertexCountFrom3rd); ANGLE_KERNEL_GUARD(idx, options.vertexCount);
uint vertexIdx = options.firstVertex + 2 + idx; uint vertexIdx = options.firstVertex + 2 + idx;
...@@ -153,6 +167,7 @@ inline uint getIndexU32(uint offset, ...@@ -153,6 +167,7 @@ inline uint getIndexU32(uint offset,
return 0; return 0;
} }
// NOTE(hqle): triangle fan indices generation doesn't support primitive restart.
// Generate triangle fan indices from an indices buffer. indexCount options indicates number // Generate triangle fan indices from an indices buffer. indexCount options indicates number
// of indices starting from the 3rd. // of indices starting from the 3rd.
kernel void genTriFanIndicesFromElements( kernel void genTriFanIndicesFromElements(
...@@ -170,4 +185,34 @@ kernel void genTriFanIndicesFromElements( ...@@ -170,4 +185,34 @@ kernel void genTriFanIndicesFromElements(
output[3 * idx] = getIndexU32(options.srcOffset, 0, inputU8, inputU16, inputU32); output[3 * idx] = getIndexU32(options.srcOffset, 0, inputU8, inputU16, inputU32);
output[3 * idx + 1] = getIndexU32(options.srcOffset, elemIdx - 1, inputU8, inputU16, inputU32); output[3 * idx + 1] = getIndexU32(options.srcOffset, elemIdx - 1, inputU8, inputU16, inputU32);
output[3 * idx + 2] = getIndexU32(options.srcOffset, elemIdx, inputU8, inputU16, inputU32); output[3 * idx + 2] = getIndexU32(options.srcOffset, elemIdx, inputU8, inputU16, inputU32);
}
// Generate line loop indices for glDrawArray()
kernel void genLineLoopIndicesFromArray(uint idx [[thread_position_in_grid]],
constant IndexFromArrayParams &options [[buffer(0)]],
device uint *output [[buffer(2)]])
{
uint totalIndices = options.vertexCount + 1;
ANGLE_KERNEL_GUARD(idx, totalIndices);
output[idx] = options.firstVertex + idx % options.vertexCount;
}
// NOTE(hqle): lineloop indices generation doesn't support primitive restart.
// Generate line loop indices for glDrawElements()
kernel void genLineLoopIndicesFromElements(uint idx [[thread_position_in_grid]],
constant IndexConversionParams &options [[buffer(0)]],
constant uchar *inputU8
[[buffer(1), function_constant(kUseSourceBufferU8)]],
constant ushort *inputU16
[[buffer(1), function_constant(kUseSourceBufferU16)]],
constant uint *inputU32
[[buffer(1), function_constant(kUseSourceBufferU32)]],
device uint *output [[buffer(2)]])
{
uint totalTargetIndices = options.indexCount + 1;
ANGLE_KERNEL_GUARD(idx, totalTargetIndices);
output[idx] =
getIndexU32(options.srcOffset, idx % options.indexCount, inputU8, inputU16, inputU32);
} }
\ No newline at end of file
...@@ -725,6 +725,7 @@ struct IndexConversionParams ...@@ -725,6 +725,7 @@ struct IndexConversionParams
{ {
uint32_t srcOffset; uint32_t srcOffset;
uint32_t indexCount; uint32_t indexCount;
bool primitiveRestartEnabled;
}; };
...@@ -764,7 +765,17 @@ kernel void convertIndexU8ToU16(uint idx[[thread_position_in_grid]], ...@@ -764,7 +765,17 @@ kernel void convertIndexU8ToU16(uint idx[[thread_position_in_grid]],
device ushort *output[[buffer(2)]]) device ushort *output[[buffer(2)]])
{ {
if (idx >= options.indexCount) { return; }; if (idx >= options.indexCount) { return; };
output[idx] = getIndexAligned(input, options.srcOffset, idx);
uchar value = getIndexAligned(input, options.srcOffset, idx);
if (options.primitiveRestartEnabled && value == 0xff)
{
output[idx] = 0xffff;
}
else
{
output[idx] = value;
}
} }
kernel void convertIndexU16( kernel void convertIndexU16(
...@@ -809,16 +820,19 @@ kernel void convertIndexU32( ...@@ -809,16 +820,19 @@ kernel void convertIndexU32(
output[idx] = value; output[idx] = value;
} }
struct TriFanArrayParams struct IndexFromArrayParams
{ {
uint firstVertex; uint firstVertex;
uint vertexCountFrom3rd;
uint vertexCount;
}; };
kernel void genTriFanIndicesFromArray(uint idx[[thread_position_in_grid]],
constant TriFanArrayParams &options[[buffer(0)]],
device uint *output[[buffer(2)]]) kernel void genTriFanIndicesFromArray(uint idx [[thread_position_in_grid]],
constant IndexFromArrayParams &options [[buffer(0)]],
device uint *output [[buffer(2)]])
{ {
if (idx >= options.vertexCountFrom3rd) { return; }; if (idx >= options.vertexCount) { return; };
uint vertexIdx = options.firstVertex + 2 + idx; uint vertexIdx = options.firstVertex + 2 + idx;
...@@ -858,6 +872,7 @@ inline uint getIndexU32(uint offset, ...@@ -858,6 +872,7 @@ inline uint getIndexU32(uint offset,
kernel void genTriFanIndicesFromElements( kernel void genTriFanIndicesFromElements(
uint idx[[thread_position_in_grid]], uint idx[[thread_position_in_grid]],
constant IndexConversionParams &options[[buffer(0)]], constant IndexConversionParams &options[[buffer(0)]],
...@@ -874,6 +889,36 @@ kernel void genTriFanIndicesFromElements( ...@@ -874,6 +889,36 @@ kernel void genTriFanIndicesFromElements(
output[3 * idx + 1] = getIndexU32(options.srcOffset, elemIdx - 1, inputU8, inputU16, inputU32); output[3 * idx + 1] = getIndexU32(options.srcOffset, elemIdx - 1, inputU8, inputU16, inputU32);
output[3 * idx + 2] = getIndexU32(options.srcOffset, elemIdx, inputU8, inputU16, inputU32); output[3 * idx + 2] = getIndexU32(options.srcOffset, elemIdx, inputU8, inputU16, inputU32);
} }
kernel void genLineLoopIndicesFromArray(uint idx [[thread_position_in_grid]],
constant IndexFromArrayParams &options [[buffer(0)]],
device uint *output [[buffer(2)]])
{
uint totalIndices = options.vertexCount + 1;
if (idx >= totalIndices) { return; };
output[idx] = options.firstVertex + idx % options.vertexCount;
}
kernel void genLineLoopIndicesFromElements(uint idx [[thread_position_in_grid]],
constant IndexConversionParams &options [[buffer(0)]],
constant uchar *inputU8
[[buffer(1), function_constant(kUseSourceBufferU8)]],
constant ushort *inputU16
[[buffer(1), function_constant(kUseSourceBufferU16)]],
constant uint *inputU32
[[buffer(1), function_constant(kUseSourceBufferU32)]],
device uint *output [[buffer(2)]])
{
uint totalTargetIndices = options.indexCount + 1;
if (idx >= totalTargetIndices) { return; };
output[idx] =
getIndexU32(options.srcOffset, idx % options.indexCount, inputU8, inputU16, inputU32);
}
# 4 "temp_master_source.metal" 2 # 4 "temp_master_source.metal" 2
# 1 "./gen_mipmap.metal" 1 # 1 "./gen_mipmap.metal" 1
......
...@@ -495,23 +495,31 @@ attribute vec2 a_position; ...@@ -495,23 +495,31 @@ attribute vec2 a_position;
// x,y = offset, z = scale // x,y = offset, z = scale
attribute vec3 a_transform; attribute vec3 a_transform;
attribute vec4 a_color;
varying vec4 v_color;
invariant gl_Position; invariant gl_Position;
void main() void main()
{ {
vec2 v_position = a_transform.z * a_position + a_transform.xy; vec2 v_position = a_transform.z * a_position + a_transform.xy;
gl_Position = vec4(v_position, 0.0, 1.0); gl_Position = vec4(v_position, 0.0, 1.0);
v_color = a_color;
})"; })";
constexpr char kFS[] = R"( constexpr char kFS[] = R"(
precision highp float; precision highp float;
varying vec4 v_color;
void main() void main()
{ {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); gl_FragColor = v_color;
})"; })";
ANGLE_GL_PROGRAM(program, kVS, kFS); ANGLE_GL_PROGRAM(program, kVS, kFS);
glBindAttribLocation(program, 0, "a_position"); glBindAttribLocation(program, 0, "a_position");
glBindAttribLocation(program, 1, "a_transform"); glBindAttribLocation(program, 1, "a_transform");
glBindAttribLocation(program, 2, "a_color");
glLinkProgram(program); glLinkProgram(program);
glUseProgram(program); glUseProgram(program);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
...@@ -524,13 +532,18 @@ void main() ...@@ -524,13 +532,18 @@ void main()
0, 0, 9, 0.2, 0.1, 2, 0.5, -0.2, 3, -0.8, -0.5, 1, -0.4, 0.4, 6, 0, 0, 9, 0.2, 0.1, 2, 0.5, -0.2, 3, -0.8, -0.5, 1, -0.4, 0.4, 6,
}; };
constexpr GLushort lineloopAsStripIndices[] = {0, 1, 2, 3, 0};
constexpr GLsizei instances = ArraySize(transform) / 3; constexpr GLsizei instances = ArraySize(transform) / 3;
const GLfloat colors[instances * 3] = {
1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0,
};
constexpr GLushort lineloopAsStripIndices[] = {0, 1, 2, 3, 0};
std::vector<GLColor> expectedPixels(getWindowWidth() * getWindowHeight()); std::vector<GLColor> expectedPixels(getWindowWidth() * getWindowHeight());
// Draw in non-instanced way // Draw in non-instanced way
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
...@@ -545,6 +558,7 @@ void main() ...@@ -545,6 +558,7 @@ void main()
for (size_t i = 0; i < instances; ++i) for (size_t i = 0; i < instances; ++i)
{ {
glVertexAttrib3fv(1, transform + 3 * i); glVertexAttrib3fv(1, transform + 3 * i);
glVertexAttrib3fv(2, colors + 3 * i);
glDrawElements(GL_LINE_STRIP, ArraySize(lineloopAsStripIndices), GL_UNSIGNED_SHORT, glDrawElements(GL_LINE_STRIP, ArraySize(lineloopAsStripIndices), GL_UNSIGNED_SHORT,
lineloopAsStripIndices); lineloopAsStripIndices);
...@@ -557,7 +571,7 @@ void main() ...@@ -557,7 +571,7 @@ void main()
// Draw in instanced way: // Draw in instanced way:
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
GLBuffer vertexBuffer[2]; GLBuffer vertexBuffer[3];
GLBuffer indexBuffer; GLBuffer indexBuffer;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
...@@ -576,6 +590,12 @@ void main() ...@@ -576,6 +590,12 @@ void main()
glVertexAttribDivisorANGLE(1, 1); glVertexAttribDivisorANGLE(1, 1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribDivisorANGLE(2, 1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArraysInstancedANGLE(GL_LINE_LOOP, 0, ArraySize(vertices) / 2, instances); glDrawArraysInstancedANGLE(GL_LINE_LOOP, 0, ArraySize(vertices) / 2, instances);
std::vector<GLColor> actualPixels(getWindowWidth() * getWindowHeight()); std::vector<GLColor> actualPixels(getWindowWidth() * getWindowHeight());
......
...@@ -57,9 +57,9 @@ class LineLoopTest : public ANGLETest ...@@ -57,9 +57,9 @@ class LineLoopTest : public ANGLETest
{ {
const GLubyte *pixel = &pixels[0] + ((y * getWindowWidth() + x) * 4); const GLubyte *pixel = &pixels[0] + ((y * getWindowWidth() + x) * 4);
EXPECT_EQ(pixel[0], 0); EXPECT_EQ(pixel[0], 0) << "Failed at " << x << ", " << y << std::endl;
EXPECT_EQ(pixel[1], pixel[2]); EXPECT_EQ(pixel[1], pixel[2]) << "Failed at " << x << ", " << y << std::endl;
ASSERT_EQ(pixel[3], 255); ASSERT_EQ(pixel[3], 255) << "Failed at " << x << ", " << y << std::endl;
} }
} }
} }
...@@ -202,6 +202,166 @@ TEST_P(LineLoopTest, DISABLED_DrawArraysWithLargeCount) ...@@ -202,6 +202,166 @@ TEST_P(LineLoopTest, DISABLED_DrawArraysWithLargeCount)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
class LineLoopPrimitiveRestartTest : public ANGLETest
{
protected:
LineLoopPrimitiveRestartTest()
{
setWindowWidth(64);
setWindowHeight(64);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
};
TEST_P(LineLoopPrimitiveRestartTest, LineLoopWithPrimitiveRestart)
{
constexpr char kVS[] = R"(#version 300 es
in vec2 a_position;
// x,y = offset, z = scale
in vec3 a_transform;
invariant gl_Position;
void main()
{
vec2 v_position = a_transform.z * a_position + a_transform.xy;
gl_Position = vec4(v_position, 0.0, 1.0);
})";
constexpr char kFS[] = R"(#version 300 es
precision highp float;
layout (location=0) out vec4 fragColor;
void main()
{
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
})";
ANGLE_GL_PROGRAM(program, kVS, kFS);
glBindAttribLocation(program, 0, "a_position");
glBindAttribLocation(program, 1, "a_transform");
glLinkProgram(program);
glUseProgram(program);
ASSERT_GL_NO_ERROR();
// clang-format off
constexpr GLfloat vertices[] = {
0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
};
constexpr GLfloat transform[] = {
// first loop transform
0, 0, 9,
0, 0, 9,
0, 0, 9,
0, 0, 9,
// second loop transform
0.2, 0.1, 2,
0.2, 0.1, 2,
0.2, 0.1, 2,
0.2, 0.1, 2,
// third loop transform
0.5, -0.2, 3,
0.5, -0.2, 3,
0.5, -0.2, 3,
0.5, -0.2, 3,
// forth loop transform
-0.8, -0.5, 1,
-0.8, -0.5, 1,
-0.8, -0.5, 1,
-0.8, -0.5, 1,
};
constexpr GLushort lineloopAsStripIndices[] = {
// first strip
0, 1, 2, 3, 0,
// second strip
4, 5, 6, 7, 4,
// third strip
8, 9, 10, 11, 8,
// forth strip
12, 13, 14, 15, 12 };
constexpr GLushort lineloopWithRestartIndices[] = {
// first loop
0, 1, 2, 3, 0xffff,
// second loop
4, 5, 6, 7, 0xffff,
// third loop
8, 9, 10, 11, 0xffff,
// forth loop
12, 13, 14, 15,
};
// clang-format on
std::vector<GLColor> expectedPixels(getWindowWidth() * getWindowHeight());
std::vector<GLColor> renderedPixels(getWindowWidth() * getWindowHeight());
// Draw in non-primitive restart way
glClear(GL_COLOR_BUFFER_BIT);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
for (int loop = 0; loop < 4; ++loop)
{
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices + 8 * loop);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, transform + 12 * loop);
glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, lineloopAsStripIndices);
}
glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
expectedPixels.data());
ASSERT_GL_NO_ERROR();
// Draw line loop with primitive restart:
glClear(GL_COLOR_BUFFER_BIT);
GLBuffer vertexBuffer[2];
GLBuffer indexBuffer;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(lineloopWithRestartIndices),
lineloopWithRestartIndices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(transform), transform, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_LINE_LOOP, ArraySize(lineloopWithRestartIndices), GL_UNSIGNED_SHORT, 0);
glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
renderedPixels.data());
for (int y = 0; y < getWindowHeight(); ++y)
{
for (int x = 0; x < getWindowWidth(); ++x)
{
int idx = y * getWindowWidth() + x;
EXPECT_EQ(expectedPixels[idx], renderedPixels[idx])
<< "Expected pixel at " << x << ", " << y << " to be " << expectedPixels[idx]
<< std::endl;
}
}
}
class LineLoopIndirectTest : public LineLoopTest class LineLoopIndirectTest : public LineLoopTest
{ {
protected: protected:
...@@ -318,4 +478,12 @@ TEST_P(LineLoopIndirectTest, UShortIndexIndirectBuffer) ...@@ -318,4 +478,12 @@ TEST_P(LineLoopIndirectTest, UShortIndexIndirectBuffer)
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2(LineLoopTest); ANGLE_INSTANTIATE_TEST_ES2(LineLoopTest);
ANGLE_INSTANTIATE_TEST_ES3_AND(
LineLoopPrimitiveRestartTest,
ES3_METAL(),
WithMetalForcedBufferGPUStorage(ES3_METAL()),
WithMetalMemoryBarrierAndCheapRenderPass(ES3_METAL(),
/* hasBarrier */ false,
/* cheapRenderPass */ false));
ANGLE_INSTANTIATE_TEST_ES31(LineLoopIndirectTest); ANGLE_INSTANTIATE_TEST_ES31(LineLoopIndirectTest);
...@@ -132,6 +132,9 @@ TEST_P(OcclusionQueriesTest, ClearNotCounted) ...@@ -132,6 +132,9 @@ TEST_P(OcclusionQueriesTest, ClearNotCounted)
// http://anglebug.com/4925 // http://anglebug.com/4925
ANGLE_SKIP_TEST_IF(IsD3D11()); ANGLE_SKIP_TEST_IF(IsD3D11());
// http://anglebug.com/5307
ANGLE_SKIP_TEST_IF(IsMetal() && IsNVIDIA());
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
......
...@@ -464,57 +464,184 @@ TEST_P(SimpleOperationTest, DrawLineStrip) ...@@ -464,57 +464,184 @@ TEST_P(SimpleOperationTest, DrawLineStrip)
} }
} }
class TriangleFanDrawTest : public SimpleOperationTest
{
protected:
void testSetUp() override
{
// We assume in the test the width and height are equal and we are tracing
// 2 triangles to cover half the surface like this:
ASSERT_EQ(getWindowWidth(), getWindowHeight());
mProgram.makeRaster(kBasicVertexShader, kGreenFragmentShader);
ASSERT_TRUE(mProgram.valid());
glUseProgram(mProgram);
const GLint positionLocation = glGetAttribLocation(mProgram, "position");
ASSERT_NE(-1, positionLocation);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer.get());
glBufferData(GL_ARRAY_BUFFER, sizeof(mVertices[0]) * mVertices.size(), mVertices.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(positionLocation);
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
void readPixels()
{
if (mReadPixels.empty())
{
mReadPixels.resize(getWindowWidth() * getWindowWidth());
}
glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
mReadPixels.data());
EXPECT_GL_NO_ERROR();
}
void verifyPixelAt(int x, int y, const GLColor &expected)
{
EXPECT_EQ(mReadPixels[y * getWindowWidth() + x], expected);
}
void verifyTriangles()
{
readPixels();
// Check 4 lines accross de triangles to make sure we filled it.
// Don't check every pixel as it would slow down our tests.
for (auto x = 0; x < getWindowWidth(); x++)
{
verifyPixelAt(x, x, GLColor::green);
}
for (auto x = getWindowWidth() / 3, y = 0; x < getWindowWidth(); x++, y++)
{
verifyPixelAt(x, y, GLColor::green);
}
for (auto x = getWindowWidth() / 2, y = 0; x < getWindowWidth(); x++, y++)
{
verifyPixelAt(x, y, GLColor::green);
}
for (auto x = (getWindowWidth() / 4) * 3, y = 0; x < getWindowWidth(); x++, y++)
{
verifyPixelAt(x, y, GLColor::green);
}
// Area outside triangles
for (auto x = 0; x < getWindowWidth() - 2; x++)
{
verifyPixelAt(x, x + 2, GLColor::red);
}
}
const std::vector<Vector3> mVertices = {{0.0f, 0.0f, 0.0f},
{-1.0f, -1.0f, 0.0f},
{0.0f, -1.0f, 0.0f},
{1.0f, -1.0f, 0.0f},
{1.0f, 1.0f, 0.0f}};
GLBuffer mVertexBuffer;
GLProgram mProgram;
std::vector<GLColor> mReadPixels;
};
// Simple triangle fans test. // Simple triangle fans test.
TEST_P(SimpleOperationTest, DrawTriangleFan) TEST_P(TriangleFanDrawTest, DrawTriangleFan)
{ {
// We assume in the test the width and height are equal and we are tracing glClear(GL_COLOR_BUFFER_BIT);
// 2 triangles to cover half the surface like this: glDrawArrays(GL_TRIANGLE_FAN, 0, static_cast<GLsizei>(mVertices.size()));
ASSERT_EQ(getWindowWidth(), getWindowHeight());
ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader); EXPECT_GL_NO_ERROR();
glUseProgram(program);
auto vertices = std::vector<Vector3>{ verifyTriangles();
{-1.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}}; }
const GLint positionLocation = glGetAttribLocation(program, "position"); // Triangle fans test with index buffer.
ASSERT_NE(-1, positionLocation); TEST_P(TriangleFanDrawTest, DrawTriangleFanElements)
{
std::vector<GLubyte> indices = {0, 1, 2, 3, 4};
GLBuffer vertexBuffer; GLBuffer indexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get()); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(), glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
GL_STATIC_DRAW); GL_STATIC_DRAW);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(positionLocation);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_FAN, 0, static_cast<GLsizei>(vertices.size())); glDrawElements(GL_TRIANGLE_FAN, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_BYTE, 0);
glDisableVertexAttribArray(positionLocation); EXPECT_GL_NO_ERROR();
verifyTriangles();
}
// Triangle fans test with primitive restart index at the middle.
TEST_P(TriangleFanDrawTest, DrawTriangleFanPrimitiveRestartAtMiddle)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
std::vector<GLubyte> indices = {0, 1, 2, 3, 0xff, 0, 4, 3};
GLBuffer indexBuffer;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
GL_STATIC_DRAW);
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glDrawElements(GL_TRIANGLE_FAN, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_BYTE, 0);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
// Check 4 lines accross de triangles to make sure we filled it. verifyTriangles();
// Don't check every pixel as it would slow down our tests. }
for (auto x = 0; x < getWindowWidth(); x++)
{
EXPECT_PIXEL_COLOR_EQ(x, x, GLColor::green);
}
for (auto x = getWindowWidth() / 3, y = 0; x < getWindowWidth(); x++, y++) // Triangle fans test with primitive restart at begin.
{ TEST_P(TriangleFanDrawTest, DrawTriangleFanPrimitiveRestartAtBegin)
EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green); {
} ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
for (auto x = getWindowWidth() / 2, y = 0; x < getWindowWidth(); x++, y++) // Primitive restart index is at middle, but we will use draw call which index offset=4.
{ std::vector<GLubyte> indices = {0, 1, 2, 3, 0xff, 0, 4, 3};
EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green);
}
for (auto x = (getWindowWidth() / 4) * 3, y = 0; x < getWindowWidth(); x++, y++) GLBuffer indexBuffer;
{ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
} GL_STATIC_DRAW);
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_BYTE, 0);
glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_BYTE,
reinterpret_cast<void *>(sizeof(indices[0]) * 4));
EXPECT_GL_NO_ERROR();
verifyTriangles();
}
// Triangle fans test with primitive restart at end.
TEST_P(TriangleFanDrawTest, DrawTriangleFanPrimitiveRestartAtEnd)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
std::vector<GLubyte> indices = {0, 1, 2, 3, 4, 0xff};
GLBuffer indexBuffer;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
GL_STATIC_DRAW);
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glDrawElements(GL_TRIANGLE_FAN, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_BYTE, 0);
EXPECT_GL_NO_ERROR();
verifyTriangles();
} }
// Simple repeated draw and swap test. // Simple repeated draw and swap test.
...@@ -1080,6 +1207,20 @@ TEST_P(SimpleOperationTest, PrimitiveModeNegativeTest) ...@@ -1080,6 +1207,20 @@ TEST_P(SimpleOperationTest, PrimitiveModeNegativeTest)
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(SimpleOperationTest); ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
SimpleOperationTest,
ES3_METAL(),
WithMetalForcedBufferGPUStorage(ES3_METAL()),
WithMetalMemoryBarrierAndCheapRenderPass(ES3_METAL(),
/* hasBarrier */ false,
/* cheapRenderPass */ false));
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
TriangleFanDrawTest,
ES3_METAL(),
WithMetalForcedBufferGPUStorage(ES3_METAL()),
WithMetalMemoryBarrierAndCheapRenderPass(ES3_METAL(),
/* hasBarrier */ false,
/* cheapRenderPass */ false));
} // namespace } // namespace
...@@ -236,12 +236,17 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp) ...@@ -236,12 +236,17 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp)
if (pp.eglParameters.hasExplicitMemBarrierFeatureMtl == EGL_FALSE) if (pp.eglParameters.hasExplicitMemBarrierFeatureMtl == EGL_FALSE)
{ {
stream << "_NoExplicitMemoryBarrier"; stream << "_NoMetalExplicitMemoryBarrier";
} }
if (pp.eglParameters.hasCheapRenderPassFeatureMtl == EGL_FALSE) if (pp.eglParameters.hasCheapRenderPassFeatureMtl == EGL_FALSE)
{ {
stream << "_NoCheapRenderPass"; stream << "_NoMetalCheapRenderPass";
}
if (pp.eglParameters.forceBufferGPUStorageFeatureMtl == EGL_TRUE)
{
stream << "_ForceMetalBufferGPUStorage";
} }
return stream; return stream;
......
...@@ -251,6 +251,13 @@ inline PlatformParameters WithMetalMemoryBarrierAndCheapRenderPass(const Platfor ...@@ -251,6 +251,13 @@ inline PlatformParameters WithMetalMemoryBarrierAndCheapRenderPass(const Platfor
return re; return re;
} }
inline PlatformParameters WithMetalForcedBufferGPUStorage(const PlatformParameters &params)
{
PlatformParameters re = params;
re.eglParameters.forceBufferGPUStorageFeatureMtl = EGL_TRUE;
return re;
}
inline PlatformParameters WithRobustness(const PlatformParameters &params) inline PlatformParameters WithRobustness(const PlatformParameters &params)
{ {
PlatformParameters withRobustness = params; PlatformParameters withRobustness = params;
......
...@@ -63,7 +63,7 @@ struct EGLPlatformParameters ...@@ -63,7 +63,7 @@ struct EGLPlatformParameters
allocateNonZeroMemoryFeature, emulateCopyTexImage2DFromRenderbuffers, allocateNonZeroMemoryFeature, emulateCopyTexImage2DFromRenderbuffers,
shaderStencilOutputFeature, genMultipleMipsPerPassFeature, platformMethods, shaderStencilOutputFeature, genMultipleMipsPerPassFeature, platformMethods,
robustness, emulatedPrerotation, hasExplicitMemBarrierFeatureMtl, robustness, emulatedPrerotation, hasExplicitMemBarrierFeatureMtl,
hasCheapRenderPassFeatureMtl); hasCheapRenderPassFeatureMtl, forceBufferGPUStorageFeatureMtl);
} }
EGLint renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; EGLint renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
...@@ -82,6 +82,7 @@ struct EGLPlatformParameters ...@@ -82,6 +82,7 @@ struct EGLPlatformParameters
uint32_t emulatedPrerotation = 0; // Can be 0, 90, 180 or 270 uint32_t emulatedPrerotation = 0; // Can be 0, 90, 180 or 270
EGLint hasExplicitMemBarrierFeatureMtl = EGL_DONT_CARE; EGLint hasExplicitMemBarrierFeatureMtl = EGL_DONT_CARE;
EGLint hasCheapRenderPassFeatureMtl = EGL_DONT_CARE; EGLint hasCheapRenderPassFeatureMtl = EGL_DONT_CARE;
EGLint forceBufferGPUStorageFeatureMtl = EGL_DONT_CARE;
angle::PlatformMethods *platformMethods = nullptr; angle::PlatformMethods *platformMethods = nullptr;
}; };
......
...@@ -231,6 +231,11 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow, ...@@ -231,6 +231,11 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow,
disabledFeatureOverrides.push_back("has_cheap_render_pass_mtl"); disabledFeatureOverrides.push_back("has_cheap_render_pass_mtl");
} }
if (params.forceBufferGPUStorageFeatureMtl == EGL_TRUE)
{
enabledFeatureOverrides.push_back("force_buffer_gpu_storage_mtl");
}
if (!disabledFeatureOverrides.empty()) if (!disabledFeatureOverrides.empty())
{ {
if (strstr(extensionString, "EGL_ANGLE_feature_control") == nullptr) if (strstr(extensionString, "EGL_ANGLE_feature_control") == nullptr)
......
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