Metal lambda sync

This commit is contained in:
Jack Andersen 2016-03-30 11:07:12 -10:00
parent ecc65a9fd5
commit 679ba36c4c
2 changed files with 114 additions and 101 deletions

View File

@ -38,37 +38,44 @@ public:
Platform platform() const {return Platform::Metal;} Platform platform() const {return Platform::Metal;}
const char* platformName() const {return "Metal";} const char* platformName() const {return "Metal";}
IGraphicsBufferS* newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count); class Context : public IGraphicsDataFactory::Context
IGraphicsBufferD* newDynamicBuffer(BufferUse use, size_t stride, size_t count); {
friend class MetalDataFactory;
MetalDataFactory& m_parent;
Context(MetalDataFactory& parent) : m_parent(parent) {}
public:
Platform platform() const {return Platform::Metal;}
const char* platformName() const {return "Metal";}
ITextureS* newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, IGraphicsBufferS* newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
const void* data, size_t sz); IGraphicsBufferD* newDynamicBuffer(BufferUse use, size_t stride, size_t count);
GraphicsDataToken
newStaticTextureNoContext(size_t width, size_t height, size_t mips, TextureFormat fmt,
const void* data, size_t sz, ITextureS*& texOut);
ITextureSA* newStaticArrayTexture(size_t width, size_t height, size_t layers, TextureFormat fmt,
const void* data, size_t sz);
ITextureD* newDynamicTexture(size_t width, size_t height, TextureFormat fmt);
ITextureR* newRenderTexture(size_t width, size_t height,
bool enableShaderColorBinding, bool enableShaderDepthBinding);
bool bindingNeedsVertexFormat() const {return false;} ITextureS* newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements); const void* data, size_t sz);
ITextureSA* newStaticArrayTexture(size_t width, size_t height, size_t layers, TextureFormat fmt,
const void* data, size_t sz);
ITextureD* newDynamicTexture(size_t width, size_t height, TextureFormat fmt);
ITextureR* newRenderTexture(size_t width, size_t height,
bool enableShaderColorBinding, bool enableShaderDepthBinding);
IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource, bool bindingNeedsVertexFormat() const {return false;}
IVertexFormat* vtxFmt, unsigned targetSamples, IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements);
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, bool backfaceCulling);
IShaderDataBinding* IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource,
newShaderDataBinding(IShaderPipeline* pipeline, IVertexFormat* vtxFmt, unsigned targetSamples,
IVertexFormat* vtxFormat, BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo, bool depthTest, bool depthWrite, bool backfaceCulling);
size_t ubufCount, IGraphicsBuffer** ubufs,
size_t texCount, ITexture** texs);
void reset(); IShaderDataBinding*
GraphicsDataToken commit(); newShaderDataBinding(IShaderPipeline* pipeline,
IVertexFormat* vtxFormat,
IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo,
size_t ubufCount, IGraphicsBuffer** ubufs,
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs);
};
virtual GraphicsDataToken commitTransaction(const std::function<bool(IGraphicsDataFactory::Context& ctx)>&);
}; };
} }

View File

@ -528,12 +528,14 @@ struct MetalShaderDataBinding : IShaderDataBinding
IGraphicsBuffer* m_ibuf; IGraphicsBuffer* m_ibuf;
size_t m_ubufCount; size_t m_ubufCount;
std::unique_ptr<IGraphicsBuffer*[]> m_ubufs; std::unique_ptr<IGraphicsBuffer*[]> m_ubufs;
std::vector<size_t> m_ubufOffs;
size_t m_texCount; size_t m_texCount;
std::unique_ptr<ITexture*[]> m_texs; std::unique_ptr<ITexture*[]> m_texs;
MetalShaderDataBinding(MetalContext* ctx, MetalShaderDataBinding(MetalContext* ctx,
IShaderPipeline* pipeline, IShaderPipeline* pipeline,
IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf, IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf,
size_t ubufCount, IGraphicsBuffer** ubufs, size_t ubufCount, IGraphicsBuffer** ubufs,
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs) size_t texCount, ITexture** texs)
: m_pipeline(static_cast<MetalShaderPipeline*>(pipeline)), : m_pipeline(static_cast<MetalShaderPipeline*>(pipeline)),
m_vbuf(vbuf), m_vbuf(vbuf),
@ -544,10 +546,34 @@ struct MetalShaderDataBinding : IShaderDataBinding
m_texCount(texCount), m_texCount(texCount),
m_texs(new ITexture*[texCount]) m_texs(new ITexture*[texCount])
{ {
if (ubufOffs && ubufSizes)
{
m_ubufOffs.reserve(ubufCount);
for (size_t i=0 ; i<ubufCount ; ++i)
{
#ifndef NDEBUG
if (ubufOffs[i] % 256)
Log.report(logvisor::Fatal, "non-256-byte-aligned uniform-offset %d provided to newShaderDataBinding", int(i));
#endif
m_ubufOffs.push_back(ubufOffs[i]);
}
}
for (size_t i=0 ; i<ubufCount ; ++i) for (size_t i=0 ; i<ubufCount ; ++i)
{
#ifndef NDEBUG
if (!ubufs[i])
Log.report(logvisor::Fatal, "null uniform-buffer %d provided to newShaderDataBinding", int(i));
#endif
m_ubufs[i] = ubufs[i]; m_ubufs[i] = ubufs[i];
}
for (size_t i=0 ; i<texCount ; ++i) for (size_t i=0 ; i<texCount ; ++i)
{
#ifndef NDEBUG
if (!texs[i])
Log.report(logvisor::Fatal, "null texture %d provided to newShaderDataBinding", int(i));
#endif
m_texs[i] = texs[i]; m_texs[i] = texs[i];
}
} }
void bind(id<MTLRenderCommandEncoder> enc, int b) void bind(id<MTLRenderCommandEncoder> enc, int b)
@ -557,8 +583,12 @@ struct MetalShaderDataBinding : IShaderDataBinding
[enc setVertexBuffer:GetBufferGPUResource(m_vbuf, b) offset:0 atIndex:0]; [enc setVertexBuffer:GetBufferGPUResource(m_vbuf, b) offset:0 atIndex:0];
if (m_instVbo) if (m_instVbo)
[enc setVertexBuffer:GetBufferGPUResource(m_instVbo, b) offset:0 atIndex:1]; [enc setVertexBuffer:GetBufferGPUResource(m_instVbo, b) offset:0 atIndex:1];
for (size_t i=0 ; i<m_ubufCount ; ++i) if (m_ubufOffs.size())
[enc setVertexBuffer:GetBufferGPUResource(m_ubufs[i], b) offset:0 atIndex:i+2]; for (size_t i=0 ; i<m_ubufCount ; ++i)
[enc setVertexBuffer:GetBufferGPUResource(m_ubufs[i], b) offset:m_ubufOffs[i] atIndex:i+2];
else
for (size_t i=0 ; i<m_ubufCount ; ++i)
[enc setVertexBuffer:GetBufferGPUResource(m_ubufs[i], b) offset:0 atIndex:i+2];
for (size_t i=0 ; i<m_texCount ; ++i) for (size_t i=0 ; i<m_texCount ; ++i)
[enc setFragmentTexture:GetTextureGPUResource(m_texs[i], b) atIndex:i]; [enc setFragmentTexture:GetTextureGPUResource(m_texs[i], b) atIndex:i];
} }
@ -883,139 +913,115 @@ void MetalTextureD::unmap()
MetalDataFactory::MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx, uint32_t sampleCount) MetalDataFactory::MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx, uint32_t sampleCount)
: m_parent(parent), m_ctx(ctx), m_sampleCount(sampleCount) {} : m_parent(parent), m_ctx(ctx), m_sampleCount(sampleCount) {}
IGraphicsBufferS* MetalDataFactory::newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count) IGraphicsBufferS* MetalDataFactory::Context::newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count)
{ {
MetalGraphicsBufferS* retval = new MetalGraphicsBufferS(use, m_ctx, data, stride, count); MetalGraphicsBufferS* retval = new MetalGraphicsBufferS(use, m_parent.m_ctx, data, stride, count);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
m_deferredData->m_SBufs.emplace_back(retval); m_deferredData->m_SBufs.emplace_back(retval);
return retval; return retval;
} }
IGraphicsBufferD* MetalDataFactory::newDynamicBuffer(BufferUse use, size_t stride, size_t count) IGraphicsBufferD* MetalDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, size_t count)
{ {
MetalCommandQueue* q = static_cast<MetalCommandQueue*>(m_parent->getCommandQueue()); MetalCommandQueue* q = static_cast<MetalCommandQueue*>(m_parent.m_parent->getCommandQueue());
MetalGraphicsBufferD* retval = new MetalGraphicsBufferD(q, use, m_ctx, stride, count); MetalGraphicsBufferD* retval = new MetalGraphicsBufferD(q, use, m_parent.m_ctx, stride, count);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
m_deferredData->m_DBufs.emplace_back(retval); m_deferredData->m_DBufs.emplace_back(retval);
return retval; return retval;
} }
ITextureS* MetalDataFactory::newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, ITextureS* MetalDataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
const void* data, size_t sz) const void* data, size_t sz)
{ {
MetalTextureS* retval = new MetalTextureS(m_ctx, width, height, mips, fmt, data, sz); MetalTextureS* retval = new MetalTextureS(m_parent.m_ctx, width, height, mips, fmt, data, sz);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
m_deferredData->m_STexs.emplace_back(retval); m_deferredData->m_STexs.emplace_back(retval);
return retval; return retval;
} }
GraphicsDataToken ITextureSA* MetalDataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_t layers, TextureFormat fmt,
MetalDataFactory::newStaticTextureNoContext(size_t width, size_t height, size_t mips, TextureFormat fmt, const void* data, size_t sz)
const void* data, size_t sz, ITextureS*& texOut)
{ {
MetalTextureS* retval = new MetalTextureS(m_ctx, width, height, mips, fmt, data, sz); MetalTextureSA* retval = new MetalTextureSA(m_parent.m_ctx, width, height, layers, fmt, data, sz);
MetalData* tokData = new struct MetalData();
tokData->m_STexs.emplace_back(retval);
texOut = retval;
std::unique_lock<std::mutex> lk(m_committedMutex);
m_committedData.insert(tokData);
return GraphicsDataToken(this, tokData);
}
ITextureSA* MetalDataFactory::newStaticArrayTexture(size_t width, size_t height, size_t layers, TextureFormat fmt,
const void* data, size_t sz)
{
MetalTextureSA* retval = new MetalTextureSA(m_ctx, width, height, layers, fmt, data, sz);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
m_deferredData->m_SATexs.emplace_back(retval); m_deferredData->m_SATexs.emplace_back(retval);
return retval; return retval;
} }
ITextureD* MetalDataFactory::newDynamicTexture(size_t width, size_t height, TextureFormat fmt) ITextureD* MetalDataFactory::Context::newDynamicTexture(size_t width, size_t height, TextureFormat fmt)
{ {
MetalCommandQueue* q = static_cast<MetalCommandQueue*>(m_parent->getCommandQueue()); MetalCommandQueue* q = static_cast<MetalCommandQueue*>(m_parent.m_parent->getCommandQueue());
MetalTextureD* retval = new MetalTextureD(q, m_ctx, width, height, fmt); MetalTextureD* retval = new MetalTextureD(q, m_parent.m_ctx, width, height, fmt);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
m_deferredData->m_DTexs.emplace_back(retval); m_deferredData->m_DTexs.emplace_back(retval);
return retval; return retval;
} }
ITextureR* MetalDataFactory::newRenderTexture(size_t width, size_t height, ITextureR* MetalDataFactory::Context::newRenderTexture(size_t width, size_t height,
bool enableShaderColorBinding, bool enableShaderDepthBinding) bool enableShaderColorBinding, bool enableShaderDepthBinding)
{ {
MetalTextureR* retval = new MetalTextureR(m_ctx, width, height, m_sampleCount, enableShaderColorBinding); MetalTextureR* retval = new MetalTextureR(m_parent.m_ctx, width, height, m_parent.m_sampleCount, enableShaderColorBinding);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
m_deferredData->m_RTexs.emplace_back(retval); m_deferredData->m_RTexs.emplace_back(retval);
return retval; return retval;
} }
IVertexFormat* MetalDataFactory::newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements) IVertexFormat* MetalDataFactory::Context::newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements)
{ {
MetalVertexFormat* retval = new struct MetalVertexFormat(elementCount, elements); MetalVertexFormat* retval = new struct MetalVertexFormat(elementCount, elements);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
m_deferredData->m_VFmts.emplace_back(retval); m_deferredData->m_VFmts.emplace_back(retval);
return retval; return retval;
} }
IShaderPipeline* MetalDataFactory::newShaderPipeline(const char* vertSource, const char* fragSource, IShaderPipeline* MetalDataFactory::Context::newShaderPipeline(const char* vertSource, const char* fragSource,
IVertexFormat* vtxFmt, unsigned targetSamples, IVertexFormat* vtxFmt, unsigned targetSamples,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim, BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, bool backfaceCulling) bool depthTest, bool depthWrite, bool backfaceCulling)
{ {
MTLCompileOptions* compOpts = [MTLCompileOptions new]; MTLCompileOptions* compOpts = [MTLCompileOptions new];
compOpts.languageVersion = MTLLanguageVersion1_1; compOpts.languageVersion = MTLLanguageVersion1_1;
NSError* err = nullptr; NSError* err = nullptr;
id<MTLLibrary> vertShaderLib = [m_ctx->m_dev newLibraryWithSource:@(vertSource) id<MTLLibrary> vertShaderLib = [m_parent.m_ctx->m_dev newLibraryWithSource:@(vertSource)
options:compOpts options:compOpts
error:&err]; error:&err];
if (err) if (err)
Log.report(logvisor::Fatal, "error compiling vert shader: %s", [[err localizedDescription] UTF8String]); Log.report(logvisor::Fatal, "error compiling vert shader: %s", [[err localizedDescription] UTF8String]);
id<MTLFunction> vertFunc = [vertShaderLib newFunctionWithName:@"vmain"]; id<MTLFunction> vertFunc = [vertShaderLib newFunctionWithName:@"vmain"];
id<MTLLibrary> fragShaderLib = [m_ctx->m_dev newLibraryWithSource:@(fragSource) id<MTLLibrary> fragShaderLib = [m_parent.m_ctx->m_dev newLibraryWithSource:@(fragSource)
options:compOpts options:compOpts
error:&err]; error:&err];
if (err) if (err)
Log.report(logvisor::Fatal, "error compiling frag shader: %s", [[err localizedDescription] UTF8String]); Log.report(logvisor::Fatal, "error compiling frag shader: %s", [[err localizedDescription] UTF8String]);
id<MTLFunction> fragFunc = [fragShaderLib newFunctionWithName:@"fmain"]; id<MTLFunction> fragFunc = [fragShaderLib newFunctionWithName:@"fmain"];
MetalShaderPipeline* retval = new MetalShaderPipeline(m_ctx, vertFunc, fragFunc, MetalShaderPipeline* retval = new MetalShaderPipeline(m_parent.m_ctx, vertFunc, fragFunc,
static_cast<const MetalVertexFormat*>(vtxFmt), targetSamples, static_cast<const MetalVertexFormat*>(vtxFmt), targetSamples,
srcFac, dstFac, prim, depthTest, depthWrite, backfaceCulling); srcFac, dstFac, prim, depthTest, depthWrite, backfaceCulling);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
m_deferredData->m_SPs.emplace_back(retval); m_deferredData->m_SPs.emplace_back(retval);
return retval; return retval;
} }
IShaderDataBinding* IShaderDataBinding*
MetalDataFactory::newShaderDataBinding(IShaderPipeline* pipeline, MetalDataFactory::Context::newShaderDataBinding(IShaderPipeline* pipeline,
IVertexFormat* vtxFormat, IVertexFormat* vtxFormat,
IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf, IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf,
size_t ubufCount, IGraphicsBuffer** ubufs, size_t ubufCount, IGraphicsBuffer** ubufs,
size_t texCount, ITexture** texs) const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs)
{ {
MetalShaderDataBinding* retval = MetalShaderDataBinding* retval =
new MetalShaderDataBinding(m_ctx, pipeline, vbuf, instVbo, ibuf, ubufCount, ubufs, texCount, texs); new MetalShaderDataBinding(m_parent.m_ctx, pipeline, vbuf, instVbo, ibuf,
if (!m_deferredData.get()) ubufCount, ubufs, ubufOffs, ubufSizes, texCount, texs);
m_deferredData.reset(new struct MetalData());
m_deferredData->m_SBinds.emplace_back(retval); m_deferredData->m_SBinds.emplace_back(retval);
return retval; return retval;
} }
void MetalDataFactory::reset() GraphicsDataToken MetalDataFactory::commitTransaction(const FactoryCommitFunc& trans)
{ {
delete m_deferredData.get(); if (m_deferredData.get())
m_deferredData.reset(); Log.report(logvisor::Fatal, "nested commitTransaction usage detected");
} m_deferredData.reset(new MetalData());
GraphicsDataToken MetalDataFactory::commit()
{ MetalDataFactory::Context ctx(*this);
if (!m_deferredData.get()) if (!trans(ctx))
{
delete m_deferredData.get();
m_deferredData.reset();
return GraphicsDataToken(this, nullptr); return GraphicsDataToken(this, nullptr);
}
std::unique_lock<std::mutex> lk(m_committedMutex); std::unique_lock<std::mutex> lk(m_committedMutex);
MetalData* retval = m_deferredData.get(); MetalData* retval = m_deferredData.get();
m_deferredData.reset(); m_deferredData.reset();