Brought metal in sync

This commit is contained in:
Jack Andersen 2015-12-02 12:25:30 -10:00
parent d0bdb40f0e
commit fc4234708f
2 changed files with 85 additions and 27 deletions

View File

@ -20,9 +20,10 @@ struct MetalContext;
class MetalDataFactory : public IGraphicsDataFactory class MetalDataFactory : public IGraphicsDataFactory
{ {
friend struct MetalCommandQueue;
IGraphicsContext* m_parent; IGraphicsContext* m_parent;
IGraphicsData* m_deferredData = nullptr; struct MetalData* m_deferredData = nullptr;
std::unordered_set<IGraphicsData*> m_committedData; std::unordered_set<struct MetalData*> m_committedData;
struct MetalContext* m_ctx; struct MetalContext* m_ctx;
public: public:
MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx); MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx);

View File

@ -51,12 +51,16 @@ class MetalGraphicsBufferD : public IGraphicsBufferD
friend class MetalDataFactory; friend class MetalDataFactory;
friend struct MetalCommandQueue; friend struct MetalCommandQueue;
MetalCommandQueue* m_q; MetalCommandQueue* m_q;
std::unique_ptr<uint8_t[]> m_cpuBuf;
int m_validSlots = 0;
MetalGraphicsBufferD(MetalCommandQueue* q, BufferUse use, MetalContext* ctx, size_t stride, size_t count) MetalGraphicsBufferD(MetalCommandQueue* q, BufferUse use, MetalContext* ctx, size_t stride, size_t count)
: m_q(q), m_stride(stride), m_count(count), m_sz(stride * count) : m_q(q), m_stride(stride), m_count(count), m_sz(stride * count)
{ {
m_cpuBuf.reset(new uint8_t[m_sz]);
m_bufs[0] = [ctx->m_dev.get() newBufferWithLength:m_sz options:MTL_DYNAMIC]; m_bufs[0] = [ctx->m_dev.get() newBufferWithLength:m_sz options:MTL_DYNAMIC];
m_bufs[1] = [ctx->m_dev.get() newBufferWithLength:m_sz options:MTL_DYNAMIC]; m_bufs[1] = [ctx->m_dev.get() newBufferWithLength:m_sz options:MTL_DYNAMIC];
} }
void update(int b);
public: public:
size_t m_stride; size_t m_stride;
size_t m_count; size_t m_count;
@ -65,8 +69,6 @@ public:
MetalGraphicsBufferD() = default; MetalGraphicsBufferD() = default;
void load(const void* data, size_t sz); void load(const void* data, size_t sz);
size_t m_mappedSz;
void* map(size_t sz); void* map(size_t sz);
void unmap(); void unmap();
}; };
@ -167,14 +169,35 @@ class MetalTextureD : public ITextureD
MetalCommandQueue* m_q; MetalCommandQueue* m_q;
size_t m_width = 0; size_t m_width = 0;
size_t m_height = 0; size_t m_height = 0;
void* m_mappedBuf; std::unique_ptr<uint8_t[]> m_cpuBuf;
size_t m_cpuSz;
size_t m_pxPitch;
int m_validSlots = 0;
MetalTextureD(MetalCommandQueue* q, MetalContext* ctx, size_t width, size_t height, TextureFormat fmt) MetalTextureD(MetalCommandQueue* q, MetalContext* ctx, size_t width, size_t height, TextureFormat fmt)
: m_q(q), m_width(width), m_height(height) : m_q(q), m_width(width), m_height(height)
{ {
MTLPixelFormat format;
switch (fmt)
{
case TextureFormat::RGBA8:
format = MTLPixelFormatRGBA8Unorm;
m_pxPitch = 4;
break;
case TextureFormat::I8:
format = MTLPixelFormatR8Unorm;
m_pxPitch = 1;
break;
default:
Log.report(LogVisor::FatalError, "unsupported tex format");
}
m_cpuSz = width * height * m_pxPitch;
m_cpuBuf.reset(new uint8_t[m_cpuSz]);
NSPtr<MTLTextureDescriptor*> desc; NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool @autoreleasepool
{ {
desc = [[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm desc = [[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
width:width height:height width:width height:height
mipmapped:NO] retain]; mipmapped:NO] retain];
} }
@ -182,6 +205,7 @@ class MetalTextureD : public ITextureD
m_texs[0] = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()]; m_texs[0] = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()];
m_texs[1] = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()]; m_texs[1] = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()];
} }
void update(int b);
public: public:
NSPtr<id<MTLTexture>> m_texs[2]; NSPtr<id<MTLTexture>> m_texs[2];
~MetalTextureD() = default; ~MetalTextureD() = default;
@ -566,9 +590,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
NSUInteger(rect.size[0]), NSUInteger(rect.size[1])}; NSUInteger(rect.size[0]), NSUInteger(rect.size[1])};
[m_enc.get() setScissorRect:scissor]; [m_enc.get() setScissorRect:scissor];
} }
int pendingDynamicSlot() {return m_fillBuf;}
std::unordered_map<MetalTextureR*, std::pair<size_t, size_t>> m_texResizes; std::unordered_map<MetalTextureR*, std::pair<size_t, size_t>> m_texResizes;
void resizeRenderTexture(ITextureR* tex, size_t width, size_t height) void resizeRenderTexture(ITextureR* tex, size_t width, size_t height)
{ {
@ -664,6 +686,20 @@ struct MetalCommandQueue : IGraphicsCommandQueue
bool m_inProgress = false; bool m_inProgress = false;
void execute() void execute()
{ {
/* Update dynamic data here */
MetalDataFactory* gfxF = static_cast<MetalDataFactory*>(m_parent->getDataFactory());
for (MetalData* d : gfxF->m_committedData)
{
for (std::unique_ptr<MetalGraphicsBufferD>& b : d->m_DBufs)
b->update(m_fillBuf);
for (std::unique_ptr<MetalTextureD>& t : d->m_DTexs)
t->update(m_fillBuf);
}
for (std::unique_ptr<MetalGraphicsBufferD>& b : gfxF->m_deferredData->m_DBufs)
b->update(m_fillBuf);
for (std::unique_ptr<MetalTextureD>& t : gfxF->m_deferredData->m_DTexs)
t->update(m_fillBuf);
@autoreleasepool @autoreleasepool
{ {
/* Abandon if in progress (renderer too slow) */ /* Abandon if in progress (renderer too slow) */
@ -684,9 +720,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
} }
m_drawBuf = m_fillBuf; m_drawBuf = m_fillBuf;
++m_fillBuf; m_fillBuf ^= 1;
if (m_fillBuf == 2)
m_fillBuf = 0;
[m_cmdBuf.get() addCompletedHandler:^(id<MTLCommandBuffer> buf) {m_inProgress = false;}]; [m_cmdBuf.get() addCompletedHandler:^(id<MTLCommandBuffer> buf) {m_inProgress = false;}];
m_inProgress = true; m_inProgress = true;
@ -696,36 +730,59 @@ struct MetalCommandQueue : IGraphicsCommandQueue
} }
}; };
void MetalGraphicsBufferD::update(int b)
{
int slot = 1 << b;
if ((slot & m_validSlots) == 0)
{
id<MTLBuffer> res = m_bufs[b].get();
memcpy(res.contents, m_cpuBuf.get(), m_sz);
m_validSlots |= slot;
}
}
void MetalGraphicsBufferD::load(const void* data, size_t sz) void MetalGraphicsBufferD::load(const void* data, size_t sz)
{ {
id<MTLBuffer> res = m_bufs[m_q->m_fillBuf].get(); size_t bufSz = std::min(sz, m_sz);
memcpy(res.contents, data, sz); memcpy(m_cpuBuf.get(), data, bufSz);
m_validSlots = 0;
} }
void* MetalGraphicsBufferD::map(size_t sz) void* MetalGraphicsBufferD::map(size_t sz)
{ {
m_mappedSz = sz; if (sz > m_sz)
id<MTLBuffer> res = m_bufs[m_q->m_fillBuf].get(); return nullptr;
return res.contents; return m_cpuBuf.get();
}
void MetalGraphicsBufferD::unmap()
{
m_validSlots = 0;
} }
void MetalGraphicsBufferD::unmap() {}
void MetalTextureD::update(int b)
{
int slot = 1 << b;
if ((slot & m_validSlots) == 0)
{
id<MTLTexture> res = m_texs[b].get();
[res replaceRegion:MTLRegionMake2D(0, 0, m_width, m_height)
mipmapLevel:0 withBytes:m_cpuBuf.get() bytesPerRow:m_width*m_pxPitch];
m_validSlots |= slot;
}
}
void MetalTextureD::load(const void* data, size_t sz) void MetalTextureD::load(const void* data, size_t sz)
{ {
id<MTLTexture> res = m_texs[m_q->m_fillBuf].get(); size_t bufSz = std::min(sz, m_cpuSz);
[res replaceRegion:MTLRegionMake2D(0, 0, m_width, m_height) memcpy(m_cpuBuf.get(), data, bufSz);
mipmapLevel:0 withBytes:data bytesPerRow:m_width*4]; m_validSlots = 0;
} }
void* MetalTextureD::map(size_t sz) void* MetalTextureD::map(size_t sz)
{ {
m_mappedBuf = malloc(sz); if (sz > m_cpuSz)
return m_mappedBuf; return nullptr;
return m_cpuBuf.get();
} }
void MetalTextureD::unmap() void MetalTextureD::unmap()
{ {
id<MTLTexture> res = m_texs[m_q->m_fillBuf].get(); m_validSlots = 0;
[res replaceRegion:MTLRegionMake2D(0, 0, m_width, m_height)
mipmapLevel:0 withBytes:m_mappedBuf bytesPerRow:m_width*4];
free(m_mappedBuf);
} }
MetalDataFactory::MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx) MetalDataFactory::MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx)