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
// 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
// right before the draw call to retrieved the most up-to-date mtl::Buffer.
mtl::BufferRef getCurrentBuffer(const gl::Context *context)
{
return mIsWeak ? mBufferWeakRef.lock() : mBuffer;
}
mtl::BufferRef getCurrentBuffer() { return mIsWeak ? mBufferWeakRef.lock() : mBuffer; }
protected:
mtl::BufferRef mBuffer;
......@@ -111,8 +108,7 @@ class BufferMtl : public BufferImpl, public BufferHolderMtl
bool primitiveRestartEnabled,
gl::IndexRange *outRange) override;
angle::Result getFirstLastIndices(const gl::Context *context,
gl::DrawElementsType type,
angle::Result getFirstLastIndices(gl::DrawElementsType type,
size_t offset,
size_t count,
std::pair<uint32_t, uint32_t> *outIndices) const;
......
......@@ -228,8 +228,7 @@ angle::Result BufferMtl::getIndexRange(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result BufferMtl::getFirstLastIndices(const gl::Context *context,
gl::DrawElementsType type,
angle::Result BufferMtl::getFirstLastIndices(gl::DrawElementsType type,
size_t offset,
size_t count,
std::pair<uint32_t, uint32_t> *outIndices) const
......
......@@ -175,7 +175,7 @@ angle::Result ContextMtl::drawTriFanArraysWithBaseVertex(const gl::Context *cont
ANGLE_TRY(
mtl::Buffer::MakeBuffer(this, indexBufferSize, nullptr, &mTriFanArraysIndexBuffer));
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,
......@@ -203,8 +203,8 @@ angle::Result ContextMtl::drawTriFanArraysLegacy(const gl::Context *context,
ANGLE_TRY(AllocateTriangleFanBufferFromPool(this, count, &mTriFanIndexBuffer, &genIdxBuffer,
&genIdxBufferOffset, &genIndicesCount));
ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromArrays(
context, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer,
genIdxBufferOffset}));
this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer,
genIdxBufferOffset}));
ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances,
gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0)));
......@@ -314,7 +314,7 @@ angle::Result ContextMtl::drawTriFanElements(const gl::Context *context,
&genIdxBufferOffset, &genIndicesCount));
ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromElementsArray(
context, {type, count, indices, genIdxBuffer, genIdxBufferOffset}));
this, {type, count, indices, genIdxBuffer, genIdxBufferOffset}));
ANGLE_TRY(mTriFanIndexBuffer.commit(this));
......@@ -1552,7 +1552,7 @@ angle::Result ContextMtl::genLineLoopLastSegment(const gl::Context *context,
if (indexTypeOrNone == gl::DrawElementsType::InvalidEnum)
{
ANGLE_TRY(getDisplay()->getUtils().generateLineLoopLastSegment(
context, firstVertex, firstVertex + vertexOrIndexCount - 1, newBuffer, 0));
this, firstVertex, firstVertex + vertexOrIndexCount - 1, newBuffer, 0));
}
else
{
......@@ -1560,7 +1560,7 @@ angle::Result ContextMtl::genLineLoopLastSegment(const gl::Context *context,
// taken into account
ASSERT(firstVertex == 0);
ANGLE_TRY(getDisplay()->getUtils().generateLineLoopLastSegmentFromElementsArray(
context, {indexTypeOrNone, vertexOrIndexCount, indices, newBuffer, 0}));
this, {indexTypeOrNone, vertexOrIndexCount, indices, newBuffer, 0}));
}
ANGLE_TRY(mLineLoopIndexBuffer.commit(this));
......
......@@ -534,9 +534,7 @@ angle::Result FramebufferMtl::clearWithDraw(const gl::Context *context,
// Start new render encoder if not already.
mtl::RenderCommandEncoder *encoder = contextMtl->getRenderCommandEncoder(mRenderPassDesc);
display->getUtils().clearWithDraw(context, encoder, clearOpts);
return angle::Result::Continue;
return display->getUtils().clearWithDraw(context, encoder, clearOpts);
}
angle::Result FramebufferMtl::clearImpl(const gl::Context *context,
......
......@@ -1200,9 +1200,7 @@ angle::Result TextureMtl::copySubImageWithDraw(const gl::Context *context,
blitParams.srcYFlipped = framebufferMtl->flipY();
blitParams.dstLuminance = internalFormat.isLUMA();
displayMtl->getUtils().blitWithDraw(context, cmdEncoder, blitParams);
return angle::Result::Continue;
return displayMtl->getUtils().blitWithDraw(context, cmdEncoder, blitParams);
}
angle::Result TextureMtl::copySubImageCPU(const gl::Context *context,
......
......@@ -315,7 +315,7 @@ angle::Result VertexArrayMtl::setupDraw(const gl::Context *glContext,
}
desc.layouts[bufferIdx].stride = mCurrentArrayBufferStrides[v];
cmdEncoder->setVertexBuffer(mCurrentArrayBuffers[v]->getCurrentBuffer(glContext),
cmdEncoder->setVertexBuffer(mCurrentArrayBuffers[v]->getCurrentBuffer(),
bufferOffset, bufferIdx);
}
else
......@@ -487,7 +487,7 @@ angle::Result VertexArrayMtl::getIndexBuffer(const gl::Context *context,
{
// No conversion needed:
BufferMtl *bufferMtl = mtl::GetImpl(glElementArrayBuffer);
*idxBufferOut = bufferMtl->getCurrentBuffer(context);
*idxBufferOut = bufferMtl->getCurrentBuffer();
*idxBufferOffsetOut = convertedOffset;
}
}
......@@ -555,10 +555,11 @@ angle::Result VertexArrayMtl::convertIndexBufferGPU(const gl::Context *glContext
&conversion->convertedOffset));
// Do the conversion on GPU.
ANGLE_TRY(display->getUtils().convertIndexBuffer(
glContext, indexType, static_cast<uint32_t>(indexCount),
idxBuffer->getCurrentBuffer(glContext), static_cast<uint32_t>(offset),
conversion->convertedBuffer, static_cast<uint32_t>(conversion->convertedOffset)));
ANGLE_TRY(display->getUtils().convertIndexBufferGPU(
mtl::GetImpl(glContext),
{indexType, static_cast<uint32_t>(indexCount), idxBuffer->getCurrentBuffer(),
static_cast<uint32_t>(offset), conversion->convertedBuffer,
static_cast<uint32_t>(conversion->convertedOffset)}));
ANGLE_TRY(conversion->data.commit(contextMtl));
......@@ -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
// changed.
conversion->convertedBuffer =
mConvertedArrayBufferHolders[attribIndex].getCurrentBuffer(glContext);
conversion->convertedBuffer = mConvertedArrayBufferHolders[attribIndex].getCurrentBuffer();
conversion->convertedOffset = mCurrentArrayBufferOffsets[attribIndex];
#ifndef NDEBUG
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,
binding.getOffset(), binding.getStride()];
}
......
......@@ -62,6 +62,18 @@ struct TriFanFromArrayParams
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
{
gl::DrawElementsType srcType;
......@@ -71,93 +83,116 @@ struct IndexGenerationParams
uint32_t dstOffset;
};
class RenderUtils : public Context, angle::NonCopyable
// Utils class for clear & blitting
class ClearUtils
{
public:
RenderUtils(DisplayMtl *display);
~RenderUtils() override;
ClearUtils();
angle::Result initialize();
void onDestroy();
// Clear current framebuffer
void clearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
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);
angle::Result clearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const ClearRectParams &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;
void initClearResources();
void initBlitResources();
// Defer loading of render pipeline state cache.
void ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx);
void setupClearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params);
void setupBlitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params);
id<MTLDepthStencilState> getClearDepthStencilState(const gl::Context *context,
const ClearRectParams &params);
id<MTLRenderPipelineState> getClearRenderPipelineState(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
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,
RenderCommandEncoder *cmdEncoder,
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(
ContextMtl *context,
ContextMtl *contextMtl,
gl::DrawElementsType srcType,
uint32_t srcOffset);
// Get compute pipeline to generate tri fan index for glDrawElements().
AutoObjCPtr<id<MTLComputePipelineState>> getTriFanFromElemArrayGeneratorPipeline(
ContextMtl *context,
ContextMtl *contextMtl,
gl::DrawElementsType srcType,
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(
const gl::Context *context,
ContextMtl *contextMtl,
gl::DrawElementsType srcType,
uint32_t indexCount,
const BufferRef &srcBuffer,
......@@ -165,29 +200,69 @@ class RenderUtils : public Context, angle::NonCopyable
const BufferRef &dstBuffer,
// Must be multiples of kIndexBufferOffsetAlignment
uint32_t dstOffset);
angle::Result generateTriFanBufferFromElementsArrayCPU(const gl::Context *context,
angle::Result generateTriFanBufferFromElementsArrayCPU(ContextMtl *contextMtl,
const IndexGenerationParams &params);
angle::Result generateLineLoopLastSegmentFromElementsArrayCPU(
const gl::Context *context,
ContextMtl *contextMtl,
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 mTriFanFromElemArrayGeneratorPipelineCaches;
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 rx
......
......@@ -30,6 +30,7 @@ namespace
#define SOURCE_IDX_IS_U16_CONSTANT_NAME @"kSourceIndexIsU16"
#define SOURCE_IDX_IS_U32_CONSTANT_NAME @"kSourceIndexIsU32"
// See libANGLE/renderer/metal/shaders/clear.metal
struct ClearParamsUniform
{
float clearColor[4];
......@@ -37,6 +38,7 @@ struct ClearParamsUniform
float padding[3];
};
// See libANGLE/renderer/metal/shaders/blit.metal
struct BlitParamsUniform
{
// 0: lower left, 1: lower right, 2: upper left
......@@ -55,6 +57,40 @@ struct IndexConversionUniform
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>
angle::Result GenTriFanFromClientElements(ContextMtl *contextMtl,
GLsizei count,
......@@ -95,6 +131,82 @@ void GetFirstLastIndicesFromClientElements(GLsizei count,
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>
void ClearPipelineStateArray(T *pipelineCacheArray)
{
......@@ -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
// RenderUtils implementation
RenderUtils::RenderUtils(DisplayMtl *display) : Context(display) {}
RenderUtils::~RenderUtils() {}
angle::Result RenderUtils::initialize()
{
initClearResources();
initBlitResources();
return angle::Result::Continue;
}
void RenderUtils::onDestroy()
{
mClearRenderPipelineCache.clear();
mBlitRenderPipelineCache.clear();
mBlitPremultiplyAlphaRenderPipelineCache.clear();
mBlitUnmultiplyAlphaRenderPipelineCache.clear();
ClearPipelineState2DArray(&mIndexConversionPipelineCaches);
ClearPipelineState2DArray(&mTriFanFromElemArrayGeneratorPipelineCaches);
mTriFanFromArraysGeneratorPipeline = nil;
mIndexUtils.onDestroy();
mClearUtils.onDestroy();
mColorBlitUtils.onDestroy();
}
// override ErrorHandler
......@@ -164,105 +337,146 @@ void RenderUtils::handleError(NSError *nserror,
<< 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
{
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]);
}
return mClearUtils.clearWithDraw(context, cmdEncoder, params);
}
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
{
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
id<MTLFunction> vertexShader =
[[shaderLib newFunctionWithName:@"blitVS"] ANGLE_MTL_AUTORELEASE];
return mColorBlitUtils.blitWithDraw(context, cmdEncoder, params);
}
angle::Result RenderUtils::convertIndexBufferGPU(ContextMtl *contextMtl,
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);
mBlitRenderPipelineCache.setFragmentShader(
this, [[shaderLib newFunctionWithName:@"blitFS"] ANGLE_MTL_AUTORELEASE]);
void ClearUtils::onDestroy()
{
mClearRenderPipelineCache.clear();
}
mBlitPremultiplyAlphaRenderPipelineCache.setVertexShader(this, vertexShader);
mBlitPremultiplyAlphaRenderPipelineCache.setFragmentShader(
this,
[[shaderLib newFunctionWithName:@"blitPremultiplyAlphaFS"] ANGLE_MTL_AUTORELEASE]);
void ClearUtils::ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx)
{
ANGLE_MTL_OBJC_SCOPE
{
id<MTLLibrary> shaderLib = ctx->getDisplay()->getDefaultShadersLib();
mBlitUnmultiplyAlphaRenderPipelineCache.setVertexShader(this, vertexShader);
mBlitUnmultiplyAlphaRenderPipelineCache.setFragmentShader(
this, [[shaderLib newFunctionWithName:@"blitUnmultiplyAlphaFS"] ANGLE_MTL_AUTORELEASE]);
mClearRenderPipelineCache.setVertexShader(
ctx, [[shaderLib newFunctionWithName:@"clearVS"] ANGLE_MTL_AUTORELEASE]);
mClearRenderPipelineCache.setFragmentShader(
ctx, [[shaderLib newFunctionWithName:@"clearFS"] ANGLE_MTL_AUTORELEASE]);
}
}
void RenderUtils::clearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params)
id<MTLDepthStencilState> ClearUtils::getClearDepthStencilState(const gl::Context *context,
const ClearRectParams &params)
{
auto overridedParams = params;
// Make sure we don't clear attachment that doesn't exist
const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
if (renderPassDesc.numColorAttachments == 0)
ContextMtl *contextMtl = GetImpl(context);
if (!params.clearDepth.valid() && !params.clearStencil.valid())
{
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() &&
!overridedParams.clearStencil.valid())
if (params.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);
// Draw the screen aligned triangle
cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
// Invalidate current context's state
auto contextMtl = GetImpl(context);
contextMtl->invalidateState(context);
return contextMtl->getDisplay()->getStateCache().getDepthStencilState(
contextMtl->getMetalDevice(), desc);
}
void RenderUtils::blitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params)
id<MTLRenderPipelineState> ClearUtils::getClearRenderPipelineState(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
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
cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
RenderPipelineDesc pipelineDesc;
const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
// Invalidate current context's state
ContextMtl *contextMtl = GetImpl(context);
contextMtl->invalidateState(context);
renderPassDesc.populateRenderPipelineOutputDesc(colorMask, &pipelineDesc.outputDescriptor);
pipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassTriangle;
ensureRenderPipelineStateCacheInitialized(contextMtl);
return mClearRenderPipelineCache.getRenderPipelineState(contextMtl, pipelineDesc);
}
void RenderUtils::setupClearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params)
void ClearUtils::setupClearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params)
{
// Generate render pipeline state
auto renderPipelineState = getClearRenderPipelineState(context, cmdEncoder, params);
id<MTLRenderPipelineState> renderPipelineState =
getClearRenderPipelineState(context, cmdEncoder, params);
ASSERT(renderPipelineState);
// Setup states
setupDrawCommonStates(cmdEncoder);
SetupFullscreenDrawCommonStates(cmdEncoder);
cmdEncoder->setRenderPipelineState(renderPipelineState);
id<MTLDepthStencilState> dsState = getClearDepthStencilState(context, params);
......@@ -290,7 +504,7 @@ void RenderUtils::setupClearWithDraw(const gl::Context *context,
renderPassAttachment = renderPassDesc.stencilAttachment;
}
auto texture = renderPassAttachment.texture;
TextureRef texture = renderPassAttachment.texture;
viewport =
GetViewport(params.clearArea, texture->height(renderPassAttachment.level), params.flipY);
......@@ -313,109 +527,92 @@ void RenderUtils::setupClearWithDraw(const gl::Context *context,
cmdEncoder->setFragmentData(uniformParams, 0);
}
void RenderUtils::setupBlitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params)
angle::Result ClearUtils::clearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params)
{
ASSERT(cmdEncoder->renderPassDesc().numColorAttachments == 1 && params.src);
// 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
ClearRectParams overridedParams = params;
// Make sure we don't clear attachment that doesn't exist
const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
const RenderPassColorAttachmentDesc &renderPassColorAttachment =
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())
if (renderPassDesc.numColorAttachments == 0)
{
// Doesn't clear depth nor stencil
return getDisplay()->getStateCache().getNullDepthStencilState(this);
overridedParams.clearColor.reset();
}
ContextMtl *contextMtl = GetImpl(context);
DepthStencilDesc desc;
desc.reset();
if (params.clearDepth.valid())
if (!renderPassDesc.depthAttachment.texture)
{
// Clear depth state
desc.depthWriteEnabled = true;
overridedParams.clearDepth.reset();
}
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
desc.frontFaceStencil.depthStencilPassOperation = MTLStencilOperationReplace;
desc.frontFaceStencil.writeMask = contextMtl->getStencilMask();
desc.backFaceStencil.depthStencilPassOperation = MTLStencilOperationReplace;
desc.backFaceStencil.writeMask = contextMtl->getStencilMask();
return angle::Result::Continue;
}
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(
const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params)
// ColorBlitUtils implementation
ColorBlitUtils::ColorBlitUtils() = default;
void ColorBlitUtils::onDestroy()
{
ContextMtl *contextMtl = GetImpl(context);
MTLColorWriteMask colorMask = contextMtl->getColorMask();
if (!params.clearColor.valid())
mBlitRenderPipelineCache.clear();
mBlitPremultiplyAlphaRenderPipelineCache.clear();
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;
const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
renderPassDesc.populateRenderPipelineOutputDesc(colorMask, &pipelineDesc.outputDescriptor);
ANGLE_MTL_OBJC_SCOPE
{
NSString *const fragmentShaderNames[] = {// Normal blit
@"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,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params)
id<MTLRenderPipelineState> ColorBlitUtils::getBlitRenderPipelineState(
const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params)
{
ContextMtl *contextMtl = GetImpl(context);
RenderPipelineDesc pipelineDesc;
......@@ -427,157 +624,160 @@ id<MTLRenderPipelineState> RenderUtils::getBlitRenderPipelineState(const gl::Con
pipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassTriangle;
RenderPipelineCache *pipelineCache;
int alphaPremultiplyType;
if (params.unpackPremultiplyAlpha == params.unpackUnmultiplyAlpha)
{
pipelineCache = &mBlitRenderPipelineCache;
alphaPremultiplyType = 0;
pipelineCache = &mBlitRenderPipelineCache;
}
else if (params.unpackPremultiplyAlpha)
{
pipelineCache = &mBlitPremultiplyAlphaRenderPipelineCache;
alphaPremultiplyType = 1;
pipelineCache = &mBlitPremultiplyAlphaRenderPipelineCache;
}
else
{
pipelineCache = &mBlitUnmultiplyAlphaRenderPipelineCache;
alphaPremultiplyType = 2;
pipelineCache = &mBlitUnmultiplyAlphaRenderPipelineCache;
}
ensureRenderPipelineStateCacheInitialized(contextMtl, alphaPremultiplyType, pipelineCache);
return pipelineCache->getRenderPipelineState(contextMtl, pipelineDesc);
}
void RenderUtils::setupBlitWithDrawUniformData(RenderCommandEncoder *cmdEncoder,
const BlitParams &params)
void ColorBlitUtils::setupBlitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams &params)
{
BlitParamsUniform uniformParams;
uniformParams.dstFlipY = params.dstFlipY ? 1 : 0;
uniformParams.srcLevel = params.srcLevel;
uniformParams.dstLuminance = params.dstLuminance ? 1 : 0;
ASSERT(cmdEncoder->renderPassDesc().numColorAttachments == 1 && params.src);
// Compute source texCoords
auto srcWidth = params.src->width(params.srcLevel);
auto srcHeight = params.src->height(params.srcLevel);
ContextMtl *contextMtl = mtl::GetImpl(context);
int x0 = params.srcRect.x0(); // left
int x1 = params.srcRect.x1(); // right
int y0 = params.srcRect.y0(); // lower
int y1 = params.srcRect.y1(); // upper
if (params.srcYFlipped)
{
// If source's Y has been flipped, such as default framebuffer, then adjust the real source
// rectangle.
y0 = srcHeight - y1;
y1 = y0 + params.srcRect.height;
std::swap(y0, y1);
}
// Generate render pipeline state
id<MTLRenderPipelineState> renderPipelineState =
getBlitRenderPipelineState(context, cmdEncoder, params);
ASSERT(renderPipelineState);
// Setup states
SetupFullscreenDrawCommonStates(cmdEncoder);
cmdEncoder->setRenderPipelineState(renderPipelineState);
cmdEncoder->setDepthStencilState(
contextMtl->getDisplay()->getStateCache().getNullDepthStencilState(contextMtl));
// 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;
float u1 = static_cast<float>(x1) / srcWidth;
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;
// Draw the screen aligned triangle
cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3);
// lower left
uniformParams.srcTexCoords[0][0] = u0;
uniformParams.srcTexCoords[0][1] = v0;
// Invalidate current context's state
contextMtl->invalidateState(context);
// lower right
uniformParams.srcTexCoords[1][0] = u1 + du;
uniformParams.srcTexCoords[1][1] = v0;
return angle::Result::Continue;
}
// upper left
uniformParams.srcTexCoords[2][0] = u0;
uniformParams.srcTexCoords[2][1] = v1 + dv;
// IndexGeneratorUtils implementation
void IndexGeneratorUtils::onDestroy()
{
ClearPipelineState2DArray(&mIndexConversionPipelineCaches);
ClearPipelineState2DArray(&mTriFanFromElemArrayGeneratorPipelineCaches);
cmdEncoder->setVertexData(uniformParams, 0);
cmdEncoder->setFragmentData(uniformParams, 0);
mTriFanFromArraysGeneratorPipeline = nil;
}
AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getIndexConversionPipeline(
ContextMtl *context,
AutoObjCPtr<id<MTLComputePipelineState>> IndexGeneratorUtils::getIndexConversionPipeline(
ContextMtl *contextMtl,
gl::DrawElementsType srcType,
uint32_t srcOffset)
{
id<MTLDevice> metalDevice = context->getMetalDevice();
size_t elementSize = gl::GetDrawElementsTypeSize(srcType);
BOOL aligned = (srcOffset % elementSize) == 0;
int srcTypeKey = static_cast<int>(srcType);
auto &cache = mIndexConversionPipelineCaches[srcTypeKey][aligned ? 1 : 0];
size_t elementSize = gl::GetDrawElementsTypeSize(srcType);
BOOL aligned = (srcOffset % elementSize) == 0;
int srcTypeKey = static_cast<int>(srcType);
AutoObjCPtr<id<MTLComputePipelineState>> &cache =
mIndexConversionPipelineCaches[srcTypeKey][aligned ? 1 : 0];
if (!cache)
{
ANGLE_MTL_OBJC_SCOPE
{
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
id<MTLFunction> shader = nil;
auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE];
NSError *err = nil;
[funcConstants setConstantValue:&aligned
type:MTLDataTypeBool
withName:SOURCE_BUFFER_ALIGNED_CONSTANT_NAME];
NSString *shaderName = nil;
switch (srcType)
{
case gl::DrawElementsType::UnsignedByte:
shader = [shaderLib newFunctionWithName:@"convertIndexU8ToU16"];
// No need for specialized shader
funcConstants = nil;
shaderName = @"convertIndexU8ToU16";
break;
case gl::DrawElementsType::UnsignedShort:
shader = [shaderLib newFunctionWithName:@"convertIndexU16"
constantValues:funcConstants
error:&err];
shaderName = @"convertIndexU16";
break;
case gl::DrawElementsType::UnsignedInt:
shader = [shaderLib newFunctionWithName:@"convertIndexU32"
constantValues:funcConstants
error:&err];
shaderName = @"convertIndexU32";
break;
default:
UNREACHABLE();
}
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);
EnsureSpecializedComputePipelineInitialized(contextMtl->getDisplay(), shaderName,
funcConstants, &cache);
}
}
return cache;
}
AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getTriFanFromElemArrayGeneratorPipeline(
ContextMtl *context,
gl::DrawElementsType srcType,
uint32_t srcOffset)
AutoObjCPtr<id<MTLComputePipelineState>>
IndexGeneratorUtils::getTriFanFromElemArrayGeneratorPipeline(ContextMtl *contextMtl,
gl::DrawElementsType srcType,
uint32_t srcOffset)
{
id<MTLDevice> metalDevice = context->getMetalDevice();
size_t elementSize = gl::GetDrawElementsTypeSize(srcType);
BOOL aligned = (srcOffset % elementSize) == 0;
int srcTypeKey = static_cast<int>(srcType);
size_t elementSize = gl::GetDrawElementsTypeSize(srcType);
BOOL aligned = (srcOffset % elementSize) == 0;
int srcTypeKey = static_cast<int>(srcType);
auto &cache = mTriFanFromElemArrayGeneratorPipelineCaches[srcTypeKey][aligned ? 1 : 0];
AutoObjCPtr<id<MTLComputePipelineState>> &cache =
mTriFanFromElemArrayGeneratorPipelineCaches[srcTypeKey][aligned ? 1 : 0];
if (!cache)
{
ANGLE_MTL_OBJC_SCOPE
{
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
id<MTLFunction> shader = nil;
auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE];
NSError *err = nil;
bool isU8 = false;
bool isU16 = false;
......@@ -611,96 +811,55 @@ AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getTriFanFromElemArrayGene
type:MTLDataTypeBool
withName:SOURCE_IDX_IS_U32_CONSTANT_NAME];
shader = [shaderLib newFunctionWithName:@"genTriFanIndicesFromElements"
constantValues:funcConstants
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);
EnsureSpecializedComputePipelineInitialized(
contextMtl->getDisplay(), @"genTriFanIndicesFromElements", funcConstants, &cache);
}
}
return cache;
}
angle::Result RenderUtils::ensureTriFanFromArrayGeneratorInitialized(ContextMtl *context)
void IndexGeneratorUtils::ensureTriFanFromArrayGeneratorInitialized(ContextMtl *contextMtl)
{
if (!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;
EnsureComputePipelineInitialized(contextMtl->getDisplay(), @"genTriFanIndicesFromArray",
&mTriFanFromArraysGeneratorPipeline);
}
angle::Result RenderUtils::convertIndexBuffer(const gl::Context *context,
gl::DrawElementsType srcType,
uint32_t indexCount,
const BufferRef &srcBuffer,
uint32_t srcOffset,
const BufferRef &dstBuffer,
uint32_t dstOffset)
angle::Result IndexGeneratorUtils::convertIndexBufferGPU(ContextMtl *contextMtl,
const IndexConversionParams &params)
{
ContextMtl *contextMtl = GetImpl(context);
ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
ASSERT(cmdEncoder);
AutoObjCPtr<id<MTLComputePipelineState>> pipelineState =
getIndexConversionPipeline(contextMtl, srcType, srcOffset);
getIndexConversionPipeline(contextMtl, params.srcType, params.srcOffset);
ASSERT(pipelineState);
cmdEncoder->setComputePipelineState(pipelineState);
ASSERT((dstOffset % kIndexBufferOffsetAlignment) == 0);
ASSERT((params.dstOffset % kIndexBufferOffsetAlignment) == 0);
IndexConversionUniform uniform;
uniform.srcOffset = srcOffset;
uniform.indexCount = indexCount;
uniform.srcOffset = params.srcOffset;
uniform.indexCount = params.indexCount;
cmdEncoder->setData(uniform, 0);
cmdEncoder->setBuffer(srcBuffer, 0, 1);
cmdEncoder->setBuffer(dstBuffer, dstOffset, 2);
cmdEncoder->setBuffer(params.srcBuffer, 0, 1);
cmdEncoder->setBuffer(params.dstBuffer, params.dstOffset, 2);
ANGLE_TRY(dispatchCompute(context, cmdEncoder, pipelineState, indexCount));
DispatchCompute(contextMtl, cmdEncoder, pipelineState, params.indexCount);
return angle::Result::Continue;
}
angle::Result RenderUtils::generateTriFanBufferFromArrays(const gl::Context *context,
const TriFanFromArrayParams &params)
angle::Result IndexGeneratorUtils::generateTriFanBufferFromArrays(
ContextMtl *contextMtl,
const TriFanFromArrayParams &params)
{
ContextMtl *contextMtl = GetImpl(context);
ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
ASSERT(cmdEncoder);
ANGLE_TRY(ensureTriFanFromArrayGeneratorInitialized(contextMtl));
ensureTriFanFromArrayGeneratorInitialized(contextMtl);
ASSERT(params.vertexCount > 2);
......@@ -721,37 +880,36 @@ angle::Result RenderUtils::generateTriFanBufferFromArrays(const gl::Context *con
cmdEncoder->setData(uniform, 0);
cmdEncoder->setBuffer(params.dstBuffer, params.dstOffset, 2);
ANGLE_TRY(dispatchCompute(context, cmdEncoder, mTriFanFromArraysGeneratorPipeline,
uniform.vertexCountFrom3rd));
DispatchCompute(contextMtl, cmdEncoder, mTriFanFromArraysGeneratorPipeline,
uniform.vertexCountFrom3rd);
return angle::Result::Continue;
}
angle::Result RenderUtils::generateTriFanBufferFromElementsArray(
const gl::Context *context,
angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArray(
ContextMtl *contextMtl,
const IndexGenerationParams &params)
{
ContextMtl *contextMtl = GetImpl(context);
const gl::VertexArray *vertexArray = context->getState().getVertexArray();
const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray();
const gl::Buffer *elementBuffer = vertexArray->getElementArrayBuffer();
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(),
"Index offset is too large", GL_INVALID_VALUE);
return generateTriFanBufferFromElementsArrayGPU(
context, params.srcType, params.indexCount,
GetImpl(elementBuffer)->getCurrentBuffer(context), static_cast<uint32_t>(srcOffset),
params.dstBuffer, params.dstOffset);
contextMtl, params.srcType, params.indexCount, elementBufferMtl->getCurrentBuffer(),
static_cast<uint32_t>(srcOffset), params.dstBuffer, params.dstOffset);
}
else
{
return generateTriFanBufferFromElementsArrayCPU(context, params);
return generateTriFanBufferFromElementsArrayCPU(contextMtl, params);
}
}
angle::Result RenderUtils::generateTriFanBufferFromElementsArrayGPU(
const gl::Context *context,
angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayGPU(
ContextMtl *contextMtl,
gl::DrawElementsType srcType,
uint32_t indexCount,
const BufferRef &srcBuffer,
......@@ -760,7 +918,6 @@ angle::Result RenderUtils::generateTriFanBufferFromElementsArrayGPU(
// Must be multiples of kIndexBufferOffsetAlignment
uint32_t dstOffset)
{
ContextMtl *contextMtl = GetImpl(context);
ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder();
ASSERT(cmdEncoder);
......@@ -782,16 +939,15 @@ angle::Result RenderUtils::generateTriFanBufferFromElementsArrayGPU(
cmdEncoder->setBuffer(srcBuffer, 0, 1);
cmdEncoder->setBuffer(dstBuffer, dstOffset, 2);
ANGLE_TRY(dispatchCompute(context, cmdEncoder, pipelineState, uniform.indexCount));
DispatchCompute(contextMtl, cmdEncoder, pipelineState, uniform.indexCount);
return angle::Result::Continue;
}
angle::Result RenderUtils::generateTriFanBufferFromElementsArrayCPU(
const gl::Context *context,
angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayCPU(
ContextMtl *contextMtl,
const IndexGenerationParams &params)
{
ContextMtl *contextMtl = GetImpl(context);
switch (params.srcType)
{
case gl::DrawElementsType::UnsignedByte:
......@@ -813,14 +969,13 @@ angle::Result RenderUtils::generateTriFanBufferFromElementsArrayCPU(
return angle::Result::Stop;
}
angle::Result RenderUtils::generateLineLoopLastSegment(const gl::Context *context,
uint32_t firstVertex,
uint32_t lastVertex,
const BufferRef &dstBuffer,
uint32_t dstOffset)
angle::Result IndexGeneratorUtils::generateLineLoopLastSegment(ContextMtl *contextMtl,
uint32_t firstVertex,
uint32_t lastVertex,
const BufferRef &dstBuffer,
uint32_t dstOffset)
{
ContextMtl *contextMtl = GetImpl(context);
uint8_t *ptr = dstBuffer->map(contextMtl);
uint8_t *ptr = dstBuffer->map(contextMtl) + dstOffset;
uint32_t indices[2] = {lastVertex, firstVertex};
memcpy(ptr, indices, sizeof(indices));
......@@ -830,12 +985,11 @@ angle::Result RenderUtils::generateLineLoopLastSegment(const gl::Context *contex
return angle::Result::Continue;
}
angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArray(
const gl::Context *context,
angle::Result IndexGeneratorUtils::generateLineLoopLastSegmentFromElementsArray(
ContextMtl *contextMtl,
const IndexGenerationParams &params)
{
ContextMtl *contextMtl = GetImpl(context);
const gl::VertexArray *vertexArray = context->getState().getVertexArray();
const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray();
const gl::Buffer *elementBuffer = vertexArray->getElementArrayBuffer();
if (elementBuffer)
{
......@@ -845,21 +999,20 @@ angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArray(
BufferMtl *bufferMtl = GetImpl(elementBuffer);
std::pair<uint32_t, uint32_t> firstLast;
ANGLE_TRY(bufferMtl->getFirstLastIndices(context, params.srcType,
static_cast<uint32_t>(srcOffset),
ANGLE_TRY(bufferMtl->getFirstLastIndices(params.srcType, static_cast<uint32_t>(srcOffset),
params.indexCount, &firstLast));
return generateLineLoopLastSegment(context, firstLast.first, firstLast.second,
return generateLineLoopLastSegment(contextMtl, firstLast.first, firstLast.second,
params.dstBuffer, params.dstOffset);
}
else
{
return generateLineLoopLastSegmentFromElementsArrayCPU(context, params);
return generateLineLoopLastSegmentFromElementsArrayCPU(contextMtl, params);
}
}
angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArrayCPU(
const gl::Context *context,
angle::Result IndexGeneratorUtils::generateLineLoopLastSegmentFromElementsArrayCPU(
ContextMtl *contextMtl,
const IndexGenerationParams &params)
{
uint32_t first, last;
......@@ -883,29 +1036,8 @@ angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArrayCPU(
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 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