better OpenGL mipmap configuration

This commit is contained in:
Jack Andersen 2016-02-16 09:41:16 -10:00
parent e9bd443e49
commit 77e9492b43
4 changed files with 102 additions and 86 deletions

View File

@ -267,12 +267,16 @@ class GraphicsDataToken
IGraphicsData* m_data = nullptr; IGraphicsData* m_data = nullptr;
GraphicsDataToken(IGraphicsDataFactory* factory, IGraphicsData* data) GraphicsDataToken(IGraphicsDataFactory* factory, IGraphicsData* data)
: m_factory(factory), m_data(data) {} : m_factory(factory), m_data(data) {}
public:
void doDestroy() void doDestroy()
{ {
if (m_factory && m_data) if (m_factory && m_data)
{
m_factory->destroyData(m_data); m_factory->destroyData(m_data);
m_factory = nullptr;
m_data = nullptr;
}
} }
public:
GraphicsDataToken() = default; GraphicsDataToken() = default;
GraphicsDataToken(const GraphicsDataToken& other) = delete; GraphicsDataToken(const GraphicsDataToken& other) = delete;
GraphicsDataToken(GraphicsDataToken&& other) GraphicsDataToken(GraphicsDataToken&& other)

View File

@ -18,7 +18,7 @@
namespace boo namespace boo
{ {
struct MetalContext; struct MetalContext;
class MetalDataFactory : public IGraphicsDataFactory class MetalDataFactory : public IGraphicsDataFactory
{ {
friend struct MetalCommandQueue; friend struct MetalCommandQueue;
@ -27,44 +27,45 @@ class MetalDataFactory : public IGraphicsDataFactory
std::unordered_set<struct MetalData*> m_committedData; std::unordered_set<struct MetalData*> m_committedData;
std::mutex m_committedMutex; std::mutex m_committedMutex;
struct MetalContext* m_ctx; struct MetalContext* m_ctx;
void destroyData(IGraphicsData*); void destroyData(IGraphicsData*);
void destroyAllData(); void destroyAllData();
public: public:
MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx); MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx);
~MetalDataFactory() {} ~MetalDataFactory() {}
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); IGraphicsBufferS* newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
IGraphicsBufferS* newStaticBuffer(BufferUse use, std::unique_ptr<uint8_t[]>&& data, size_t stride, size_t count); IGraphicsBufferS* newStaticBuffer(BufferUse use, std::unique_ptr<uint8_t[]>&& data, size_t stride, size_t count);
IGraphicsBufferD* newDynamicBuffer(BufferUse use, 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, ITextureS* newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
const void* data, size_t sz); const void* data, size_t sz);
ITextureS* newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, GraphicsDataToken
std::unique_ptr<uint8_t[]>&& data, size_t sz); 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, ITextureSA* newStaticArrayTexture(size_t width, size_t height, size_t layers, TextureFormat fmt,
const void* data, size_t sz); const void* data, size_t sz);
ITextureD* newDynamicTexture(size_t width, size_t height, TextureFormat fmt); ITextureD* newDynamicTexture(size_t width, size_t height, TextureFormat fmt);
ITextureR* newRenderTexture(size_t width, size_t height, size_t samples); ITextureR* newRenderTexture(size_t width, size_t height, size_t samples);
bool bindingNeedsVertexFormat() const {return false;} bool bindingNeedsVertexFormat() const {return false;}
IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements); IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements);
IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource, IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource,
IVertexFormat* vtxFmt, unsigned targetSamples, IVertexFormat* vtxFmt, unsigned targetSamples,
BlendFactor srcFac, BlendFactor dstFac, BlendFactor srcFac, BlendFactor dstFac,
bool depthTest, bool depthWrite, bool backfaceCulling); bool depthTest, bool depthWrite, bool backfaceCulling);
IShaderDataBinding* IShaderDataBinding*
newShaderDataBinding(IShaderPipeline* pipeline, newShaderDataBinding(IShaderPipeline* pipeline,
IVertexFormat* vtxFormat, IVertexFormat* vtxFormat,
IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo, IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo,
size_t ubufCount, IGraphicsBuffer** ubufs, size_t ubufCount, IGraphicsBuffer** ubufs,
size_t texCount, ITexture** texs); size_t texCount, ITexture** texs);
void reset(); void reset();
GraphicsDataToken commit(); GraphicsDataToken commit();
}; };

View File

@ -127,7 +127,10 @@ class GLTextureS : public ITextureS
glBindTexture(GL_TEXTURE_2D, m_tex); glBindTexture(GL_TEXTURE_2D, m_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (mips > 1) if (mips > 1)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mips-1);
}
else else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@ -147,7 +150,7 @@ class GLTextureS : public ITextureS
pxPitch = 1; pxPitch = 1;
break; break;
case TextureFormat::DXT1: case TextureFormat::DXT1:
intFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; intFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
compressed = true; compressed = true;
break; break;
default: default:
@ -255,12 +258,12 @@ public:
glActiveTexture(GL_TEXTURE0 + idx); glActiveTexture(GL_TEXTURE0 + idx);
glBindTexture(m_target, m_texs[0]); glBindTexture(m_target, m_texs[0]);
} }
void resize(size_t width, size_t height) void resize(size_t width, size_t height)
{ {
m_width = width; m_width = width;
m_height = height; m_height = height;
if (m_samples > 1) if (m_samples > 1)
{ {
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[0]); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texs[0]);
@ -1115,7 +1118,7 @@ struct GLCommandQueue : IGraphicsCommandQueue
cmds.emplace_back(Command::Op::Present); cmds.emplace_back(Command::Op::Present);
cmds.back().source = source; cmds.back().source = source;
} }
void addVertexFormat(GLVertexFormat* fmt) void addVertexFormat(GLVertexFormat* fmt)
{ {
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);

View File

@ -72,7 +72,7 @@ public:
size_t m_sz; size_t m_sz;
id<MTLBuffer> m_bufs[2]; id<MTLBuffer> m_bufs[2];
MetalGraphicsBufferD() = default; MetalGraphicsBufferD() = default;
void load(const void* data, size_t sz); void load(const void* data, size_t sz);
void* map(size_t sz); void* map(size_t sz);
void unmap(); void unmap();
@ -85,16 +85,21 @@ class MetalTextureS : public ITextureS
TextureFormat fmt, const void* data, size_t sz) TextureFormat fmt, const void* data, size_t sz)
{ {
MTLPixelFormat pfmt = MTLPixelFormatRGBA8Unorm; MTLPixelFormat pfmt = MTLPixelFormatRGBA8Unorm;
NSUInteger ppitch = 4; NSUInteger ppitchNum = 4;
NSUInteger ppitchDenom = 1;
switch (fmt) switch (fmt)
{ {
case TextureFormat::I8: case TextureFormat::I8:
pfmt = MTLPixelFormatR8Unorm; pfmt = MTLPixelFormatR8Unorm;
ppitch = 1; ppitchNum = 1;
break; break;
case TextureFormat::DXT1:
pfmt = MTLPixelFormatBC1_RGBA;
ppitchNum = 1;
ppitchDenom = 2;
default: break; default: break;
} }
@autoreleasepool @autoreleasepool
{ {
MTLTextureDescriptor* desc = MTLTextureDescriptor* desc =
@ -110,8 +115,8 @@ class MetalTextureS : public ITextureS
[m_tex replaceRegion:MTLRegionMake2D(0, 0, width, height) [m_tex replaceRegion:MTLRegionMake2D(0, 0, width, height)
mipmapLevel:i mipmapLevel:i
withBytes:dataIt withBytes:dataIt
bytesPerRow:width * ppitch]; bytesPerRow:width * ppitchNum / ppitchDenom];
dataIt += width * height * ppitch; dataIt += width * height * ppitchNum / ppitchDenom;
width /= 2; width /= 2;
height /= 2; height /= 2;
} }
@ -121,7 +126,7 @@ public:
id<MTLTexture> m_tex; id<MTLTexture> m_tex;
~MetalTextureS() = default; ~MetalTextureS() = default;
}; };
class MetalTextureSA : public ITextureSA class MetalTextureSA : public ITextureSA
{ {
friend class MetalDataFactory; friend class MetalDataFactory;
@ -138,7 +143,7 @@ class MetalTextureSA : public ITextureSA
break; break;
default: break; default: break;
} }
@autoreleasepool @autoreleasepool
{ {
MTLTextureDescriptor* desc = MTLTextureDescriptor* desc =
@ -166,7 +171,7 @@ public:
id<MTLTexture> m_tex; id<MTLTexture> m_tex;
~MetalTextureSA() = default; ~MetalTextureSA() = default;
}; };
class MetalTextureD : public ITextureD class MetalTextureD : public ITextureD
{ {
friend class MetalDataFactory; friend class MetalDataFactory;
@ -195,10 +200,10 @@ class MetalTextureD : public ITextureD
default: default:
Log.report(LogVisor::FatalError, "unsupported tex format"); Log.report(LogVisor::FatalError, "unsupported tex format");
} }
m_cpuSz = width * height * m_pxPitch; m_cpuSz = width * height * m_pxPitch;
m_cpuBuf.reset(new uint8_t[m_cpuSz]); m_cpuBuf.reset(new uint8_t[m_cpuSz]);
@autoreleasepool @autoreleasepool
{ {
MTLTextureDescriptor* desc = MTLTextureDescriptor* desc =
@ -214,12 +219,12 @@ class MetalTextureD : public ITextureD
public: public:
id<MTLTexture> m_texs[2]; id<MTLTexture> m_texs[2];
~MetalTextureD() = default; ~MetalTextureD() = default;
void load(const void* data, size_t sz); void load(const void* data, size_t sz);
void* map(size_t sz); void* map(size_t sz);
void unmap(); void unmap();
}; };
class MetalTextureR : public ITextureR class MetalTextureR : public ITextureR
{ {
friend class MetalDataFactory; friend class MetalDataFactory;
@ -227,7 +232,7 @@ class MetalTextureR : public ITextureR
size_t m_width = 0; size_t m_width = 0;
size_t m_height = 0; size_t m_height = 0;
size_t m_samples = 0; size_t m_samples = 0;
void Setup(MetalContext* ctx, size_t width, size_t height, size_t samples) void Setup(MetalContext* ctx, size_t width, size_t height, size_t samples)
{ {
@autoreleasepool @autoreleasepool
@ -275,7 +280,7 @@ class MetalTextureR : public ITextureR
} }
} }
} }
MetalTextureR(MetalContext* ctx, size_t width, size_t height, size_t samples) MetalTextureR(MetalContext* ctx, size_t width, size_t height, size_t samples)
: m_width(width), m_height(height), m_samples(samples) : m_width(width), m_height(height), m_samples(samples)
{ {
@ -289,7 +294,7 @@ public:
id<MTLTexture> m_depthTex; id<MTLTexture> m_depthTex;
MTLRenderPassDescriptor* m_passDesc; MTLRenderPassDescriptor* m_passDesc;
~MetalTextureR() = default; ~MetalTextureR() = default;
void resize(MetalContext* ctx, size_t width, size_t height) void resize(MetalContext* ctx, size_t width, size_t height)
{ {
if (width < 1) if (width < 1)
@ -300,10 +305,10 @@ public:
m_height = height; m_height = height;
Setup(ctx, width, height, m_samples); Setup(ctx, width, height, m_samples);
} }
id<MTLTexture> getRenderColorRes() {if (m_samples > 1) return m_msaaTex; return m_tex;} id<MTLTexture> getRenderColorRes() {if (m_samples > 1) return m_msaaTex; return m_tex;}
}; };
static const size_t SEMANTIC_SIZE_TABLE[] = static const size_t SEMANTIC_SIZE_TABLE[] =
{ {
0, 0,
@ -352,18 +357,18 @@ struct MetalVertexFormat : IVertexFormat
else else
stride += SEMANTIC_SIZE_TABLE[semantic]; stride += SEMANTIC_SIZE_TABLE[semantic];
} }
m_vdesc = [MTLVertexDescriptor vertexDescriptor]; m_vdesc = [MTLVertexDescriptor vertexDescriptor];
MTLVertexBufferLayoutDescriptor* layoutDesc = m_vdesc.layouts[0]; MTLVertexBufferLayoutDescriptor* layoutDesc = m_vdesc.layouts[0];
layoutDesc.stride = stride; layoutDesc.stride = stride;
layoutDesc.stepFunction = MTLVertexStepFunctionPerVertex; layoutDesc.stepFunction = MTLVertexStepFunctionPerVertex;
layoutDesc.stepRate = 1; layoutDesc.stepRate = 1;
layoutDesc = m_vdesc.layouts[1]; layoutDesc = m_vdesc.layouts[1];
layoutDesc.stride = instStride; layoutDesc.stride = instStride;
layoutDesc.stepFunction = MTLVertexStepFunctionPerInstance; layoutDesc.stepFunction = MTLVertexStepFunctionPerInstance;
layoutDesc.stepRate = 1; layoutDesc.stepRate = 1;
size_t offset = 0; size_t offset = 0;
size_t instOffset = 0; size_t instOffset = 0;
for (size_t i=0 ; i<elementCount ; ++i) for (size_t i=0 ; i<elementCount ; ++i)
@ -387,7 +392,7 @@ struct MetalVertexFormat : IVertexFormat
} }
} }
}; };
static const MTLBlendFactor BLEND_FACTOR_TABLE[] = static const MTLBlendFactor BLEND_FACTOR_TABLE[] =
{ {
MTLBlendFactorZero, MTLBlendFactorZero,
@ -406,7 +411,7 @@ class MetalShaderPipeline : public IShaderPipeline
{ {
friend class MetalDataFactory; friend class MetalDataFactory;
MTLCullMode m_cullMode = MTLCullModeNone; MTLCullMode m_cullMode = MTLCullModeNone;
MetalShaderPipeline(MetalContext* ctx, id<MTLFunction> vert, id<MTLFunction> frag, MetalShaderPipeline(MetalContext* ctx, id<MTLFunction> vert, id<MTLFunction> frag,
const MetalVertexFormat* vtxFmt, NSUInteger targetSamples, const MetalVertexFormat* vtxFmt, NSUInteger targetSamples,
BlendFactor srcFac, BlendFactor dstFac, BlendFactor srcFac, BlendFactor dstFac,
@ -414,7 +419,7 @@ class MetalShaderPipeline : public IShaderPipeline
{ {
if (backfaceCulling) if (backfaceCulling)
m_cullMode = MTLCullModeBack; m_cullMode = MTLCullModeBack;
MTLRenderPipelineDescriptor* desc = [MTLRenderPipelineDescriptor new]; MTLRenderPipelineDescriptor* desc = [MTLRenderPipelineDescriptor new];
desc.vertexFunction = vert; desc.vertexFunction = vert;
desc.fragmentFunction = frag; desc.fragmentFunction = frag;
@ -431,7 +436,7 @@ class MetalShaderPipeline : public IShaderPipeline
if (err) if (err)
Log.report(LogVisor::FatalError, "error making shader pipeline: %s", Log.report(LogVisor::FatalError, "error making shader pipeline: %s",
[[err localizedDescription] UTF8String]); [[err localizedDescription] UTF8String]);
MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new]; MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new];
if (depthTest) if (depthTest)
dsDesc.depthCompareFunction = MTLCompareFunctionLessEqual; dsDesc.depthCompareFunction = MTLCompareFunctionLessEqual;
@ -444,7 +449,7 @@ public:
~MetalShaderPipeline() = default; ~MetalShaderPipeline() = default;
MetalShaderPipeline& operator=(const MetalShaderPipeline&) = delete; MetalShaderPipeline& operator=(const MetalShaderPipeline&) = delete;
MetalShaderPipeline(const MetalShaderPipeline&) = delete; MetalShaderPipeline(const MetalShaderPipeline&) = delete;
void bind(id<MTLRenderCommandEncoder> enc) void bind(id<MTLRenderCommandEncoder> enc)
{ {
[enc setRenderPipelineState:m_state]; [enc setRenderPipelineState:m_state];
@ -452,7 +457,7 @@ public:
[enc setCullMode:m_cullMode]; [enc setCullMode:m_cullMode];
} }
}; };
static id<MTLBuffer> GetBufferGPUResource(const IGraphicsBuffer* buf, int idx) static id<MTLBuffer> GetBufferGPUResource(const IGraphicsBuffer* buf, int idx)
{ {
if (buf->dynamic()) if (buf->dynamic())
@ -525,7 +530,7 @@ struct MetalShaderDataBinding : IShaderDataBinding
for (size_t i=0 ; i<texCount ; ++i) for (size_t i=0 ; i<texCount ; ++i)
m_texs[i] = texs[i]; m_texs[i] = texs[i];
} }
void bind(id<MTLRenderCommandEncoder> enc, int b) void bind(id<MTLRenderCommandEncoder> enc, int b)
{ {
m_pipeline->bind(enc); m_pipeline->bind(enc);
@ -550,10 +555,10 @@ struct MetalCommandQueue : IGraphicsCommandQueue
id<MTLCommandBuffer> m_cmdBuf; id<MTLCommandBuffer> m_cmdBuf;
id<MTLRenderCommandEncoder> m_enc; id<MTLRenderCommandEncoder> m_enc;
bool m_running = true; bool m_running = true;
size_t m_fillBuf = 0; size_t m_fillBuf = 0;
size_t m_drawBuf = 0; size_t m_drawBuf = 0;
MetalCommandQueue(MetalContext* ctx, IWindow* parentWindow, IGraphicsContext* parent) MetalCommandQueue(MetalContext* ctx, IWindow* parentWindow, IGraphicsContext* parent)
: m_ctx(ctx), m_parentWindow(parentWindow), m_parent(parent) : m_ctx(ctx), m_parentWindow(parentWindow), m_parent(parent)
{ {
@ -562,19 +567,19 @@ struct MetalCommandQueue : IGraphicsCommandQueue
m_cmdBuf = [ctx->m_q commandBuffer]; m_cmdBuf = [ctx->m_q commandBuffer];
} }
} }
void stopRenderer() void stopRenderer()
{ {
m_running = false; m_running = false;
if (m_inProgress) if (m_inProgress)
[m_cmdBuf waitUntilCompleted]; [m_cmdBuf waitUntilCompleted];
} }
~MetalCommandQueue() ~MetalCommandQueue()
{ {
if (m_running) stopRenderer(); if (m_running) stopRenderer();
} }
MetalShaderDataBinding* m_boundData = nullptr; MetalShaderDataBinding* m_boundData = nullptr;
void setShaderDataBinding(IShaderDataBinding* binding) void setShaderDataBinding(IShaderDataBinding* binding)
{ {
@ -582,7 +587,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
cbind->bind(m_enc, m_fillBuf); cbind->bind(m_enc, m_fillBuf);
m_boundData = cbind; m_boundData = cbind;
} }
MetalTextureR* m_boundTarget = nullptr; MetalTextureR* m_boundTarget = nullptr;
void setRenderTarget(ITextureR* target) void setRenderTarget(ITextureR* target)
{ {
@ -594,14 +599,14 @@ struct MetalCommandQueue : IGraphicsCommandQueue
} }
m_boundTarget = ctarget; m_boundTarget = ctarget;
} }
void setViewport(const SWindowRect& rect) void setViewport(const SWindowRect& rect)
{ {
MTLViewport vp = {double(rect.location[0]), double(rect.location[1]), MTLViewport vp = {double(rect.location[0]), double(rect.location[1]),
double(rect.size[0]), double(rect.size[1]), 0.0, 1.0}; double(rect.size[0]), double(rect.size[1]), 0.0, 1.0};
[m_enc setViewport:vp]; [m_enc setViewport:vp];
} }
void setScissor(const SWindowRect& rect) void setScissor(const SWindowRect& rect)
{ {
if (m_boundTarget) if (m_boundTarget)
@ -612,7 +617,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
[m_enc setScissorRect:scissor]; [m_enc setScissorRect:scissor];
} }
} }
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)
{ {
@ -624,9 +629,9 @@ struct MetalCommandQueue : IGraphicsCommandQueue
{ {
func(); func();
} }
void flushBufferUpdates() {} void flushBufferUpdates() {}
float m_clearColor[4] = {0.0,0.0,0.0,1.0}; float m_clearColor[4] = {0.0,0.0,0.0,1.0};
void setClearColor(const float rgba[4]) void setClearColor(const float rgba[4])
{ {
@ -635,14 +640,14 @@ struct MetalCommandQueue : IGraphicsCommandQueue
m_clearColor[2] = rgba[2]; m_clearColor[2] = rgba[2];
m_clearColor[3] = rgba[3]; m_clearColor[3] = rgba[3];
} }
void clearTarget(bool render=true, bool depth=true) void clearTarget(bool render=true, bool depth=true)
{ {
if (!m_boundTarget) if (!m_boundTarget)
return; return;
setRenderTarget(m_boundTarget); setRenderTarget(m_boundTarget);
} }
MTLPrimitiveType m_primType = MTLPrimitiveTypeTriangle; MTLPrimitiveType m_primType = MTLPrimitiveTypeTriangle;
void setDrawPrimitive(Primitive prim) void setDrawPrimitive(Primitive prim)
{ {
@ -651,12 +656,12 @@ struct MetalCommandQueue : IGraphicsCommandQueue
else if (prim == Primitive::TriStrips) else if (prim == Primitive::TriStrips)
m_primType = MTLPrimitiveTypeTriangleStrip; m_primType = MTLPrimitiveTypeTriangleStrip;
} }
void draw(size_t start, size_t count) void draw(size_t start, size_t count)
{ {
[m_enc drawPrimitives:m_primType vertexStart:start vertexCount:count]; [m_enc drawPrimitives:m_primType vertexStart:start vertexCount:count];
} }
void drawIndexed(size_t start, size_t count) void drawIndexed(size_t start, size_t count)
{ {
[m_enc drawIndexedPrimitives:m_primType [m_enc drawIndexedPrimitives:m_primType
@ -665,12 +670,12 @@ struct MetalCommandQueue : IGraphicsCommandQueue
indexBuffer:GetBufferGPUResource(m_boundData->m_ibuf, m_fillBuf) indexBuffer:GetBufferGPUResource(m_boundData->m_ibuf, m_fillBuf)
indexBufferOffset:start*4]; indexBufferOffset:start*4];
} }
void drawInstances(size_t start, size_t count, size_t instCount) void drawInstances(size_t start, size_t count, size_t instCount)
{ {
[m_enc drawPrimitives:m_primType vertexStart:start vertexCount:count instanceCount:instCount]; [m_enc drawPrimitives:m_primType vertexStart:start vertexCount:count instanceCount:instCount];
} }
void drawInstancesIndexed(size_t start, size_t count, size_t instCount) void drawInstancesIndexed(size_t start, size_t count, size_t instCount)
{ {
[m_enc drawIndexedPrimitives:m_primType [m_enc drawIndexedPrimitives:m_primType
@ -680,19 +685,19 @@ struct MetalCommandQueue : IGraphicsCommandQueue
indexBufferOffset:start*4 indexBufferOffset:start*4
instanceCount:instCount]; instanceCount:instCount];
} }
MetalTextureR* m_needsDisplay = nullptr; MetalTextureR* m_needsDisplay = nullptr;
void resolveDisplay(ITextureR* source) void resolveDisplay(ITextureR* source)
{ {
m_needsDisplay = static_cast<MetalTextureR*>(source); m_needsDisplay = static_cast<MetalTextureR*>(source);
} }
bool m_inProgress = false; bool m_inProgress = false;
void execute() void execute()
{ {
if (!m_running) if (!m_running)
return; return;
/* Update dynamic data here */ /* Update dynamic data here */
MetalDataFactory* gfxF = static_cast<MetalDataFactory*>(m_parent->getDataFactory()); MetalDataFactory* gfxF = static_cast<MetalDataFactory*>(m_parent->getDataFactory());
std::unique_lock<std::mutex> datalk(gfxF->m_committedMutex); std::unique_lock<std::mutex> datalk(gfxF->m_committedMutex);
@ -704,19 +709,19 @@ struct MetalCommandQueue : IGraphicsCommandQueue
t->update(m_fillBuf); t->update(m_fillBuf);
} }
datalk.unlock(); datalk.unlock();
@autoreleasepool @autoreleasepool
{ {
[m_enc endEncoding]; [m_enc endEncoding];
m_enc = nullptr; m_enc = nullptr;
/* Abandon if in progress (renderer too slow) */ /* Abandon if in progress (renderer too slow) */
if (m_inProgress) if (m_inProgress)
{ {
m_cmdBuf = [m_ctx->m_q commandBuffer]; m_cmdBuf = [m_ctx->m_q commandBuffer];
return; return;
} }
/* Perform texture resizes */ /* Perform texture resizes */
if (m_texResizes.size()) if (m_texResizes.size())
{ {
@ -726,7 +731,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
m_cmdBuf = [m_ctx->m_q commandBuffer]; m_cmdBuf = [m_ctx->m_q commandBuffer];
return; return;
} }
/* Wrap up and present if needed */ /* Wrap up and present if needed */
if (m_needsDisplay) if (m_needsDisplay)
{ {
@ -767,10 +772,10 @@ struct MetalCommandQueue : IGraphicsCommandQueue
} }
m_needsDisplay = nullptr; m_needsDisplay = nullptr;
} }
m_drawBuf = m_fillBuf; m_drawBuf = m_fillBuf;
m_fillBuf ^= 1; m_fillBuf ^= 1;
[m_cmdBuf addCompletedHandler:^(id<MTLCommandBuffer> buf) {m_inProgress = false;}]; [m_cmdBuf addCompletedHandler:^(id<MTLCommandBuffer> buf) {m_inProgress = false;}];
m_inProgress = true; m_inProgress = true;
[m_cmdBuf commit]; [m_cmdBuf commit];
@ -778,7 +783,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
} }
} }
}; };
void MetalGraphicsBufferD::update(int b) void MetalGraphicsBufferD::update(int b)
{ {
int slot = 1 << b; int slot = 1 << b;
@ -833,10 +838,10 @@ void MetalTextureD::unmap()
{ {
m_validSlots = 0; m_validSlots = 0;
} }
MetalDataFactory::MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx) MetalDataFactory::MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx)
: m_parent(parent), m_ctx(ctx) {} : m_parent(parent), m_ctx(ctx) {}
IGraphicsBufferS* MetalDataFactory::newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count) IGraphicsBufferS* MetalDataFactory::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_ctx, data, stride, count);
@ -873,15 +878,18 @@ ITextureS* MetalDataFactory::newStaticTexture(size_t width, size_t height, size_
m_deferredData->m_STexs.emplace_back(retval); m_deferredData->m_STexs.emplace_back(retval);
return retval; return retval;
} }
ITextureS* MetalDataFactory::newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, GraphicsDataToken
std::unique_ptr<uint8_t[]>&& data, size_t sz) MetalDataFactory::newStaticTextureNoContext(size_t width, size_t height, size_t mips, TextureFormat fmt,
const void* data, size_t sz, ITextureS** texOut)
{ {
std::unique_ptr<uint8_t[]> d = std::move(data); MetalTextureS* retval = new MetalTextureS(m_ctx, width, height, mips, fmt, data, sz);
MetalTextureS* retval = new MetalTextureS(m_ctx, width, height, mips, fmt, d.get(), sz); MetalData* tokData = new struct MetalData();
if (!m_deferredData.get()) tokData->m_STexs.emplace_back(retval);
m_deferredData.reset(new struct MetalData()); *texOut = retval;
m_deferredData->m_STexs.emplace_back(retval);
return 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::newStaticArrayTexture(size_t width, size_t height, size_t layers, TextureFormat fmt,
const void* data, size_t sz) const void* data, size_t sz)
@ -927,21 +935,21 @@ IShaderPipeline* MetalDataFactory::newShaderPipeline(const char* vertSource, con
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_ctx->m_dev newLibraryWithSource:@(vertSource)
options:compOpts options:compOpts
error:&err]; error:&err];
if (err) if (err)
Log.report(LogVisor::FatalError, "error compiling vert shader: %s", [[err localizedDescription] UTF8String]); Log.report(LogVisor::FatalError, "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_ctx->m_dev newLibraryWithSource:@(fragSource)
options:compOpts options:compOpts
error:&err]; error:&err];
if (err) if (err)
Log.report(LogVisor::FatalError, "error compiling frag shader: %s", [[err localizedDescription] UTF8String]); Log.report(LogVisor::FatalError, "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_ctx, vertFunc, fragFunc,
static_cast<const MetalVertexFormat*>(vtxFmt), targetSamples, static_cast<const MetalVertexFormat*>(vtxFmt), targetSamples,
srcFac, dstFac, depthTest, depthWrite, backfaceCulling); srcFac, dstFac, depthTest, depthWrite, backfaceCulling);
@ -995,13 +1003,13 @@ void MetalDataFactory::destroyAllData()
delete static_cast<MetalData*>(data); delete static_cast<MetalData*>(data);
m_committedData.clear(); m_committedData.clear();
} }
IGraphicsCommandQueue* _NewMetalCommandQueue(MetalContext* ctx, IWindow* parentWindow, IGraphicsCommandQueue* _NewMetalCommandQueue(MetalContext* ctx, IWindow* parentWindow,
IGraphicsContext* parent) IGraphicsContext* parent)
{ {
return new struct MetalCommandQueue(ctx, parentWindow, parent); return new struct MetalCommandQueue(ctx, parentWindow, parent);
} }
} }
#endif #endif