Commit ab372311 by Le Hoang Quyen Committed by Commit Bot

Metal: refactor RenderUtils to split into multiple util classes.

This is useful for later modifications where blit/clear could be further categorized based on texture format type (float/integer). Bug: angleproject:2634 Change-Id: I877abd21761af9e91657686a60e189a43a33e3f4 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2193195Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 957a2359
...@@ -63,10 +63,7 @@ class BufferHolderMtl ...@@ -63,10 +63,7 @@ class BufferHolderMtl
// a queue of mtl::Buffer and only let CPU modifies a free mtl::Buffer. // a queue of mtl::Buffer and only let CPU modifies a free mtl::Buffer.
// So, in order to let GPU use the most recent modified content, one must call this method // So, in order to let GPU use the most recent modified content, one must call this method
// right before the draw call to retrieved the most up-to-date mtl::Buffer. // right before the draw call to retrieved the most up-to-date mtl::Buffer.
mtl::BufferRef getCurrentBuffer(const gl::Context *context) mtl::BufferRef getCurrentBuffer() { return mIsWeak ? mBufferWeakRef.lock() : mBuffer; }
{
return mIsWeak ? mBufferWeakRef.lock() : mBuffer;
}
protected: protected:
mtl::BufferRef mBuffer; mtl::BufferRef mBuffer;
...@@ -111,8 +108,7 @@ class BufferMtl : public BufferImpl, public BufferHolderMtl ...@@ -111,8 +108,7 @@ class BufferMtl : public BufferImpl, public BufferHolderMtl
bool primitiveRestartEnabled, bool primitiveRestartEnabled,
gl::IndexRange *outRange) override; gl::IndexRange *outRange) override;
angle::Result getFirstLastIndices(const gl::Context *context, angle::Result getFirstLastIndices(gl::DrawElementsType type,
gl::DrawElementsType type,
size_t offset, size_t offset,
size_t count, size_t count,
std::pair<uint32_t, uint32_t> *outIndices) const; std::pair<uint32_t, uint32_t> *outIndices) const;
......
...@@ -228,8 +228,7 @@ angle::Result BufferMtl::getIndexRange(const gl::Context *context, ...@@ -228,8 +228,7 @@ angle::Result BufferMtl::getIndexRange(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result BufferMtl::getFirstLastIndices(const gl::Context *context, angle::Result BufferMtl::getFirstLastIndices(gl::DrawElementsType type,
gl::DrawElementsType type,
size_t offset, size_t offset,
size_t count, size_t count,
std::pair<uint32_t, uint32_t> *outIndices) const std::pair<uint32_t, uint32_t> *outIndices) const
......
...@@ -175,7 +175,7 @@ angle::Result ContextMtl::drawTriFanArraysWithBaseVertex(const gl::Context *cont ...@@ -175,7 +175,7 @@ angle::Result ContextMtl::drawTriFanArraysWithBaseVertex(const gl::Context *cont
ANGLE_TRY( ANGLE_TRY(
mtl::Buffer::MakeBuffer(this, indexBufferSize, nullptr, &mTriFanArraysIndexBuffer)); mtl::Buffer::MakeBuffer(this, indexBufferSize, nullptr, &mTriFanArraysIndexBuffer));
ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromArrays( ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromArrays(
context, {0, static_cast<uint32_t>(count), mTriFanArraysIndexBuffer, 0})); this, {0, static_cast<uint32_t>(count), mTriFanArraysIndexBuffer, 0}));
} }
ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances, ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
...@@ -203,8 +203,8 @@ angle::Result ContextMtl::drawTriFanArraysLegacy(const gl::Context *context, ...@@ -203,8 +203,8 @@ angle::Result ContextMtl::drawTriFanArraysLegacy(const gl::Context *context,
ANGLE_TRY(AllocateTriangleFanBufferFromPool(this, count, &mTriFanIndexBuffer, &genIdxBuffer, ANGLE_TRY(AllocateTriangleFanBufferFromPool(this, count, &mTriFanIndexBuffer, &genIdxBuffer,
&genIdxBufferOffset, &genIndicesCount)); &genIdxBufferOffset, &genIndicesCount));
ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromArrays( ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromArrays(
context, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer, this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer,
genIdxBufferOffset})); genIdxBufferOffset}));
ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances, ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0))); gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0)));
...@@ -314,7 +314,7 @@ angle::Result ContextMtl::drawTriFanElements(const gl::Context *context, ...@@ -314,7 +314,7 @@ angle::Result ContextMtl::drawTriFanElements(const gl::Context *context,
&genIdxBufferOffset, &genIndicesCount)); &genIdxBufferOffset, &genIndicesCount));
ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromElementsArray( ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromElementsArray(
context, {type, count, indices, genIdxBuffer, genIdxBufferOffset})); this, {type, count, indices, genIdxBuffer, genIdxBufferOffset}));
ANGLE_TRY(mTriFanIndexBuffer.commit(this)); ANGLE_TRY(mTriFanIndexBuffer.commit(this));
...@@ -1552,7 +1552,7 @@ angle::Result ContextMtl::genLineLoopLastSegment(const gl::Context *context, ...@@ -1552,7 +1552,7 @@ angle::Result ContextMtl::genLineLoopLastSegment(const gl::Context *context,
if (indexTypeOrNone == gl::DrawElementsType::InvalidEnum) if (indexTypeOrNone == gl::DrawElementsType::InvalidEnum)
{ {
ANGLE_TRY(getDisplay()->getUtils().generateLineLoopLastSegment( ANGLE_TRY(getDisplay()->getUtils().generateLineLoopLastSegment(
context, firstVertex, firstVertex + vertexOrIndexCount - 1, newBuffer, 0)); this, firstVertex, firstVertex + vertexOrIndexCount - 1, newBuffer, 0));
} }
else else
{ {
...@@ -1560,7 +1560,7 @@ angle::Result ContextMtl::genLineLoopLastSegment(const gl::Context *context, ...@@ -1560,7 +1560,7 @@ angle::Result ContextMtl::genLineLoopLastSegment(const gl::Context *context,
// taken into account // taken into account
ASSERT(firstVertex == 0); ASSERT(firstVertex == 0);
ANGLE_TRY(getDisplay()->getUtils().generateLineLoopLastSegmentFromElementsArray( ANGLE_TRY(getDisplay()->getUtils().generateLineLoopLastSegmentFromElementsArray(
context, {indexTypeOrNone, vertexOrIndexCount, indices, newBuffer, 0})); this, {indexTypeOrNone, vertexOrIndexCount, indices, newBuffer, 0}));
} }
ANGLE_TRY(mLineLoopIndexBuffer.commit(this)); ANGLE_TRY(mLineLoopIndexBuffer.commit(this));
......
...@@ -534,9 +534,7 @@ angle::Result FramebufferMtl::clearWithDraw(const gl::Context *context, ...@@ -534,9 +534,7 @@ angle::Result FramebufferMtl::clearWithDraw(const gl::Context *context,
// Start new render encoder if not already. // Start new render encoder if not already.
mtl::RenderCommandEncoder *encoder = contextMtl->getRenderCommandEncoder(mRenderPassDesc); mtl::RenderCommandEncoder *encoder = contextMtl->getRenderCommandEncoder(mRenderPassDesc);
display->getUtils().clearWithDraw(context, encoder, clearOpts); return display->getUtils().clearWithDraw(context, encoder, clearOpts);
return angle::Result::Continue;
} }
angle::Result FramebufferMtl::clearImpl(const gl::Context *context, angle::Result FramebufferMtl::clearImpl(const gl::Context *context,
......
...@@ -1200,9 +1200,7 @@ angle::Result TextureMtl::copySubImageWithDraw(const gl::Context *context, ...@@ -1200,9 +1200,7 @@ angle::Result TextureMtl::copySubImageWithDraw(const gl::Context *context,
blitParams.srcYFlipped = framebufferMtl->flipY(); blitParams.srcYFlipped = framebufferMtl->flipY();
blitParams.dstLuminance = internalFormat.isLUMA(); blitParams.dstLuminance = internalFormat.isLUMA();
displayMtl->getUtils().blitWithDraw(context, cmdEncoder, blitParams); return displayMtl->getUtils().blitWithDraw(context, cmdEncoder, blitParams);
return angle::Result::Continue;
} }
angle::Result TextureMtl::copySubImageCPU(const gl::Context *context, angle::Result TextureMtl::copySubImageCPU(const gl::Context *context,
......
...@@ -315,7 +315,7 @@ angle::Result VertexArrayMtl::setupDraw(const gl::Context *glContext, ...@@ -315,7 +315,7 @@ angle::Result VertexArrayMtl::setupDraw(const gl::Context *glContext,
} }
desc.layouts[bufferIdx].stride = mCurrentArrayBufferStrides[v]; desc.layouts[bufferIdx].stride = mCurrentArrayBufferStrides[v];
cmdEncoder->setVertexBuffer(mCurrentArrayBuffers[v]->getCurrentBuffer(glContext), cmdEncoder->setVertexBuffer(mCurrentArrayBuffers[v]->getCurrentBuffer(),
bufferOffset, bufferIdx); bufferOffset, bufferIdx);
} }
else else
...@@ -487,7 +487,7 @@ angle::Result VertexArrayMtl::getIndexBuffer(const gl::Context *context, ...@@ -487,7 +487,7 @@ angle::Result VertexArrayMtl::getIndexBuffer(const gl::Context *context,
{ {
// No conversion needed: // No conversion needed:
BufferMtl *bufferMtl = mtl::GetImpl(glElementArrayBuffer); BufferMtl *bufferMtl = mtl::GetImpl(glElementArrayBuffer);
*idxBufferOut = bufferMtl->getCurrentBuffer(context); *idxBufferOut = bufferMtl->getCurrentBuffer();
*idxBufferOffsetOut = convertedOffset; *idxBufferOffsetOut = convertedOffset;
} }
} }
...@@ -555,10 +555,11 @@ angle::Result VertexArrayMtl::convertIndexBufferGPU(const gl::Context *glContext ...@@ -555,10 +555,11 @@ angle::Result VertexArrayMtl::convertIndexBufferGPU(const gl::Context *glContext
&conversion->convertedOffset)); &conversion->convertedOffset));
// Do the conversion on GPU. // Do the conversion on GPU.
ANGLE_TRY(display->getUtils().convertIndexBuffer( ANGLE_TRY(display->getUtils().convertIndexBufferGPU(
glContext, indexType, static_cast<uint32_t>(indexCount), mtl::GetImpl(glContext),
idxBuffer->getCurrentBuffer(glContext), static_cast<uint32_t>(offset), {indexType, static_cast<uint32_t>(indexCount), idxBuffer->getCurrentBuffer(),
conversion->convertedBuffer, static_cast<uint32_t>(conversion->convertedOffset))); static_cast<uint32_t>(offset), conversion->convertedBuffer,
static_cast<uint32_t>(conversion->convertedOffset)}));
ANGLE_TRY(conversion->data.commit(contextMtl)); ANGLE_TRY(conversion->data.commit(contextMtl));
...@@ -659,14 +660,13 @@ angle::Result VertexArrayMtl::convertVertexBufferCPU(const gl::Context *glContex ...@@ -659,14 +660,13 @@ angle::Result VertexArrayMtl::convertVertexBufferCPU(const gl::Context *glContex
// Cache the last converted results to be re-used later if the buffer's content won't ever be // Cache the last converted results to be re-used later if the buffer's content won't ever be
// changed. // changed.
conversion->convertedBuffer = conversion->convertedBuffer = mConvertedArrayBufferHolders[attribIndex].getCurrentBuffer();
mConvertedArrayBufferHolders[attribIndex].getCurrentBuffer(glContext);
conversion->convertedOffset = mCurrentArrayBufferOffsets[attribIndex]; conversion->convertedOffset = mCurrentArrayBufferOffsets[attribIndex];
#ifndef NDEBUG #ifndef NDEBUG
ANGLE_MTL_OBJC_SCOPE ANGLE_MTL_OBJC_SCOPE
{ {
mConvertedArrayBufferHolders[attribIndex].getCurrentBuffer(glContext)->get().label = mConvertedArrayBufferHolders[attribIndex].getCurrentBuffer()->get().label =
[NSString stringWithFormat:@"Converted from %p offset=%zu stride=%u", srcBuffer, [NSString stringWithFormat:@"Converted from %p offset=%zu stride=%u", srcBuffer,
binding.getOffset(), binding.getStride()]; binding.getOffset(), binding.getStride()];
} }
......
...@@ -62,6 +62,18 @@ struct TriFanFromArrayParams ...@@ -62,6 +62,18 @@ struct TriFanFromArrayParams
uint32_t dstOffset; uint32_t dstOffset;
}; };
struct IndexConversionParams
{
gl::DrawElementsType srcType;
uint32_t indexCount;
const BufferRef &srcBuffer;
uint32_t srcOffset;
const BufferRef &dstBuffer;
// Must be multiples of kIndexBufferOffsetAlignment
uint32_t dstOffset;
};
struct IndexGenerationParams struct IndexGenerationParams
{ {
gl::DrawElementsType srcType; gl::DrawElementsType srcType;
...@@ -71,93 +83,116 @@ struct IndexGenerationParams ...@@ -71,93 +83,116 @@ struct IndexGenerationParams
uint32_t dstOffset; uint32_t dstOffset;
}; };
class RenderUtils : public Context, angle::NonCopyable // Utils class for clear & blitting
class ClearUtils
{ {
public: public:
RenderUtils(DisplayMtl *display); ClearUtils();
~RenderUtils() override;
angle::Result initialize();
void onDestroy(); void onDestroy();
// Clear current framebuffer // Clear current framebuffer
void clearWithDraw(const gl::Context *context, angle::Result clearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params); const ClearRectParams &params);
// Blit texture data to current framebuffer
void blitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params);
angle::Result convertIndexBuffer(const gl::Context *context,
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 generateTriFanBufferFromArrays(const gl::Context *context,
const TriFanFromArrayParams &params);
angle::Result generateTriFanBufferFromElementsArray(const gl::Context *context,
const IndexGenerationParams &params);
angle::Result generateLineLoopLastSegment(const gl::Context *context,
uint32_t firstVertex,
uint32_t lastVertex,
const BufferRef &dstBuffer,
uint32_t dstOffset);
angle::Result generateLineLoopLastSegmentFromElementsArray(const gl::Context *context,
const IndexGenerationParams &params);
angle::Result dispatchCompute(const gl::Context *context,
ComputeCommandEncoder *encoder,
id<MTLComputePipelineState> pipelineState,
size_t numThreads);
private: private:
// override ErrorHandler // Defer loading of render pipeline state cache.
void handleError(GLenum error, void ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx);
const char *file,
const char *function,
unsigned int line) override;
void handleError(NSError *_Nullable error,
const char *file,
const char *function,
unsigned int line) override;
void initClearResources();
void initBlitResources();
void setupClearWithDraw(const gl::Context *context, void setupClearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params); const ClearRectParams &params);
void setupBlitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params);
id<MTLDepthStencilState> getClearDepthStencilState(const gl::Context *context, id<MTLDepthStencilState> getClearDepthStencilState(const gl::Context *context,
const ClearRectParams &params); const ClearRectParams &params);
id<MTLRenderPipelineState> getClearRenderPipelineState(const gl::Context *context, id<MTLRenderPipelineState> getClearRenderPipelineState(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params); const ClearRectParams &params);
// Render pipeline cache for clear with draw:
RenderPipelineCache mClearRenderPipelineCache;
};
class ColorBlitUtils
{
public:
ColorBlitUtils();
void onDestroy();
// Blit texture data to current framebuffer
angle::Result blitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params);
private:
// Defer loading of render pipeline state cache.
void ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx,
int alphaPremultiplyType,
RenderPipelineCache *cacheOut);
void setupBlitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params);
id<MTLRenderPipelineState> getBlitRenderPipelineState(const gl::Context *context, id<MTLRenderPipelineState> getBlitRenderPipelineState(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const BlitParams &params); const BlitParams &params);
void setupBlitWithDrawUniformData(RenderCommandEncoder *cmdEncoder, const BlitParams &params);
void setupDrawCommonStates(RenderCommandEncoder *cmdEncoder); RenderPipelineCache mBlitRenderPipelineCache;
RenderPipelineCache mBlitPremultiplyAlphaRenderPipelineCache;
RenderPipelineCache mBlitUnmultiplyAlphaRenderPipelineCache;
};
// util class for generating index buffer
class IndexGeneratorUtils
{
public:
void onDestroy();
// Convert index buffer.
angle::Result convertIndexBufferGPU(ContextMtl *contextMtl,
const IndexConversionParams &params);
// Generate triangle fan index buffer for glDrawArrays().
angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
const TriFanFromArrayParams &params);
// Generate triangle fan index buffer for glDrawElements().
angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
const IndexGenerationParams &params);
// Generate line loop's last segment index buffer for glDrawArrays().
angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl,
uint32_t firstVertex,
uint32_t lastVertex,
const BufferRef &dstBuffer,
uint32_t dstOffset);
// Generate line loop's last segment index buffer for glDrawElements().
angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl,
const IndexGenerationParams &params);
private:
// Index generator compute pipelines:
// - First dimension: index type.
// - second dimension: source buffer's offset is aligned or not.
using IndexConversionPipelineArray =
std::array<std::array<AutoObjCPtr<id<MTLComputePipelineState>>, 2>,
angle::EnumSize<gl::DrawElementsType>()>;
// Get compute pipeline to convert index between buffers.
AutoObjCPtr<id<MTLComputePipelineState>> getIndexConversionPipeline( AutoObjCPtr<id<MTLComputePipelineState>> getIndexConversionPipeline(
ContextMtl *context, ContextMtl *contextMtl,
gl::DrawElementsType srcType, gl::DrawElementsType srcType,
uint32_t srcOffset); uint32_t srcOffset);
// Get compute pipeline to generate tri fan index for glDrawElements().
AutoObjCPtr<id<MTLComputePipelineState>> getTriFanFromElemArrayGeneratorPipeline( AutoObjCPtr<id<MTLComputePipelineState>> getTriFanFromElemArrayGeneratorPipeline(
ContextMtl *context, ContextMtl *contextMtl,
gl::DrawElementsType srcType, gl::DrawElementsType srcType,
uint32_t srcOffset); uint32_t srcOffset);
angle::Result ensureTriFanFromArrayGeneratorInitialized(ContextMtl *context); // Defer loading of compute pipeline to generate tri fan index for glDrawArrays().
void ensureTriFanFromArrayGeneratorInitialized(ContextMtl *contextMtl);
angle::Result generateTriFanBufferFromElementsArrayGPU( angle::Result generateTriFanBufferFromElementsArrayGPU(
const gl::Context *context, ContextMtl *contextMtl,
gl::DrawElementsType srcType, gl::DrawElementsType srcType,
uint32_t indexCount, uint32_t indexCount,
const BufferRef &srcBuffer, const BufferRef &srcBuffer,
...@@ -165,29 +200,69 @@ class RenderUtils : public Context, angle::NonCopyable ...@@ -165,29 +200,69 @@ class RenderUtils : public Context, angle::NonCopyable
const BufferRef &dstBuffer, const BufferRef &dstBuffer,
// Must be multiples of kIndexBufferOffsetAlignment // Must be multiples of kIndexBufferOffsetAlignment
uint32_t dstOffset); uint32_t dstOffset);
angle::Result generateTriFanBufferFromElementsArrayCPU(const gl::Context *context, angle::Result generateTriFanBufferFromElementsArrayCPU(ContextMtl *contextMtl,
const IndexGenerationParams &params); const IndexGenerationParams &params);
angle::Result generateLineLoopLastSegmentFromElementsArrayCPU( angle::Result generateLineLoopLastSegmentFromElementsArrayCPU(
const gl::Context *context, ContextMtl *contextMtl,
const IndexGenerationParams &params); const IndexGenerationParams &params);
RenderPipelineCache mClearRenderPipelineCache;
RenderPipelineCache mBlitRenderPipelineCache;
RenderPipelineCache mBlitPremultiplyAlphaRenderPipelineCache;
RenderPipelineCache mBlitUnmultiplyAlphaRenderPipelineCache;
// Index generator compute pipelines:
// - First dimension: index type.
// - second dimension: source buffer's offset is aligned or not.
using IndexConversionPipelineArray =
std::array<std::array<AutoObjCPtr<id<MTLComputePipelineState>>, 2>,
angle::EnumSize<gl::DrawElementsType>()>;
IndexConversionPipelineArray mIndexConversionPipelineCaches; IndexConversionPipelineArray mIndexConversionPipelineCaches;
IndexConversionPipelineArray mTriFanFromElemArrayGeneratorPipelineCaches; IndexConversionPipelineArray mTriFanFromElemArrayGeneratorPipelineCaches;
AutoObjCPtr<id<MTLComputePipelineState>> mTriFanFromArraysGeneratorPipeline; AutoObjCPtr<id<MTLComputePipelineState>> mTriFanFromArraysGeneratorPipeline;
}; };
// RenderUtils: container class of various util classes above
class RenderUtils : public Context, angle::NonCopyable
{
public:
RenderUtils(DisplayMtl *display);
~RenderUtils() override;
angle::Result initialize();
void onDestroy();
// Clear current framebuffer
angle::Result clearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params);
// Blit texture data to current framebuffer
angle::Result blitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params);
// See IndexGeneratorUtils
angle::Result convertIndexBufferGPU(ContextMtl *contextMtl,
const IndexConversionParams &params);
angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
const TriFanFromArrayParams &params);
angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
const IndexGenerationParams &params);
angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl,
uint32_t firstVertex,
uint32_t lastVertex,
const BufferRef &dstBuffer,
uint32_t dstOffset);
angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl,
const IndexGenerationParams &params);
private:
// override ErrorHandler
void handleError(GLenum error,
const char *file,
const char *function,
unsigned int line) override;
void handleError(NSError *_Nullable error,
const char *file,
const char *function,
unsigned int line) override;
ClearUtils mClearUtils;
ColorBlitUtils mColorBlitUtils;
IndexGeneratorUtils mIndexUtils;
};
} // namespace mtl } // namespace mtl
} // namespace rx } // namespace rx
......
...@@ -30,6 +30,7 @@ namespace ...@@ -30,6 +30,7 @@ namespace
#define SOURCE_IDX_IS_U16_CONSTANT_NAME @"kSourceIndexIsU16" #define SOURCE_IDX_IS_U16_CONSTANT_NAME @"kSourceIndexIsU16"
#define SOURCE_IDX_IS_U32_CONSTANT_NAME @"kSourceIndexIsU32" #define SOURCE_IDX_IS_U32_CONSTANT_NAME @"kSourceIndexIsU32"
// See libANGLE/renderer/metal/shaders/clear.metal
struct ClearParamsUniform struct ClearParamsUniform
{ {
float clearColor[4]; float clearColor[4];
...@@ -37,6 +38,7 @@ struct ClearParamsUniform ...@@ -37,6 +38,7 @@ struct ClearParamsUniform
float padding[3]; float padding[3];
}; };
// See libANGLE/renderer/metal/shaders/blit.metal
struct BlitParamsUniform struct BlitParamsUniform
{ {
// 0: lower left, 1: lower right, 2: upper left // 0: lower left, 1: lower right, 2: upper left
...@@ -55,6 +57,40 @@ struct IndexConversionUniform ...@@ -55,6 +57,40 @@ struct IndexConversionUniform
uint32_t padding[2]; uint32_t padding[2];
}; };
void GetBlitTexCoords(uint32_t srcWidth,
uint32_t srcHeight,
const gl::Rectangle &srcRect,
bool srcYFlipped,
bool unpackFlipY,
float *u0,
float *v0,
float *u1,
float *v1)
{
int x0 = srcRect.x0(); // left
int x1 = srcRect.x1(); // right
int y0 = srcRect.y0(); // lower
int y1 = srcRect.y1(); // upper
if (srcYFlipped)
{
// If source's Y has been flipped, such as default framebuffer, then adjust the real source
// rectangle.
y0 = srcHeight - y1;
y1 = y0 + srcRect.height;
std::swap(y0, y1);
}
if (unpackFlipY)
{
std::swap(y0, y1);
}
*u0 = static_cast<float>(x0) / srcWidth;
*u1 = static_cast<float>(x1) / srcWidth;
*v0 = static_cast<float>(y0) / srcHeight;
*v1 = static_cast<float>(y1) / srcHeight;
}
template <typename T> template <typename T>
angle::Result GenTriFanFromClientElements(ContextMtl *contextMtl, angle::Result GenTriFanFromClientElements(ContextMtl *contextMtl,
GLsizei count, GLsizei count,
...@@ -95,6 +131,82 @@ void GetFirstLastIndicesFromClientElements(GLsizei count, ...@@ -95,6 +131,82 @@ void GetFirstLastIndicesFromClientElements(GLsizei count,
memcpy(lastOut, indices + count - 1, sizeof(indices[0])); memcpy(lastOut, indices + count - 1, sizeof(indices[0]));
} }
ANGLE_INLINE
void EnsureComputePipelineInitialized(DisplayMtl *display,
NSString *functionName,
AutoObjCPtr<id<MTLComputePipelineState>> *pipelineOut)
{
AutoObjCPtr<id<MTLComputePipelineState>> &pipeline = *pipelineOut;
if (pipeline)
{
return;
}
ANGLE_MTL_OBJC_SCOPE
{
id<MTLDevice> metalDevice = display->getMetalDevice();
id<MTLLibrary> shaderLib = display->getDefaultShadersLib();
NSError *err = nil;
id<MTLFunction> shader = [shaderLib newFunctionWithName:functionName];
[shader ANGLE_MTL_AUTORELEASE];
pipeline = [[metalDevice newComputePipelineStateWithFunction:shader
error:&err] ANGLE_MTL_AUTORELEASE];
if (err && !pipeline)
{
ERR() << "Internal error: " << err.localizedDescription.UTF8String << "\n";
}
ASSERT(pipeline);
}
}
ANGLE_INLINE
void EnsureSpecializedComputePipelineInitialized(
DisplayMtl *display,
NSString *functionName,
MTLFunctionConstantValues *funcConstants,
AutoObjCPtr<id<MTLComputePipelineState>> *pipelineOut)
{
if (!funcConstants)
{
// Non specialized constants provided, use default creation function.
EnsureComputePipelineInitialized(display, functionName, pipelineOut);
return;
}
AutoObjCPtr<id<MTLComputePipelineState>> &pipeline = *pipelineOut;
if (pipeline)
{
return;
}
ANGLE_MTL_OBJC_SCOPE
{
id<MTLDevice> metalDevice = display->getMetalDevice();
id<MTLLibrary> shaderLib = display->getDefaultShadersLib();
NSError *err = nil;
id<MTLFunction> shader = [shaderLib newFunctionWithName:functionName
constantValues:funcConstants
error:&err];
if (err && !shader)
{
ERR() << "Internal error: " << err.localizedDescription.UTF8String << "\n";
}
ASSERT([shader ANGLE_MTL_AUTORELEASE]);
pipeline = [[metalDevice newComputePipelineStateWithFunction:shader
error:&err] ANGLE_MTL_AUTORELEASE];
if (err && !pipeline)
{
ERR() << "Internal error: " << err.localizedDescription.UTF8String << "\n";
}
ASSERT(pipeline);
}
}
template <typename T> template <typename T>
void ClearPipelineStateArray(T *pipelineCacheArray) void ClearPipelineStateArray(T *pipelineCacheArray)
{ {
...@@ -113,31 +225,92 @@ void ClearPipelineState2DArray(T *pipelineCache2DArray) ...@@ -113,31 +225,92 @@ void ClearPipelineState2DArray(T *pipelineCache2DArray)
} }
} }
void DispatchCompute(ContextMtl *contextMtl,
ComputeCommandEncoder *cmdEncoder,
id<MTLComputePipelineState> pipelineState,
size_t numThreads)
{
NSUInteger w = std::min<NSUInteger>(pipelineState.threadExecutionWidth, numThreads);
MTLSize threadsPerThreadgroup = MTLSizeMake(w, 1, 1);
if (contextMtl->getDisplay()->getFeatures().hasNonUniformDispatch.enabled)
{
MTLSize threads = MTLSizeMake(numThreads, 1, 1);
cmdEncoder->dispatchNonUniform(threads, threadsPerThreadgroup);
}
else
{
MTLSize groups = MTLSizeMake((numThreads + w - 1) / w, 1, 1);
cmdEncoder->dispatch(groups, threadsPerThreadgroup);
}
}
void SetupFullscreenDrawCommonStates(RenderCommandEncoder *cmdEncoder)
{
cmdEncoder->setCullMode(MTLCullModeNone);
cmdEncoder->setTriangleFillMode(MTLTriangleFillModeFill);
cmdEncoder->setDepthBias(0, 0, 0);
}
void SetupBlitWithDrawUniformData(RenderCommandEncoder *cmdEncoder, const BlitParams &params)
{
BlitParamsUniform uniformParams;
uniformParams.dstFlipY = params.dstFlipY ? 1 : 0;
uniformParams.srcLevel = params.srcLevel;
uniformParams.dstLuminance = params.dstLuminance ? 1 : 0;
// Compute source texCoords
uint32_t srcWidth = 0, srcHeight = 0;
if (params.src)
{
srcWidth = params.src->width(params.srcLevel);
srcHeight = params.src->height(params.srcLevel);
}
else
{
UNREACHABLE();
}
float u0, v0, u1, v1;
GetBlitTexCoords(srcWidth, srcHeight, params.srcRect, params.srcYFlipped, params.unpackFlipY,
&u0, &v0, &u1, &v1);
float du = u1 - u0;
float dv = v1 - v0;
// lower left
uniformParams.srcTexCoords[0][0] = u0;
uniformParams.srcTexCoords[0][1] = v0;
// lower right
uniformParams.srcTexCoords[1][0] = u1 + du;
uniformParams.srcTexCoords[1][1] = v0;
// upper left
uniformParams.srcTexCoords[2][0] = u0;
uniformParams.srcTexCoords[2][1] = v1 + dv;
cmdEncoder->setVertexData(uniformParams, 0);
cmdEncoder->setFragmentData(uniformParams, 0);
}
} // namespace } // namespace
// RenderUtils implementation
RenderUtils::RenderUtils(DisplayMtl *display) : Context(display) {} RenderUtils::RenderUtils(DisplayMtl *display) : Context(display) {}
RenderUtils::~RenderUtils() {} RenderUtils::~RenderUtils() {}
angle::Result RenderUtils::initialize() angle::Result RenderUtils::initialize()
{ {
initClearResources();
initBlitResources();
return angle::Result::Continue; return angle::Result::Continue;
} }
void RenderUtils::onDestroy() void RenderUtils::onDestroy()
{ {
mClearRenderPipelineCache.clear(); mIndexUtils.onDestroy();
mBlitRenderPipelineCache.clear(); mClearUtils.onDestroy();
mBlitPremultiplyAlphaRenderPipelineCache.clear(); mColorBlitUtils.onDestroy();
mBlitUnmultiplyAlphaRenderPipelineCache.clear();
ClearPipelineState2DArray(&mIndexConversionPipelineCaches);
ClearPipelineState2DArray(&mTriFanFromElemArrayGeneratorPipelineCaches);
mTriFanFromArraysGeneratorPipeline = nil;
} }
// override ErrorHandler // override ErrorHandler
...@@ -164,105 +337,146 @@ void RenderUtils::handleError(NSError *nserror, ...@@ -164,105 +337,146 @@ void RenderUtils::handleError(NSError *nserror,
<< nserror.localizedDescription.UTF8String; << nserror.localizedDescription.UTF8String;
} }
void RenderUtils::initClearResources() // Clear current framebuffer
angle::Result RenderUtils::clearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params)
{ {
ANGLE_MTL_OBJC_SCOPE return mClearUtils.clearWithDraw(context, cmdEncoder, params);
{
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
// Shader pipeline
mClearRenderPipelineCache.setVertexShader(
this, [[shaderLib newFunctionWithName:@"clearVS"] ANGLE_MTL_AUTORELEASE]);
mClearRenderPipelineCache.setFragmentShader(
this, [[shaderLib newFunctionWithName:@"clearFS"] ANGLE_MTL_AUTORELEASE]);
}
} }
void RenderUtils::initBlitResources() // Blit texture data to current framebuffer
angle::Result RenderUtils::blitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params)
{ {
ANGLE_MTL_OBJC_SCOPE return mColorBlitUtils.blitWithDraw(context, cmdEncoder, params);
{ }
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
id<MTLFunction> vertexShader = angle::Result RenderUtils::convertIndexBufferGPU(ContextMtl *contextMtl,
[[shaderLib newFunctionWithName:@"blitVS"] ANGLE_MTL_AUTORELEASE]; const IndexConversionParams &params)
{
return mIndexUtils.convertIndexBufferGPU(contextMtl, params);
}
angle::Result RenderUtils::generateTriFanBufferFromArrays(ContextMtl *contextMtl,
const TriFanFromArrayParams &params)
{
return mIndexUtils.generateTriFanBufferFromArrays(contextMtl, params);
}
angle::Result RenderUtils::generateTriFanBufferFromElementsArray(
ContextMtl *contextMtl,
const IndexGenerationParams &params)
{
return mIndexUtils.generateTriFanBufferFromElementsArray(contextMtl, params);
}
angle::Result RenderUtils::generateLineLoopLastSegment(ContextMtl *contextMtl,
uint32_t firstVertex,
uint32_t lastVertex,
const BufferRef &dstBuffer,
uint32_t dstOffset)
{
return mIndexUtils.generateLineLoopLastSegment(contextMtl, firstVertex, lastVertex, dstBuffer,
dstOffset);
}
angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArray(
ContextMtl *contextMtl,
const IndexGenerationParams &params)
{
return mIndexUtils.generateLineLoopLastSegmentFromElementsArray(contextMtl, params);
}
// ClearUtils implementation
ClearUtils::ClearUtils() = default;
mBlitRenderPipelineCache.setVertexShader(this, vertexShader); void ClearUtils::onDestroy()
mBlitRenderPipelineCache.setFragmentShader( {
this, [[shaderLib newFunctionWithName:@"blitFS"] ANGLE_MTL_AUTORELEASE]); mClearRenderPipelineCache.clear();
}
mBlitPremultiplyAlphaRenderPipelineCache.setVertexShader(this, vertexShader); void ClearUtils::ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx)
mBlitPremultiplyAlphaRenderPipelineCache.setFragmentShader( {
this, ANGLE_MTL_OBJC_SCOPE
[[shaderLib newFunctionWithName:@"blitPremultiplyAlphaFS"] ANGLE_MTL_AUTORELEASE]); {
id<MTLLibrary> shaderLib = ctx->getDisplay()->getDefaultShadersLib();
mBlitUnmultiplyAlphaRenderPipelineCache.setVertexShader(this, vertexShader); mClearRenderPipelineCache.setVertexShader(
mBlitUnmultiplyAlphaRenderPipelineCache.setFragmentShader( ctx, [[shaderLib newFunctionWithName:@"clearVS"] ANGLE_MTL_AUTORELEASE]);
this, [[shaderLib newFunctionWithName:@"blitUnmultiplyAlphaFS"] ANGLE_MTL_AUTORELEASE]); mClearRenderPipelineCache.setFragmentShader(
ctx, [[shaderLib newFunctionWithName:@"clearFS"] ANGLE_MTL_AUTORELEASE]);
} }
} }
void RenderUtils::clearWithDraw(const gl::Context *context, id<MTLDepthStencilState> ClearUtils::getClearDepthStencilState(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, const ClearRectParams &params)
const ClearRectParams &params)
{ {
auto overridedParams = params; ContextMtl *contextMtl = GetImpl(context);
// Make sure we don't clear attachment that doesn't exist
const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc(); if (!params.clearDepth.valid() && !params.clearStencil.valid())
if (renderPassDesc.numColorAttachments == 0)
{ {
overridedParams.clearColor.reset(); // Doesn't clear depth nor stencil
return contextMtl->getDisplay()->getStateCache().getNullDepthStencilState(contextMtl);
} }
if (!renderPassDesc.depthAttachment.texture)
DepthStencilDesc desc;
desc.reset();
if (params.clearDepth.valid())
{ {
overridedParams.clearDepth.reset(); // Clear depth state
desc.depthWriteEnabled = true;
} }
if (!renderPassDesc.stencilAttachment.texture) else
{ {
overridedParams.clearStencil.reset(); desc.depthWriteEnabled = false;
} }
if (!overridedParams.clearColor.valid() && !overridedParams.clearDepth.valid() && if (params.clearStencil.valid())
!overridedParams.clearStencil.valid())
{ {
return; // Clear stencil state
desc.frontFaceStencil.depthStencilPassOperation = MTLStencilOperationReplace;
desc.frontFaceStencil.writeMask = contextMtl->getStencilMask();
desc.backFaceStencil.depthStencilPassOperation = MTLStencilOperationReplace;
desc.backFaceStencil.writeMask = contextMtl->getStencilMask();
} }
setupClearWithDraw(context, cmdEncoder, overridedParams); return contextMtl->getDisplay()->getStateCache().getDepthStencilState(
contextMtl->getMetalDevice(), desc);
// Draw the screen aligned triangle
cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
// Invalidate current context's state
auto contextMtl = GetImpl(context);
contextMtl->invalidateState(context);
} }
void RenderUtils::blitWithDraw(const gl::Context *context, id<MTLRenderPipelineState> ClearUtils::getClearRenderPipelineState(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const BlitParams &params) const ClearRectParams &params)
{ {
if (!params.src) ContextMtl *contextMtl = GetImpl(context);
MTLColorWriteMask colorMask = contextMtl->getColorMask();
if (!params.clearColor.valid())
{ {
return; colorMask = MTLColorWriteMaskNone;
} }
setupBlitWithDraw(context, cmdEncoder, params);
// Draw the screen aligned triangle RenderPipelineDesc pipelineDesc;
cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3); const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
// Invalidate current context's state renderPassDesc.populateRenderPipelineOutputDesc(colorMask, &pipelineDesc.outputDescriptor);
ContextMtl *contextMtl = GetImpl(context);
contextMtl->invalidateState(context); pipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassTriangle;
ensureRenderPipelineStateCacheInitialized(contextMtl);
return mClearRenderPipelineCache.getRenderPipelineState(contextMtl, pipelineDesc);
} }
void RenderUtils::setupClearWithDraw(const gl::Context *context, void ClearUtils::setupClearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params) const ClearRectParams &params)
{ {
// Generate render pipeline state // Generate render pipeline state
auto renderPipelineState = getClearRenderPipelineState(context, cmdEncoder, params); id<MTLRenderPipelineState> renderPipelineState =
getClearRenderPipelineState(context, cmdEncoder, params);
ASSERT(renderPipelineState); ASSERT(renderPipelineState);
// Setup states // Setup states
setupDrawCommonStates(cmdEncoder); SetupFullscreenDrawCommonStates(cmdEncoder);
cmdEncoder->setRenderPipelineState(renderPipelineState); cmdEncoder->setRenderPipelineState(renderPipelineState);
id<MTLDepthStencilState> dsState = getClearDepthStencilState(context, params); id<MTLDepthStencilState> dsState = getClearDepthStencilState(context, params);
...@@ -290,7 +504,7 @@ void RenderUtils::setupClearWithDraw(const gl::Context *context, ...@@ -290,7 +504,7 @@ void RenderUtils::setupClearWithDraw(const gl::Context *context,
renderPassAttachment = renderPassDesc.stencilAttachment; renderPassAttachment = renderPassDesc.stencilAttachment;
} }
auto texture = renderPassAttachment.texture; TextureRef texture = renderPassAttachment.texture;
viewport = viewport =
GetViewport(params.clearArea, texture->height(renderPassAttachment.level), params.flipY); GetViewport(params.clearArea, texture->height(renderPassAttachment.level), params.flipY);
...@@ -313,109 +527,92 @@ void RenderUtils::setupClearWithDraw(const gl::Context *context, ...@@ -313,109 +527,92 @@ void RenderUtils::setupClearWithDraw(const gl::Context *context,
cmdEncoder->setFragmentData(uniformParams, 0); cmdEncoder->setFragmentData(uniformParams, 0);
} }
void RenderUtils::setupBlitWithDraw(const gl::Context *context, angle::Result ClearUtils::clearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const BlitParams &params) const ClearRectParams &params)
{ {
ASSERT(cmdEncoder->renderPassDesc().numColorAttachments == 1 && params.src); ClearRectParams overridedParams = params;
// Make sure we don't clear attachment that doesn't exist
// Generate render pipeline state
auto renderPipelineState = getBlitRenderPipelineState(context, cmdEncoder, params);
ASSERT(renderPipelineState);
// Setup states
setupDrawCommonStates(cmdEncoder);
cmdEncoder->setRenderPipelineState(renderPipelineState);
cmdEncoder->setDepthStencilState(getDisplay()->getStateCache().getNullDepthStencilState(this));
// Viewport
const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc(); const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
const RenderPassColorAttachmentDesc &renderPassColorAttachment = if (renderPassDesc.numColorAttachments == 0)
renderPassDesc.colorAttachments[0];
auto texture = renderPassColorAttachment.texture;
gl::Rectangle dstRect(params.dstOffset.x, params.dstOffset.y, params.srcRect.width,
params.srcRect.height);
MTLViewport viewportMtl =
GetViewport(dstRect, texture->height(renderPassColorAttachment.level), params.dstFlipY);
MTLScissorRect scissorRectMtl =
GetScissorRect(dstRect, texture->height(renderPassColorAttachment.level), params.dstFlipY);
cmdEncoder->setViewport(viewportMtl);
cmdEncoder->setScissorRect(scissorRectMtl);
cmdEncoder->setFragmentTexture(params.src, 0);
// Uniform
setupBlitWithDrawUniformData(cmdEncoder, params);
}
void RenderUtils::setupDrawCommonStates(RenderCommandEncoder *cmdEncoder)
{
cmdEncoder->setCullMode(MTLCullModeNone);
cmdEncoder->setTriangleFillMode(MTLTriangleFillModeFill);
cmdEncoder->setDepthBias(0, 0, 0);
}
id<MTLDepthStencilState> RenderUtils::getClearDepthStencilState(const gl::Context *context,
const ClearRectParams &params)
{
if (!params.clearDepth.valid() && !params.clearStencil.valid())
{ {
// Doesn't clear depth nor stencil overridedParams.clearColor.reset();
return getDisplay()->getStateCache().getNullDepthStencilState(this);
} }
if (!renderPassDesc.depthAttachment.texture)
ContextMtl *contextMtl = GetImpl(context);
DepthStencilDesc desc;
desc.reset();
if (params.clearDepth.valid())
{ {
// Clear depth state overridedParams.clearDepth.reset();
desc.depthWriteEnabled = true;
} }
else if (!renderPassDesc.stencilAttachment.texture)
{ {
desc.depthWriteEnabled = false; overridedParams.clearStencil.reset();
} }
if (params.clearStencil.valid()) if (!overridedParams.clearColor.valid() && !overridedParams.clearDepth.valid() &&
!overridedParams.clearStencil.valid())
{ {
// Clear stencil state return angle::Result::Continue;
desc.frontFaceStencil.depthStencilPassOperation = MTLStencilOperationReplace;
desc.frontFaceStencil.writeMask = contextMtl->getStencilMask();
desc.backFaceStencil.depthStencilPassOperation = MTLStencilOperationReplace;
desc.backFaceStencil.writeMask = contextMtl->getStencilMask();
} }
return getDisplay()->getStateCache().getDepthStencilState(getDisplay()->getMetalDevice(), desc); setupClearWithDraw(context, cmdEncoder, overridedParams);
// Draw the screen aligned triangle
cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
// Invalidate current context's state
ContextMtl *contextMtl = GetImpl(context);
contextMtl->invalidateState(context);
return angle::Result::Continue;
} }
id<MTLRenderPipelineState> RenderUtils::getClearRenderPipelineState( // ColorBlitUtils implementation
const gl::Context *context, ColorBlitUtils::ColorBlitUtils() = default;
RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params) void ColorBlitUtils::onDestroy()
{ {
ContextMtl *contextMtl = GetImpl(context); mBlitRenderPipelineCache.clear();
MTLColorWriteMask colorMask = contextMtl->getColorMask(); mBlitPremultiplyAlphaRenderPipelineCache.clear();
if (!params.clearColor.valid()) mBlitUnmultiplyAlphaRenderPipelineCache.clear();
}
void ColorBlitUtils::ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx,
int alphaPremultiplyType,
RenderPipelineCache *cacheOut)
{
RenderPipelineCache &pipelineCache = *cacheOut;
if (pipelineCache.getVertexShader() && pipelineCache.getFragmentShader())
{ {
colorMask = MTLColorWriteMaskNone; // Already initialized.
return;
} }
RenderPipelineDesc pipelineDesc; ANGLE_MTL_OBJC_SCOPE
const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc(); {
NSString *const fragmentShaderNames[] = {// Normal blit
renderPassDesc.populateRenderPipelineOutputDesc(colorMask, &pipelineDesc.outputDescriptor); @"blitFS",
// Blit premultiply-alpha
@"blitPremultiplyAlphaFS",
// Blit unmultiply alpha
@"blitUnmultiplyAlphaFS"};
id<MTLLibrary> shaderLib = ctx->getDisplay()->getDefaultShadersLib();
id<MTLFunction> vertexShader =
[[shaderLib newFunctionWithName:@"blitVS"] ANGLE_MTL_AUTORELEASE];
id<MTLFunction> fragmentShader = [[shaderLib
newFunctionWithName:fragmentShaderNames[alphaPremultiplyType]] ANGLE_MTL_AUTORELEASE];
pipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassTriangle; ASSERT(vertexShader);
ASSERT(fragmentShader);
return mClearRenderPipelineCache.getRenderPipelineState(contextMtl, pipelineDesc); mBlitRenderPipelineCache.setVertexShader(ctx, vertexShader);
mBlitRenderPipelineCache.setFragmentShader(ctx, fragmentShader);
}
} }
id<MTLRenderPipelineState> RenderUtils::getBlitRenderPipelineState(const gl::Context *context, id<MTLRenderPipelineState> ColorBlitUtils::getBlitRenderPipelineState(
RenderCommandEncoder *cmdEncoder, const gl::Context *context,
const BlitParams &params) RenderCommandEncoder *cmdEncoder,
const BlitParams &params)
{ {
ContextMtl *contextMtl = GetImpl(context); ContextMtl *contextMtl = GetImpl(context);
RenderPipelineDesc pipelineDesc; RenderPipelineDesc pipelineDesc;
...@@ -427,157 +624,160 @@ id<MTLRenderPipelineState> RenderUtils::getBlitRenderPipelineState(const gl::Con ...@@ -427,157 +624,160 @@ id<MTLRenderPipelineState> RenderUtils::getBlitRenderPipelineState(const gl::Con
pipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassTriangle; pipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassTriangle;
RenderPipelineCache *pipelineCache; RenderPipelineCache *pipelineCache;
int alphaPremultiplyType;
if (params.unpackPremultiplyAlpha == params.unpackUnmultiplyAlpha) if (params.unpackPremultiplyAlpha == params.unpackUnmultiplyAlpha)
{ {
pipelineCache = &mBlitRenderPipelineCache; alphaPremultiplyType = 0;
pipelineCache = &mBlitRenderPipelineCache;
} }
else if (params.unpackPremultiplyAlpha) else if (params.unpackPremultiplyAlpha)
{ {
pipelineCache = &mBlitPremultiplyAlphaRenderPipelineCache; alphaPremultiplyType = 1;
pipelineCache = &mBlitPremultiplyAlphaRenderPipelineCache;
} }
else else
{ {
pipelineCache = &mBlitUnmultiplyAlphaRenderPipelineCache; alphaPremultiplyType = 2;
pipelineCache = &mBlitUnmultiplyAlphaRenderPipelineCache;
} }
ensureRenderPipelineStateCacheInitialized(contextMtl, alphaPremultiplyType, pipelineCache);
return pipelineCache->getRenderPipelineState(contextMtl, pipelineDesc); return pipelineCache->getRenderPipelineState(contextMtl, pipelineDesc);
} }
void RenderUtils::setupBlitWithDrawUniformData(RenderCommandEncoder *cmdEncoder, void ColorBlitUtils::setupBlitWithDraw(const gl::Context *context,
const BlitParams &params) RenderCommandEncoder *cmdEncoder,
const BlitParams &params)
{ {
BlitParamsUniform uniformParams; ASSERT(cmdEncoder->renderPassDesc().numColorAttachments == 1 && params.src);
uniformParams.dstFlipY = params.dstFlipY ? 1 : 0;
uniformParams.srcLevel = params.srcLevel;
uniformParams.dstLuminance = params.dstLuminance ? 1 : 0;
// Compute source texCoords ContextMtl *contextMtl = mtl::GetImpl(context);
auto srcWidth = params.src->width(params.srcLevel);
auto srcHeight = params.src->height(params.srcLevel);
int x0 = params.srcRect.x0(); // left // Generate render pipeline state
int x1 = params.srcRect.x1(); // right id<MTLRenderPipelineState> renderPipelineState =
int y0 = params.srcRect.y0(); // lower getBlitRenderPipelineState(context, cmdEncoder, params);
int y1 = params.srcRect.y1(); // upper ASSERT(renderPipelineState);
if (params.srcYFlipped) // Setup states
{ SetupFullscreenDrawCommonStates(cmdEncoder);
// If source's Y has been flipped, such as default framebuffer, then adjust the real source cmdEncoder->setRenderPipelineState(renderPipelineState);
// rectangle. cmdEncoder->setDepthStencilState(
y0 = srcHeight - y1; contextMtl->getDisplay()->getStateCache().getNullDepthStencilState(contextMtl));
y1 = y0 + params.srcRect.height;
std::swap(y0, y1); // Viewport
} const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
const RenderPassColorAttachmentDesc &renderPassColorAttachment =
renderPassDesc.colorAttachments[0];
mtl::TextureRef texture = renderPassColorAttachment.texture;
if (params.unpackFlipY) gl::Rectangle dstRect(params.dstOffset.x, params.dstOffset.y, params.srcRect.width,
params.srcRect.height);
MTLViewport viewportMtl =
GetViewport(dstRect, texture->height(renderPassColorAttachment.level), params.dstFlipY);
MTLScissorRect scissorRectMtl =
GetScissorRect(dstRect, texture->height(renderPassColorAttachment.level), params.dstFlipY);
cmdEncoder->setViewport(viewportMtl);
cmdEncoder->setScissorRect(scissorRectMtl);
cmdEncoder->setFragmentTexture(params.src, 0);
// Uniform
SetupBlitWithDrawUniformData(cmdEncoder, params);
}
angle::Result ColorBlitUtils::blitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params)
{
if (!params.src)
{ {
std::swap(y0, y1); return angle::Result::Continue;
} }
ContextMtl *contextMtl = GetImpl(context);
setupBlitWithDraw(context, cmdEncoder, params);
float u0 = static_cast<float>(x0) / srcWidth; // Draw the screen aligned triangle
float u1 = static_cast<float>(x1) / srcWidth; cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
float v0 = static_cast<float>(y0) / srcHeight;
float v1 = static_cast<float>(y1) / srcHeight;
float du = static_cast<float>(x1 - x0) / srcWidth;
float dv = static_cast<float>(y1 - y0) / srcHeight;
// lower left // Invalidate current context's state
uniformParams.srcTexCoords[0][0] = u0; contextMtl->invalidateState(context);
uniformParams.srcTexCoords[0][1] = v0;
// lower right return angle::Result::Continue;
uniformParams.srcTexCoords[1][0] = u1 + du; }
uniformParams.srcTexCoords[1][1] = v0;
// upper left // IndexGeneratorUtils implementation
uniformParams.srcTexCoords[2][0] = u0; void IndexGeneratorUtils::onDestroy()
uniformParams.srcTexCoords[2][1] = v1 + dv; {
ClearPipelineState2DArray(&mIndexConversionPipelineCaches);
ClearPipelineState2DArray(&mTriFanFromElemArrayGeneratorPipelineCaches);
cmdEncoder->setVertexData(uniformParams, 0); mTriFanFromArraysGeneratorPipeline = nil;
cmdEncoder->setFragmentData(uniformParams, 0);
} }
AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getIndexConversionPipeline( AutoObjCPtr<id<MTLComputePipelineState>> IndexGeneratorUtils::getIndexConversionPipeline(
ContextMtl *context, ContextMtl *contextMtl,
gl::DrawElementsType srcType, gl::DrawElementsType srcType,
uint32_t srcOffset) uint32_t srcOffset)
{ {
id<MTLDevice> metalDevice = context->getMetalDevice(); 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 =
auto &cache = mIndexConversionPipelineCaches[srcTypeKey][aligned ? 1 : 0]; mIndexConversionPipelineCaches[srcTypeKey][aligned ? 1 : 0];
if (!cache) if (!cache)
{ {
ANGLE_MTL_OBJC_SCOPE ANGLE_MTL_OBJC_SCOPE
{ {
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
id<MTLFunction> shader = nil;
auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE];
NSError *err = nil;
[funcConstants setConstantValue:&aligned [funcConstants setConstantValue:&aligned
type:MTLDataTypeBool type:MTLDataTypeBool
withName:SOURCE_BUFFER_ALIGNED_CONSTANT_NAME]; withName:SOURCE_BUFFER_ALIGNED_CONSTANT_NAME];
NSString *shaderName = nil;
switch (srcType) switch (srcType)
{ {
case gl::DrawElementsType::UnsignedByte: case gl::DrawElementsType::UnsignedByte:
shader = [shaderLib newFunctionWithName:@"convertIndexU8ToU16"]; // No need for specialized shader
funcConstants = nil;
shaderName = @"convertIndexU8ToU16";
break; break;
case gl::DrawElementsType::UnsignedShort: case gl::DrawElementsType::UnsignedShort:
shader = [shaderLib newFunctionWithName:@"convertIndexU16" shaderName = @"convertIndexU16";
constantValues:funcConstants
error:&err];
break; break;
case gl::DrawElementsType::UnsignedInt: case gl::DrawElementsType::UnsignedInt:
shader = [shaderLib newFunctionWithName:@"convertIndexU32" shaderName = @"convertIndexU32";
constantValues:funcConstants
error:&err];
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
if (err && !shader) EnsureSpecializedComputePipelineInitialized(contextMtl->getDisplay(), shaderName,
{ funcConstants, &cache);
ERR() << "Internal error: " << err.localizedDescription.UTF8String << "\n";
}
ASSERT([shader ANGLE_MTL_AUTORELEASE]);
cache = [[metalDevice newComputePipelineStateWithFunction:shader
error:&err] ANGLE_MTL_AUTORELEASE];
if (err && !cache)
{
ERR() << "Internal error: " << err.localizedDescription.UTF8String << "\n";
}
ASSERT(cache);
} }
} }
return cache; return cache;
} }
AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getTriFanFromElemArrayGeneratorPipeline( AutoObjCPtr<id<MTLComputePipelineState>>
ContextMtl *context, IndexGeneratorUtils::getTriFanFromElemArrayGeneratorPipeline(ContextMtl *contextMtl,
gl::DrawElementsType srcType, gl::DrawElementsType srcType,
uint32_t srcOffset) uint32_t srcOffset)
{ {
id<MTLDevice> metalDevice = context->getMetalDevice(); 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);
auto &cache = mTriFanFromElemArrayGeneratorPipelineCaches[srcTypeKey][aligned ? 1 : 0]; AutoObjCPtr<id<MTLComputePipelineState>> &cache =
mTriFanFromElemArrayGeneratorPipelineCaches[srcTypeKey][aligned ? 1 : 0];
if (!cache) if (!cache)
{ {
ANGLE_MTL_OBJC_SCOPE ANGLE_MTL_OBJC_SCOPE
{ {
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
id<MTLFunction> shader = nil;
auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE];
NSError *err = nil;
bool isU8 = false; bool isU8 = false;
bool isU16 = false; bool isU16 = false;
...@@ -611,96 +811,55 @@ AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getTriFanFromElemArrayGene ...@@ -611,96 +811,55 @@ AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getTriFanFromElemArrayGene
type:MTLDataTypeBool type:MTLDataTypeBool
withName:SOURCE_IDX_IS_U32_CONSTANT_NAME]; withName:SOURCE_IDX_IS_U32_CONSTANT_NAME];
shader = [shaderLib newFunctionWithName:@"genTriFanIndicesFromElements" EnsureSpecializedComputePipelineInitialized(
constantValues:funcConstants contextMtl->getDisplay(), @"genTriFanIndicesFromElements", funcConstants, &cache);
error:&err];
if (err && !shader)
{
ERR() << "Internal error: " << err.localizedDescription.UTF8String << "\n";
}
ASSERT([shader ANGLE_MTL_AUTORELEASE]);
cache = [[metalDevice newComputePipelineStateWithFunction:shader
error:&err] ANGLE_MTL_AUTORELEASE];
if (err && !cache)
{
ERR() << "Internal error: " << err.localizedDescription.UTF8String << "\n";
}
ASSERT(cache);
} }
} }
return cache; return cache;
} }
angle::Result RenderUtils::ensureTriFanFromArrayGeneratorInitialized(ContextMtl *context) void IndexGeneratorUtils::ensureTriFanFromArrayGeneratorInitialized(ContextMtl *contextMtl)
{ {
if (!mTriFanFromArraysGeneratorPipeline) EnsureComputePipelineInitialized(contextMtl->getDisplay(), @"genTriFanIndicesFromArray",
{ &mTriFanFromArraysGeneratorPipeline);
ANGLE_MTL_OBJC_SCOPE
{
id<MTLDevice> metalDevice = context->getMetalDevice();
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
NSError *err = nil;
id<MTLFunction> shader = [shaderLib newFunctionWithName:@"genTriFanIndicesFromArray"];
[shader ANGLE_MTL_AUTORELEASE];
mTriFanFromArraysGeneratorPipeline =
[[metalDevice newComputePipelineStateWithFunction:shader
error:&err] ANGLE_MTL_AUTORELEASE];
if (err && !mTriFanFromArraysGeneratorPipeline)
{
ERR() << "Internal error: " << err.localizedDescription.UTF8String << "\n";
}
ASSERT(mTriFanFromArraysGeneratorPipeline);
}
}
return angle::Result::Continue;
} }
angle::Result RenderUtils::convertIndexBuffer(const gl::Context *context, angle::Result IndexGeneratorUtils::convertIndexBufferGPU(ContextMtl *contextMtl,
gl::DrawElementsType srcType, const IndexConversionParams &params)
uint32_t indexCount,
const BufferRef &srcBuffer,
uint32_t srcOffset,
const BufferRef &dstBuffer,
uint32_t dstOffset)
{ {
ContextMtl *contextMtl = GetImpl(context);
ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
ASSERT(cmdEncoder); ASSERT(cmdEncoder);
AutoObjCPtr<id<MTLComputePipelineState>> pipelineState = AutoObjCPtr<id<MTLComputePipelineState>> pipelineState =
getIndexConversionPipeline(contextMtl, srcType, srcOffset); getIndexConversionPipeline(contextMtl, params.srcType, params.srcOffset);
ASSERT(pipelineState); ASSERT(pipelineState);
cmdEncoder->setComputePipelineState(pipelineState); cmdEncoder->setComputePipelineState(pipelineState);
ASSERT((dstOffset % kIndexBufferOffsetAlignment) == 0); ASSERT((params.dstOffset % kIndexBufferOffsetAlignment) == 0);
IndexConversionUniform uniform; IndexConversionUniform uniform;
uniform.srcOffset = srcOffset; uniform.srcOffset = params.srcOffset;
uniform.indexCount = indexCount; uniform.indexCount = params.indexCount;
cmdEncoder->setData(uniform, 0); cmdEncoder->setData(uniform, 0);
cmdEncoder->setBuffer(srcBuffer, 0, 1); cmdEncoder->setBuffer(params.srcBuffer, 0, 1);
cmdEncoder->setBuffer(dstBuffer, dstOffset, 2); cmdEncoder->setBuffer(params.dstBuffer, params.dstOffset, 2);
ANGLE_TRY(dispatchCompute(context, cmdEncoder, pipelineState, indexCount)); DispatchCompute(contextMtl, cmdEncoder, pipelineState, params.indexCount);
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result RenderUtils::generateTriFanBufferFromArrays(const gl::Context *context, angle::Result IndexGeneratorUtils::generateTriFanBufferFromArrays(
const TriFanFromArrayParams &params) ContextMtl *contextMtl,
const TriFanFromArrayParams &params)
{ {
ContextMtl *contextMtl = GetImpl(context);
ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
ASSERT(cmdEncoder); ASSERT(cmdEncoder);
ANGLE_TRY(ensureTriFanFromArrayGeneratorInitialized(contextMtl)); ensureTriFanFromArrayGeneratorInitialized(contextMtl);
ASSERT(params.vertexCount > 2); ASSERT(params.vertexCount > 2);
...@@ -721,37 +880,36 @@ angle::Result RenderUtils::generateTriFanBufferFromArrays(const gl::Context *con ...@@ -721,37 +880,36 @@ angle::Result RenderUtils::generateTriFanBufferFromArrays(const gl::Context *con
cmdEncoder->setData(uniform, 0); cmdEncoder->setData(uniform, 0);
cmdEncoder->setBuffer(params.dstBuffer, params.dstOffset, 2); cmdEncoder->setBuffer(params.dstBuffer, params.dstOffset, 2);
ANGLE_TRY(dispatchCompute(context, cmdEncoder, mTriFanFromArraysGeneratorPipeline, DispatchCompute(contextMtl, cmdEncoder, mTriFanFromArraysGeneratorPipeline,
uniform.vertexCountFrom3rd)); uniform.vertexCountFrom3rd);
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result RenderUtils::generateTriFanBufferFromElementsArray( angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArray(
const gl::Context *context, ContextMtl *contextMtl,
const IndexGenerationParams &params) const IndexGenerationParams &params)
{ {
ContextMtl *contextMtl = GetImpl(context); const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray();
const gl::VertexArray *vertexArray = context->getState().getVertexArray();
const gl::Buffer *elementBuffer = vertexArray->getElementArrayBuffer(); const gl::Buffer *elementBuffer = vertexArray->getElementArrayBuffer();
if (elementBuffer) if (elementBuffer)
{ {
size_t srcOffset = reinterpret_cast<size_t>(params.indices); BufferMtl *elementBufferMtl = GetImpl(elementBuffer);
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( return generateTriFanBufferFromElementsArrayGPU(
context, params.srcType, params.indexCount, contextMtl, params.srcType, params.indexCount, elementBufferMtl->getCurrentBuffer(),
GetImpl(elementBuffer)->getCurrentBuffer(context), static_cast<uint32_t>(srcOffset), static_cast<uint32_t>(srcOffset), params.dstBuffer, params.dstOffset);
params.dstBuffer, params.dstOffset);
} }
else else
{ {
return generateTriFanBufferFromElementsArrayCPU(context, params); return generateTriFanBufferFromElementsArrayCPU(contextMtl, params);
} }
} }
angle::Result RenderUtils::generateTriFanBufferFromElementsArrayGPU( angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayGPU(
const gl::Context *context, ContextMtl *contextMtl,
gl::DrawElementsType srcType, gl::DrawElementsType srcType,
uint32_t indexCount, uint32_t indexCount,
const BufferRef &srcBuffer, const BufferRef &srcBuffer,
...@@ -760,7 +918,6 @@ angle::Result RenderUtils::generateTriFanBufferFromElementsArrayGPU( ...@@ -760,7 +918,6 @@ angle::Result RenderUtils::generateTriFanBufferFromElementsArrayGPU(
// Must be multiples of kIndexBufferOffsetAlignment // Must be multiples of kIndexBufferOffsetAlignment
uint32_t dstOffset) uint32_t dstOffset)
{ {
ContextMtl *contextMtl = GetImpl(context);
ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
ASSERT(cmdEncoder); ASSERT(cmdEncoder);
...@@ -782,16 +939,15 @@ angle::Result RenderUtils::generateTriFanBufferFromElementsArrayGPU( ...@@ -782,16 +939,15 @@ angle::Result RenderUtils::generateTriFanBufferFromElementsArrayGPU(
cmdEncoder->setBuffer(srcBuffer, 0, 1); cmdEncoder->setBuffer(srcBuffer, 0, 1);
cmdEncoder->setBuffer(dstBuffer, dstOffset, 2); cmdEncoder->setBuffer(dstBuffer, dstOffset, 2);
ANGLE_TRY(dispatchCompute(context, cmdEncoder, pipelineState, uniform.indexCount)); DispatchCompute(contextMtl, cmdEncoder, pipelineState, uniform.indexCount);
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result RenderUtils::generateTriFanBufferFromElementsArrayCPU( angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayCPU(
const gl::Context *context, ContextMtl *contextMtl,
const IndexGenerationParams &params) const IndexGenerationParams &params)
{ {
ContextMtl *contextMtl = GetImpl(context);
switch (params.srcType) switch (params.srcType)
{ {
case gl::DrawElementsType::UnsignedByte: case gl::DrawElementsType::UnsignedByte:
...@@ -813,14 +969,13 @@ angle::Result RenderUtils::generateTriFanBufferFromElementsArrayCPU( ...@@ -813,14 +969,13 @@ angle::Result RenderUtils::generateTriFanBufferFromElementsArrayCPU(
return angle::Result::Stop; return angle::Result::Stop;
} }
angle::Result RenderUtils::generateLineLoopLastSegment(const gl::Context *context, angle::Result IndexGeneratorUtils::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)
{ {
ContextMtl *contextMtl = GetImpl(context); uint8_t *ptr = dstBuffer->map(contextMtl) + dstOffset;
uint8_t *ptr = dstBuffer->map(contextMtl);
uint32_t indices[2] = {lastVertex, firstVertex}; uint32_t indices[2] = {lastVertex, firstVertex};
memcpy(ptr, indices, sizeof(indices)); memcpy(ptr, indices, sizeof(indices));
...@@ -830,12 +985,11 @@ angle::Result RenderUtils::generateLineLoopLastSegment(const gl::Context *contex ...@@ -830,12 +985,11 @@ angle::Result RenderUtils::generateLineLoopLastSegment(const gl::Context *contex
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArray( angle::Result IndexGeneratorUtils::generateLineLoopLastSegmentFromElementsArray(
const gl::Context *context, ContextMtl *contextMtl,
const IndexGenerationParams &params) const IndexGenerationParams &params)
{ {
ContextMtl *contextMtl = GetImpl(context); const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray();
const gl::VertexArray *vertexArray = context->getState().getVertexArray();
const gl::Buffer *elementBuffer = vertexArray->getElementArrayBuffer(); const gl::Buffer *elementBuffer = vertexArray->getElementArrayBuffer();
if (elementBuffer) if (elementBuffer)
{ {
...@@ -845,21 +999,20 @@ angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArray( ...@@ -845,21 +999,20 @@ angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArray(
BufferMtl *bufferMtl = GetImpl(elementBuffer); BufferMtl *bufferMtl = GetImpl(elementBuffer);
std::pair<uint32_t, uint32_t> firstLast; std::pair<uint32_t, uint32_t> firstLast;
ANGLE_TRY(bufferMtl->getFirstLastIndices(context, params.srcType, ANGLE_TRY(bufferMtl->getFirstLastIndices(params.srcType, static_cast<uint32_t>(srcOffset),
static_cast<uint32_t>(srcOffset),
params.indexCount, &firstLast)); params.indexCount, &firstLast));
return generateLineLoopLastSegment(context, firstLast.first, firstLast.second, return generateLineLoopLastSegment(contextMtl, firstLast.first, firstLast.second,
params.dstBuffer, params.dstOffset); params.dstBuffer, params.dstOffset);
} }
else else
{ {
return generateLineLoopLastSegmentFromElementsArrayCPU(context, params); return generateLineLoopLastSegmentFromElementsArrayCPU(contextMtl, params);
} }
} }
angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArrayCPU( angle::Result IndexGeneratorUtils::generateLineLoopLastSegmentFromElementsArrayCPU(
const gl::Context *context, ContextMtl *contextMtl,
const IndexGenerationParams &params) const IndexGenerationParams &params)
{ {
uint32_t first, last; uint32_t first, last;
...@@ -883,29 +1036,8 @@ angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArrayCPU( ...@@ -883,29 +1036,8 @@ angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArrayCPU(
return angle::Result::Stop; return angle::Result::Stop;
} }
return generateLineLoopLastSegment(context, first, last, params.dstBuffer, params.dstOffset); return generateLineLoopLastSegment(contextMtl, first, last, params.dstBuffer, params.dstOffset);
} }
angle::Result RenderUtils::dispatchCompute(const gl::Context *context,
ComputeCommandEncoder *cmdEncoder,
id<MTLComputePipelineState> pipelineState,
size_t numThreads)
{
NSUInteger w = pipelineState.threadExecutionWidth;
MTLSize threadsPerThreadgroup = MTLSizeMake(w, 1, 1);
if (getDisplay()->getFeatures().hasNonUniformDispatch.enabled)
{
MTLSize threads = MTLSizeMake(numThreads, 1, 1);
cmdEncoder->dispatchNonUniform(threads, threadsPerThreadgroup);
}
else
{
MTLSize groups = MTLSizeMake((numThreads + w - 1) / w, 1, 1);
cmdEncoder->dispatch(groups, threadsPerThreadgroup);
}
return angle::Result::Continue;
}
} // namespace mtl } // namespace mtl
} // namespace rx } // namespace rx
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