mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-04 22:09:59 +03:00
Metal: Cache compute pipelines for provoking vertex emulation
Remove ProvokingVertexComputePipelineCache and update ProvokingVertexHelper to use the PipelineCache. Bug: chromium:1329376 Change-Id: Ifca89fbb572d850c806b24f124fb86c65eec4f11 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4637204 Reviewed-by: Quyen Le <lehoangquyen@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org>
This commit is contained in:
committed by
Angle LUCI CQ
parent
927410a8c1
commit
3a0da09d8b
@@ -681,12 +681,13 @@ angle::Result ContextMtl::drawArraysProvokingVertexImpl(const gl::Context *conte
|
||||
gl::DrawElementsType convertedType = gl::DrawElementsType::UnsignedInt;
|
||||
gl::PrimitiveMode outIndexMode = gl::PrimitiveMode::InvalidEnum;
|
||||
|
||||
mtl::BufferRef drawIdxBuffer = mProvokingVertexHelper.generateIndexBuffer(
|
||||
mtl::BufferRef drawIdxBuffer;
|
||||
ANGLE_TRY(mProvokingVertexHelper.generateIndexBuffer(
|
||||
mtl::GetImpl(context), first, count, mode, convertedType, outIndexCount, outIndexOffset,
|
||||
outIndexMode);
|
||||
outIndexMode, drawIdxBuffer));
|
||||
GLsizei outIndexCounti32 = static_cast<GLsizei>(outIndexCount);
|
||||
const uint8_t *mappedIndices = drawIdxBuffer->mapReadOnly(this);
|
||||
if (!drawIdxBuffer || !mappedIndices)
|
||||
if (!mappedIndices)
|
||||
{
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
@@ -804,14 +805,10 @@ angle::Result ContextMtl::drawElementsImpl(const gl::Context *context,
|
||||
{
|
||||
size_t outIndexCount = 0;
|
||||
gl::PrimitiveMode newMode = gl::PrimitiveMode::InvalidEnum;
|
||||
drawIdxBuffer = mProvokingVertexHelper.preconditionIndexBuffer(
|
||||
ANGLE_TRY(mProvokingVertexHelper.preconditionIndexBuffer(
|
||||
mtl::GetImpl(context), idxBuffer, count, convertedOffset,
|
||||
mState.isPrimitiveRestartEnabled(), mode, convertedType, outIndexCount,
|
||||
provokingVertexAdditionalOffset, newMode);
|
||||
if (!drawIdxBuffer)
|
||||
{
|
||||
return angle::Result::Stop;
|
||||
}
|
||||
provokingVertexAdditionalOffset, newMode, drawIdxBuffer));
|
||||
// Line strips and triangle strips are rewritten to flat line arrays and tri arrays.
|
||||
convertedCounti32 = (uint32_t)outIndexCount;
|
||||
mode = newMode;
|
||||
|
||||
@@ -22,29 +22,31 @@ namespace rx
|
||||
{
|
||||
class ContextMtl;
|
||||
|
||||
class ProvokingVertexHelper : public mtl::ProvokingVertexCacheSpecializeShaderFactory
|
||||
class ProvokingVertexHelper : angle::NonCopyable
|
||||
{
|
||||
public:
|
||||
ProvokingVertexHelper(ContextMtl *context);
|
||||
mtl::BufferRef preconditionIndexBuffer(ContextMtl *context,
|
||||
mtl::BufferRef indexBuffer,
|
||||
size_t indexCount,
|
||||
size_t indexOffset,
|
||||
bool primitiveRestartEnabled,
|
||||
gl::PrimitiveMode primitiveMode,
|
||||
gl::DrawElementsType elementsType,
|
||||
size_t &outIndexCount,
|
||||
size_t &outIndexOffset,
|
||||
gl::PrimitiveMode &outPrimitiveMode);
|
||||
angle::Result preconditionIndexBuffer(ContextMtl *context,
|
||||
mtl::BufferRef indexBuffer,
|
||||
size_t indexCount,
|
||||
size_t indexOffset,
|
||||
bool primitiveRestartEnabled,
|
||||
gl::PrimitiveMode primitiveMode,
|
||||
gl::DrawElementsType elementsType,
|
||||
size_t &outIndexCount,
|
||||
size_t &outIndexOffset,
|
||||
gl::PrimitiveMode &outPrimitiveMode,
|
||||
mtl::BufferRef &outNewBuffer);
|
||||
|
||||
mtl::BufferRef generateIndexBuffer(ContextMtl *context,
|
||||
size_t first,
|
||||
size_t indexCount,
|
||||
gl::PrimitiveMode primitiveMode,
|
||||
gl::DrawElementsType elementsType,
|
||||
size_t &outIndexCount,
|
||||
size_t &outIndexOffset,
|
||||
gl::PrimitiveMode &outPrimitiveMode);
|
||||
angle::Result generateIndexBuffer(ContextMtl *context,
|
||||
size_t first,
|
||||
size_t indexCount,
|
||||
gl::PrimitiveMode primitiveMode,
|
||||
gl::DrawElementsType elementsType,
|
||||
size_t &outIndexCount,
|
||||
size_t &outIndexOffset,
|
||||
gl::PrimitiveMode &outPrimitiveMode,
|
||||
mtl::BufferRef &outNewBuffer);
|
||||
|
||||
void releaseInFlightBuffers(ContextMtl *contextMtl);
|
||||
void ensureCommandBufferReady();
|
||||
@@ -52,24 +54,19 @@ class ProvokingVertexHelper : public mtl::ProvokingVertexCacheSpecializeShaderFa
|
||||
mtl::ComputeCommandEncoder *getComputeCommandEncoder();
|
||||
|
||||
private:
|
||||
angle::Result getComputePipleineState(
|
||||
ContextMtl *context,
|
||||
const mtl::ProvokingVertexComputePipelineDesc &desc,
|
||||
mtl::AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
|
||||
|
||||
angle::Result prepareCommandEncoderForDescriptor(ContextMtl *context,
|
||||
mtl::ComputeCommandEncoder *encoder,
|
||||
mtl::ProvokingVertexComputePipelineDesc desc);
|
||||
|
||||
mtl::BufferPool mIndexBuffers;
|
||||
mtl::ProvokingVertexComputePipelineCache mPipelineCache;
|
||||
mtl::ProvokingVertexComputePipelineDesc mCachedDesc;
|
||||
|
||||
// Program cache
|
||||
virtual angle::Result getSpecializedShader(
|
||||
rx::mtl::Context *context,
|
||||
gl::ShaderType shaderType,
|
||||
const mtl::ProvokingVertexComputePipelineDesc &renderPipelineDesc,
|
||||
id<MTLFunction> *shaderOut) override;
|
||||
// Private command buffer
|
||||
virtual bool hasSpecializedShader(
|
||||
gl::ShaderType shaderType,
|
||||
const mtl::ProvokingVertexComputePipelineDesc &renderPipelineDesc) override;
|
||||
|
||||
void prepareCommandEncoderForDescriptor(ContextMtl *context,
|
||||
mtl::ComputeCommandEncoder *encoder,
|
||||
mtl::ProvokingVertexComputePipelineDesc desc);
|
||||
std::unordered_map<mtl::ProvokingVertexComputePipelineDesc, mtl::AutoObjCPtr<id<MTLFunction>>>
|
||||
mComputeFunctions;
|
||||
};
|
||||
} // namespace rx
|
||||
#endif /* LIBANGLE_RENDERER_METAL_PROVOKINGVERTEXHELPER_H */
|
||||
|
||||
@@ -99,8 +99,7 @@ static inline gl::PrimitiveMode getNewPrimitiveMode(const uint fixIndexBufferKey
|
||||
return gl::PrimitiveMode::InvalidEnum;
|
||||
}
|
||||
}
|
||||
ProvokingVertexHelper::ProvokingVertexHelper(ContextMtl *context)
|
||||
: mIndexBuffers(false), mPipelineCache(this)
|
||||
ProvokingVertexHelper::ProvokingVertexHelper(ContextMtl *context) : mIndexBuffers(false)
|
||||
{
|
||||
mIndexBuffers.initialize(context, kInitialIndexBufferSize, mtl::kIndexBufferOffsetAlignment, 0);
|
||||
}
|
||||
@@ -108,7 +107,6 @@ ProvokingVertexHelper::ProvokingVertexHelper(ContextMtl *context)
|
||||
void ProvokingVertexHelper::onDestroy(ContextMtl *context)
|
||||
{
|
||||
mIndexBuffers.destroy(context);
|
||||
mPipelineCache.clear();
|
||||
}
|
||||
|
||||
void ProvokingVertexHelper::releaseInFlightBuffers(ContextMtl *contextMtl)
|
||||
@@ -143,55 +141,64 @@ static uint buildIndexBufferKey(const mtl::ProvokingVertexComputePipelineDesc &p
|
||||
return indexBufferKey;
|
||||
}
|
||||
|
||||
bool ProvokingVertexHelper::hasSpecializedShader(
|
||||
gl::ShaderType shaderType,
|
||||
const mtl::ProvokingVertexComputePipelineDesc &renderPipelineDesc)
|
||||
angle::Result ProvokingVertexHelper::getComputePipleineState(
|
||||
ContextMtl *context,
|
||||
const mtl::ProvokingVertexComputePipelineDesc &desc,
|
||||
mtl::AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
auto iter = mComputeFunctions.find(desc);
|
||||
if (iter != mComputeFunctions.end())
|
||||
{
|
||||
return context->getPipelineCache().getComputePipeline(context, iter->second,
|
||||
outComputePipeline);
|
||||
}
|
||||
|
||||
angle::Result ProvokingVertexHelper::getSpecializedShader(
|
||||
rx::mtl::Context *context,
|
||||
gl::ShaderType shaderType,
|
||||
const mtl::ProvokingVertexComputePipelineDesc &pipelineDesc,
|
||||
id<MTLFunction> *shaderOut)
|
||||
{
|
||||
id<MTLLibrary> provokingVertexLibrary = context->getDisplay()->getDefaultShadersLib();
|
||||
uint indexBufferKey = buildIndexBufferKey(pipelineDesc);
|
||||
uint indexBufferKey = buildIndexBufferKey(desc);
|
||||
auto fcValues = mtl::adoptObjCObj([[MTLFunctionConstantValues alloc] init]);
|
||||
[fcValues setConstantValue:&indexBufferKey type:MTLDataTypeUInt withName:@"fixIndexBufferKey"];
|
||||
if (pipelineDesc.generateIndices)
|
||||
|
||||
mtl::AutoObjCPtr<id<MTLFunction>> computeShader;
|
||||
if (desc.generateIndices)
|
||||
{
|
||||
return CreateMslShader(context, provokingVertexLibrary, @"genIndexBuffer", fcValues.get(),
|
||||
shaderOut);
|
||||
ANGLE_TRY(CreateMslShader(context, provokingVertexLibrary, @"genIndexBuffer",
|
||||
fcValues.get(), &computeShader));
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateMslShader(context, provokingVertexLibrary, @"fixIndexBuffer", fcValues.get(),
|
||||
shaderOut);
|
||||
ANGLE_TRY(CreateMslShader(context, provokingVertexLibrary, @"fixIndexBuffer",
|
||||
fcValues.get(), &computeShader));
|
||||
}
|
||||
mComputeFunctions[desc] = computeShader;
|
||||
|
||||
return context->getPipelineCache().getComputePipeline(context, computeShader,
|
||||
outComputePipeline);
|
||||
}
|
||||
|
||||
void ProvokingVertexHelper::prepareCommandEncoderForDescriptor(
|
||||
angle::Result ProvokingVertexHelper::prepareCommandEncoderForDescriptor(
|
||||
ContextMtl *context,
|
||||
mtl::ComputeCommandEncoder *encoder,
|
||||
mtl::ProvokingVertexComputePipelineDesc desc)
|
||||
{
|
||||
auto pipelineState = mPipelineCache.getComputePipelineState(context, desc);
|
||||
mtl::AutoObjCPtr<id<MTLComputePipelineState>> pipelineState;
|
||||
ANGLE_TRY(getComputePipleineState(context, desc, &pipelineState));
|
||||
|
||||
encoder->setComputePipelineState(pipelineState);
|
||||
mCachedDesc = desc;
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
mtl::BufferRef ProvokingVertexHelper::preconditionIndexBuffer(ContextMtl *context,
|
||||
mtl::BufferRef indexBuffer,
|
||||
size_t indexCount,
|
||||
size_t indexOffset,
|
||||
bool primitiveRestartEnabled,
|
||||
gl::PrimitiveMode primitiveMode,
|
||||
gl::DrawElementsType elementsType,
|
||||
size_t &outIndexCount,
|
||||
size_t &outIndexOffset,
|
||||
gl::PrimitiveMode &outPrimitiveMode)
|
||||
|
||||
angle::Result ProvokingVertexHelper::preconditionIndexBuffer(ContextMtl *context,
|
||||
mtl::BufferRef indexBuffer,
|
||||
size_t indexCount,
|
||||
size_t indexOffset,
|
||||
bool primitiveRestartEnabled,
|
||||
gl::PrimitiveMode primitiveMode,
|
||||
gl::DrawElementsType elementsType,
|
||||
size_t &outIndexCount,
|
||||
size_t &outIndexOffset,
|
||||
gl::PrimitiveMode &outPrimitiveMode,
|
||||
mtl::BufferRef &outNewBuffer)
|
||||
{
|
||||
// Get specialized program
|
||||
// Upload index buffer
|
||||
@@ -207,17 +214,14 @@ mtl::BufferRef ProvokingVertexHelper::preconditionIndexBuffer(ContextMtl *contex
|
||||
size_t indexSize = gl::GetDrawElementsTypeSize(elementsType);
|
||||
size_t newOffset = 0;
|
||||
mtl::BufferRef newBuffer;
|
||||
if (mIndexBuffers.allocate(context, newIndexCount * indexSize + indexOffset, nullptr,
|
||||
&newBuffer, &newOffset) == angle::Result::Stop)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
ANGLE_TRY(mIndexBuffers.allocate(context, newIndexCount * indexSize + indexOffset, nullptr,
|
||||
&newBuffer, &newOffset));
|
||||
uint indexCountEncoded = (uint)indexCount;
|
||||
auto threadsPerThreadgroup = MTLSizeMake(MIN(primCount, 64u), 1, 1);
|
||||
|
||||
mtl::ComputeCommandEncoder *encoder =
|
||||
context->getComputeCommandEncoderWithoutEndingRenderEncoder();
|
||||
prepareCommandEncoderForDescriptor(context, encoder, pipelineDesc);
|
||||
ANGLE_TRY(prepareCommandEncoderForDescriptor(context, encoder, pipelineDesc));
|
||||
encoder->setBuffer(indexBuffer, static_cast<uint32_t>(indexOffset), 0);
|
||||
encoder->setBufferForWrite(
|
||||
newBuffer, static_cast<uint32_t>(indexOffset) + static_cast<uint32_t>(newOffset), 1);
|
||||
@@ -230,17 +234,19 @@ mtl::BufferRef ProvokingVertexHelper::preconditionIndexBuffer(ContextMtl *contex
|
||||
outIndexCount = newIndexCount;
|
||||
outIndexOffset = newOffset;
|
||||
outPrimitiveMode = getNewPrimitiveMode(indexBufferKey);
|
||||
return newBuffer;
|
||||
outNewBuffer = newBuffer;
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
mtl::BufferRef ProvokingVertexHelper::generateIndexBuffer(ContextMtl *context,
|
||||
size_t first,
|
||||
size_t indexCount,
|
||||
gl::PrimitiveMode primitiveMode,
|
||||
gl::DrawElementsType elementsType,
|
||||
size_t &outIndexCount,
|
||||
size_t &outIndexOffset,
|
||||
gl::PrimitiveMode &outPrimitiveMode)
|
||||
angle::Result ProvokingVertexHelper::generateIndexBuffer(ContextMtl *context,
|
||||
size_t first,
|
||||
size_t indexCount,
|
||||
gl::PrimitiveMode primitiveMode,
|
||||
gl::DrawElementsType elementsType,
|
||||
size_t &outIndexCount,
|
||||
size_t &outIndexOffset,
|
||||
gl::PrimitiveMode &outPrimitiveMode,
|
||||
mtl::BufferRef &outNewBuffer)
|
||||
{
|
||||
// Get specialized program
|
||||
// Upload index buffer
|
||||
@@ -256,11 +262,8 @@ mtl::BufferRef ProvokingVertexHelper::generateIndexBuffer(ContextMtl *context,
|
||||
size_t indexSize = gl::GetDrawElementsTypeSize(elementsType);
|
||||
size_t newIndexOffset = 0;
|
||||
mtl::BufferRef newBuffer;
|
||||
if (mIndexBuffers.allocate(context, newIndexCount * indexSize, nullptr, &newBuffer,
|
||||
&newIndexOffset) == angle::Result::Stop)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
ANGLE_TRY(mIndexBuffers.allocate(context, newIndexCount * indexSize, nullptr, &newBuffer,
|
||||
&newIndexOffset));
|
||||
uint indexCountEncoded = static_cast<uint>(indexCount);
|
||||
uint firstVertexEncoded = static_cast<uint>(first);
|
||||
uint indexOffsetEncoded = static_cast<uint>(newIndexOffset);
|
||||
@@ -268,7 +271,7 @@ mtl::BufferRef ProvokingVertexHelper::generateIndexBuffer(ContextMtl *context,
|
||||
|
||||
mtl::ComputeCommandEncoder *encoder =
|
||||
context->getComputeCommandEncoderWithoutEndingRenderEncoder();
|
||||
prepareCommandEncoderForDescriptor(context, encoder, pipelineDesc);
|
||||
ANGLE_TRY(prepareCommandEncoderForDescriptor(context, encoder, pipelineDesc));
|
||||
encoder->setBufferForWrite(newBuffer, indexOffsetEncoded, 1);
|
||||
encoder->setData(indexCountEncoded, 2);
|
||||
encoder->setData(primCount, 3);
|
||||
@@ -280,7 +283,8 @@ mtl::BufferRef ProvokingVertexHelper::generateIndexBuffer(ContextMtl *context,
|
||||
outIndexCount = newIndexCount;
|
||||
outIndexOffset = newIndexOffset;
|
||||
outPrimitiveMode = getNewPrimitiveMode(indexBufferKey);
|
||||
return newBuffer;
|
||||
outNewBuffer = newBuffer;
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
} // namespace rx
|
||||
|
||||
@@ -298,7 +298,7 @@ struct alignas(4) ProvokingVertexComputePipelineDesc
|
||||
{
|
||||
ProvokingVertexComputePipelineDesc();
|
||||
ProvokingVertexComputePipelineDesc(const ProvokingVertexComputePipelineDesc &src);
|
||||
ProvokingVertexComputePipelineDesc(const ProvokingVertexComputePipelineDesc &&src);
|
||||
ProvokingVertexComputePipelineDesc(ProvokingVertexComputePipelineDesc &&src);
|
||||
|
||||
ProvokingVertexComputePipelineDesc &operator=(const ProvokingVertexComputePipelineDesc &src);
|
||||
|
||||
@@ -451,72 +451,6 @@ namespace rx
|
||||
namespace mtl
|
||||
{
|
||||
|
||||
// Abstract factory to create specialized provoking vertex compute shaders based off of
|
||||
// compute shader pipeline descs
|
||||
|
||||
class ProvokingVertexCacheSpecializeShaderFactory
|
||||
{
|
||||
public:
|
||||
virtual ~ProvokingVertexCacheSpecializeShaderFactory() = default;
|
||||
// Get specialized shader for the render pipeline cache.
|
||||
virtual angle::Result getSpecializedShader(
|
||||
Context *context,
|
||||
gl::ShaderType shaderType,
|
||||
const ProvokingVertexComputePipelineDesc &renderPipelineDesc,
|
||||
id<MTLFunction> *shaderOut) = 0;
|
||||
// Check whether specialized shaders is required for the specified RenderPipelineDesc.
|
||||
// If not, the render pipeline cache will use the supplied non-specialized shaders.
|
||||
virtual bool hasSpecializedShader(
|
||||
gl::ShaderType shaderType,
|
||||
const ProvokingVertexComputePipelineDesc &renderPipelineDesc) = 0;
|
||||
};
|
||||
|
||||
// render pipeline state cache per shader program
|
||||
class ProvokingVertexComputePipelineCache final : angle::NonCopyable
|
||||
{
|
||||
public:
|
||||
ProvokingVertexComputePipelineCache();
|
||||
ProvokingVertexComputePipelineCache(
|
||||
ProvokingVertexCacheSpecializeShaderFactory *specializedShaderFactory);
|
||||
~ProvokingVertexComputePipelineCache();
|
||||
|
||||
// Set non-specialized vertex/fragment shader to be used by render pipeline cache to create
|
||||
// render pipeline state. If the internal
|
||||
// RenderPipelineCacheSpecializeShaderFactory.hasSpecializedShader() returns false for a
|
||||
// particular RenderPipelineDesc, the render pipeline cache will use the non-specialized
|
||||
// shaders.
|
||||
void setComputeShader(ContextMtl *context, id<MTLFunction> shader);
|
||||
id<MTLFunction> getComputeShader() { return mComputeShader; }
|
||||
|
||||
AutoObjCPtr<id<MTLComputePipelineState>> getComputePipelineState(
|
||||
ContextMtl *context,
|
||||
const ProvokingVertexComputePipelineDesc &desc);
|
||||
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
// Non-specialized compute shader
|
||||
AutoObjCPtr<id<MTLFunction>> mComputeShader;
|
||||
|
||||
private:
|
||||
void clearPipelineStates();
|
||||
void recreatePipelineStates(ContextMtl *context);
|
||||
AutoObjCPtr<id<MTLComputePipelineState>> insertComputePipelineState(
|
||||
ContextMtl *context,
|
||||
const ProvokingVertexComputePipelineDesc &desc);
|
||||
|
||||
AutoObjCPtr<id<MTLComputePipelineState>> createComputePipelineState(
|
||||
ContextMtl *context,
|
||||
const ProvokingVertexComputePipelineDesc &desc);
|
||||
|
||||
bool hasDefaultAttribs(const RenderPipelineDesc &desc) const;
|
||||
|
||||
// One table with default attrib and one table without.
|
||||
std::unordered_map<ProvokingVertexComputePipelineDesc, AutoObjCPtr<id<MTLComputePipelineState>>>
|
||||
mComputePipelineStates;
|
||||
ProvokingVertexCacheSpecializeShaderFactory *mSpecializedShaderFactory;
|
||||
};
|
||||
|
||||
class StateCache final : angle::NonCopyable
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -873,7 +873,7 @@ ProvokingVertexComputePipelineDesc::ProvokingVertexComputePipelineDesc(
|
||||
memcpy(this, &src, sizeof(*this));
|
||||
}
|
||||
ProvokingVertexComputePipelineDesc::ProvokingVertexComputePipelineDesc(
|
||||
const ProvokingVertexComputePipelineDesc &&src)
|
||||
ProvokingVertexComputePipelineDesc &&src)
|
||||
{
|
||||
memcpy(this, &src, sizeof(*this));
|
||||
}
|
||||
@@ -898,135 +898,6 @@ size_t ProvokingVertexComputePipelineDesc::hash() const
|
||||
return angle::ComputeGenericHash(*this);
|
||||
}
|
||||
|
||||
ProvokingVertexComputePipelineCache::ProvokingVertexComputePipelineCache() : mComputeShader(nullptr)
|
||||
{}
|
||||
|
||||
ProvokingVertexComputePipelineCache::ProvokingVertexComputePipelineCache(
|
||||
ProvokingVertexCacheSpecializeShaderFactory *specializedShaderFactory)
|
||||
: mComputeShader(nullptr), mSpecializedShaderFactory(specializedShaderFactory)
|
||||
{}
|
||||
|
||||
void ProvokingVertexComputePipelineCache::setComputeShader(ContextMtl *context,
|
||||
id<MTLFunction> shader)
|
||||
{
|
||||
mComputeShader.retainAssign(shader);
|
||||
if (!shader)
|
||||
{
|
||||
clearPipelineStates();
|
||||
return;
|
||||
}
|
||||
|
||||
recreatePipelineStates(context);
|
||||
}
|
||||
|
||||
void ProvokingVertexComputePipelineCache::clearPipelineStates()
|
||||
{
|
||||
mComputePipelineStates.clear();
|
||||
}
|
||||
|
||||
void ProvokingVertexComputePipelineCache::clear()
|
||||
{
|
||||
clearPipelineStates();
|
||||
}
|
||||
|
||||
AutoObjCPtr<id<MTLComputePipelineState>>
|
||||
ProvokingVertexComputePipelineCache::getComputePipelineState(
|
||||
ContextMtl *context,
|
||||
const ProvokingVertexComputePipelineDesc &desc)
|
||||
{
|
||||
auto &table = mComputePipelineStates;
|
||||
auto ite = table.find(desc);
|
||||
if (ite == table.end())
|
||||
{
|
||||
return insertComputePipelineState(context, desc);
|
||||
}
|
||||
|
||||
return ite->second;
|
||||
}
|
||||
|
||||
AutoObjCPtr<id<MTLComputePipelineState>>
|
||||
ProvokingVertexComputePipelineCache::insertComputePipelineState(
|
||||
ContextMtl *context,
|
||||
const ProvokingVertexComputePipelineDesc &desc)
|
||||
{
|
||||
AutoObjCPtr<id<MTLComputePipelineState>> newState = createComputePipelineState(context, desc);
|
||||
|
||||
auto re = mComputePipelineStates.insert(std::make_pair(desc, newState));
|
||||
if (!re.second)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return re.first->second;
|
||||
}
|
||||
|
||||
void ProvokingVertexComputePipelineCache::recreatePipelineStates(ContextMtl *context)
|
||||
{
|
||||
|
||||
for (auto &ite : mComputePipelineStates)
|
||||
{
|
||||
if (ite.second == nil)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ite.second = createComputePipelineState(context, ite.first);
|
||||
}
|
||||
}
|
||||
|
||||
AutoObjCPtr<id<MTLComputePipelineState>>
|
||||
ProvokingVertexComputePipelineCache::createComputePipelineState(
|
||||
ContextMtl *context,
|
||||
const ProvokingVertexComputePipelineDesc &originalDesc)
|
||||
{
|
||||
ANGLE_MTL_OBJC_SCOPE
|
||||
{
|
||||
// Disable coverage if the render pipeline's sample count is only 1.
|
||||
ProvokingVertexComputePipelineDesc desc = originalDesc;
|
||||
|
||||
id<MTLFunction> computeFunction = nil;
|
||||
// Special case for transform feedback shader, we've already created it! See
|
||||
// getTransformFeedbackRenderPipeline
|
||||
if (mSpecializedShaderFactory &&
|
||||
mSpecializedShaderFactory->hasSpecializedShader(gl::ShaderType::Compute, desc))
|
||||
{
|
||||
if (IsError(mSpecializedShaderFactory->getSpecializedShader(
|
||||
context, gl::ShaderType::Compute, desc, &computeFunction)))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-specialized version
|
||||
computeFunction = mComputeShader;
|
||||
}
|
||||
|
||||
if (!computeFunction)
|
||||
{
|
||||
ANGLE_MTL_HANDLE_ERROR(context, "Render pipeline without vertex shader is invalid.",
|
||||
GL_INVALID_OPERATION);
|
||||
return nil;
|
||||
}
|
||||
|
||||
const mtl::ContextDevice &metalDevice = context->getMetalDevice();
|
||||
|
||||
// Convert to Objective-C desc:
|
||||
NSError *err = nil;
|
||||
auto newState = metalDevice.newComputePipelineStateWithFunction(computeFunction, &err);
|
||||
if (err)
|
||||
{
|
||||
ANGLE_MTL_HANDLE_ERROR(context, mtl::FormatMetalErrorMessage(err).c_str(),
|
||||
GL_INVALID_OPERATION);
|
||||
return nil;
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
}
|
||||
|
||||
ProvokingVertexComputePipelineCache::~ProvokingVertexComputePipelineCache() {}
|
||||
|
||||
// StateCache implementation
|
||||
StateCache::StateCache(const angle::FeaturesMtl &features) : mFeatures(features) {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user