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,14 +38,20 @@ public:
Platform platform() const {return Platform::Metal;}
const char* platformName() const {return "Metal";}
class Context : public IGraphicsDataFactory::Context
{
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";}
IGraphicsBufferS* newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
IGraphicsBufferD* newDynamicBuffer(BufferUse use, size_t stride, size_t count);
ITextureS* newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
const void* data, size_t sz);
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);
@ -65,10 +71,11 @@ public:
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);
};
void reset();
GraphicsDataToken commit();
virtual GraphicsDataToken commitTransaction(const std::function<bool(IGraphicsDataFactory::Context& ctx)>&);
};
}

View File

@ -528,12 +528,14 @@ struct MetalShaderDataBinding : IShaderDataBinding
IGraphicsBuffer* m_ibuf;
size_t m_ubufCount;
std::unique_ptr<IGraphicsBuffer*[]> m_ubufs;
std::vector<size_t> m_ubufOffs;
size_t m_texCount;
std::unique_ptr<ITexture*[]> m_texs;
MetalShaderDataBinding(MetalContext* ctx,
IShaderPipeline* pipeline,
IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf,
size_t ubufCount, IGraphicsBuffer** ubufs,
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs)
: m_pipeline(static_cast<MetalShaderPipeline*>(pipeline)),
m_vbuf(vbuf),
@ -544,11 +546,35 @@ struct MetalShaderDataBinding : IShaderDataBinding
m_texCount(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)
{
#ifndef NDEBUG
if (!ubufs[i])
Log.report(logvisor::Fatal, "null uniform-buffer %d provided to newShaderDataBinding", int(i));
#endif
m_ubufs[i] = ubufs[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];
}
}
void bind(id<MTLRenderCommandEncoder> enc, int b)
{
@ -557,6 +583,10 @@ struct MetalShaderDataBinding : IShaderDataBinding
[enc setVertexBuffer:GetBufferGPUResource(m_vbuf, b) offset:0 atIndex:0];
if (m_instVbo)
[enc setVertexBuffer:GetBufferGPUResource(m_instVbo, b) offset:0 atIndex:1];
if (m_ubufOffs.size())
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)
@ -883,84 +913,57 @@ void MetalTextureD::unmap()
MetalDataFactory::MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx, uint32_t 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);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
MetalGraphicsBufferS* retval = new MetalGraphicsBufferS(use, m_parent.m_ctx, data, stride, count);
m_deferredData->m_SBufs.emplace_back(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());
MetalGraphicsBufferD* retval = new MetalGraphicsBufferD(q, use, m_ctx, stride, count);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
MetalCommandQueue* q = static_cast<MetalCommandQueue*>(m_parent.m_parent->getCommandQueue());
MetalGraphicsBufferD* retval = new MetalGraphicsBufferD(q, use, m_parent.m_ctx, stride, count);
m_deferredData->m_DBufs.emplace_back(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)
{
MetalTextureS* retval = new MetalTextureS(m_ctx, width, height, mips, fmt, data, sz);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
MetalTextureS* retval = new MetalTextureS(m_parent.m_ctx, width, height, mips, fmt, data, sz);
m_deferredData->m_STexs.emplace_back(retval);
return retval;
}
GraphicsDataToken
MetalDataFactory::newStaticTextureNoContext(size_t width, size_t height, size_t mips, TextureFormat fmt,
const void* data, size_t sz, ITextureS*& texOut)
{
MetalTextureS* retval = new MetalTextureS(m_ctx, width, height, mips, 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,
ITextureSA* MetalDataFactory::Context::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());
MetalTextureSA* retval = new MetalTextureSA(m_parent.m_ctx, width, height, layers, fmt, data, sz);
m_deferredData->m_SATexs.emplace_back(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());
MetalTextureD* retval = new MetalTextureD(q, m_ctx, width, height, fmt);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
MetalCommandQueue* q = static_cast<MetalCommandQueue*>(m_parent.m_parent->getCommandQueue());
MetalTextureD* retval = new MetalTextureD(q, m_parent.m_ctx, width, height, fmt);
m_deferredData->m_DTexs.emplace_back(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)
{
MetalTextureR* retval = new MetalTextureR(m_ctx, width, height, m_sampleCount, enableShaderColorBinding);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
MetalTextureR* retval = new MetalTextureR(m_parent.m_ctx, width, height, m_parent.m_sampleCount, enableShaderColorBinding);
m_deferredData->m_RTexs.emplace_back(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);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
m_deferredData->m_VFmts.emplace_back(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,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, bool backfaceCulling)
@ -969,53 +972,56 @@ IShaderPipeline* MetalDataFactory::newShaderPipeline(const char* vertSource, con
compOpts.languageVersion = MTLLanguageVersion1_1;
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
error:&err];
if (err)
Log.report(logvisor::Fatal, "error compiling vert shader: %s", [[err localizedDescription] UTF8String]);
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
error:&err];
if (err)
Log.report(logvisor::Fatal, "error compiling frag shader: %s", [[err localizedDescription] UTF8String]);
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,
srcFac, dstFac, prim, depthTest, depthWrite, backfaceCulling);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
m_deferredData->m_SPs.emplace_back(retval);
return retval;
}
IShaderDataBinding*
MetalDataFactory::newShaderDataBinding(IShaderPipeline* pipeline,
MetalDataFactory::Context::newShaderDataBinding(IShaderPipeline* pipeline,
IVertexFormat* vtxFormat,
IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf,
size_t ubufCount, IGraphicsBuffer** ubufs,
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs)
{
MetalShaderDataBinding* retval =
new MetalShaderDataBinding(m_ctx, pipeline, vbuf, instVbo, ibuf, ubufCount, ubufs, texCount, texs);
if (!m_deferredData.get())
m_deferredData.reset(new struct MetalData());
new MetalShaderDataBinding(m_parent.m_ctx, pipeline, vbuf, instVbo, ibuf,
ubufCount, ubufs, ubufOffs, ubufSizes, texCount, texs);
m_deferredData->m_SBinds.emplace_back(retval);
return retval;
}
void MetalDataFactory::reset()
GraphicsDataToken MetalDataFactory::commitTransaction(const FactoryCommitFunc& trans)
{
if (m_deferredData.get())
Log.report(logvisor::Fatal, "nested commitTransaction usage detected");
m_deferredData.reset(new MetalData());
MetalDataFactory::Context ctx(*this);
if (!trans(ctx))
{
delete m_deferredData.get();
m_deferredData.reset();
}
GraphicsDataToken MetalDataFactory::commit()
{
if (!m_deferredData.get())
return GraphicsDataToken(this, nullptr);
}
std::unique_lock<std::mutex> lk(m_committedMutex);
MetalData* retval = m_deferredData.get();
m_deferredData.reset();