diff --git a/include/boo/graphicsdev/Metal.hpp b/include/boo/graphicsdev/Metal.hpp index 7820467..6476f7a 100644 --- a/include/boo/graphicsdev/Metal.hpp +++ b/include/boo/graphicsdev/Metal.hpp @@ -39,6 +39,8 @@ public: const void* data, size_t sz); ITextureS* newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, std::unique_ptr&& 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, size_t samples); @@ -46,14 +48,14 @@ public: IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements); IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource, - IVertexFormat* vtxFmt, ITextureR* target, + IVertexFormat* vtxFmt, unsigned targetSamples, BlendFactor srcFac, BlendFactor dstFac, bool depthTest, bool depthWrite, bool backfaceCulling); IShaderDataBinding* newShaderDataBinding(IShaderPipeline* pipeline, IVertexFormat* vtxFormat, - IGraphicsBuffer* vbo, IGraphicsBuffer* ibo, + IGraphicsBuffer* vbo, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibo, size_t ubufCount, IGraphicsBuffer** ubufs, size_t texCount, ITexture** texs); diff --git a/lib/graphicsdev/Metal.mm b/lib/graphicsdev/Metal.mm index 1a0521f..2489a8a 100644 --- a/lib/graphicsdev/Metal.mm +++ b/lib/graphicsdev/Metal.mm @@ -20,6 +20,7 @@ struct MetalData : IGraphicsData std::vector> m_SBufs; std::vector> m_DBufs; std::vector> m_STexs; + std::vector> m_SATexs; std::vector> m_DTexs; std::vector> m_RTexs; std::vector> m_VFmts; @@ -76,10 +77,21 @@ class MetalTextureS : public ITextureS MetalTextureS(MetalContext* ctx, size_t width, size_t height, size_t mips, TextureFormat fmt, const void* data, size_t sz) { + MTLPixelFormat pfmt = MTLPixelFormatRGBA8Unorm; + NSUInteger ppitch = 4; + switch (fmt) + { + case TextureFormat::I8: + pfmt = MTLPixelFormatR8Unorm; + ppitch = 1; + break; + default: break; + } + NSPtr desc; @autoreleasepool { - desc = [[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm + desc = [[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt width:width height:height mipmapped:(mips>1)?YES:NO] retain]; } @@ -92,8 +104,8 @@ class MetalTextureS : public ITextureS [m_tex.get() replaceRegion:MTLRegionMake2D(0, 0, width, height) mipmapLevel:i withBytes:dataIt - bytesPerRow:width * 4]; - dataIt += width * height * 4; + bytesPerRow:width * ppitch]; + dataIt += width * height * ppitch; width /= 2; height /= 2; } @@ -103,6 +115,51 @@ public: ~MetalTextureS() = default; }; +class MetalTextureSA : public ITextureSA +{ + friend class MetalDataFactory; + MetalTextureSA(MetalContext* ctx, size_t width, size_t height, size_t layers, + TextureFormat fmt, const void* data, size_t sz) + { + MTLPixelFormat pfmt = MTLPixelFormatRGBA8Unorm; + NSUInteger ppitch = 4; + switch (fmt) + { + case TextureFormat::I8: + pfmt = MTLPixelFormatR8Unorm; + ppitch = 1; + break; + default: break; + } + + NSPtr desc; + @autoreleasepool + { + desc = [[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt + width:width height:height + mipmapped:NO] retain]; + } + desc.get().textureType = MTLTextureType2DArray; + desc.get().arrayLength = layers; + desc.get().usage = MTLTextureUsageShaderRead; + m_tex = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()]; + const uint8_t* dataIt = reinterpret_cast(data); + for (size_t i=0 ; i> m_tex; + ~MetalTextureSA() = default; +}; + class MetalTextureD : public ITextureD { friend class MetalDataFactory; @@ -220,19 +277,31 @@ public: static const size_t SEMANTIC_SIZE_TABLE[] = { + 0, 12, + 16, 12, + 16, + 16, 4, 8, + 16, + 16, 16 }; static const MTLVertexFormat SEMANTIC_TYPE_TABLE[] = { + MTLVertexFormatInvalid, MTLVertexFormatFloat3, + MTLVertexFormatFloat4, MTLVertexFormatFloat3, + MTLVertexFormatFloat4, + MTLVertexFormatFloat4, MTLVertexFormatUChar4Normalized, MTLVertexFormatFloat2, + MTLVertexFormatFloat4, + MTLVertexFormatFloat4, MTLVertexFormatFloat4 }; @@ -244,10 +313,15 @@ struct MetalVertexFormat : IVertexFormat : m_elementCount(elementCount) { size_t stride = 0; + size_t instStride = 0; for (size_t i=0 ; isemantic)]; + int semantic = int(elemin->semantic & VertexSemantic::SemanticMask); + if ((elemin->semantic & VertexSemantic::Instanced) != VertexSemantic::None) + instStride += SEMANTIC_SIZE_TABLE[semantic]; + else + stride += SEMANTIC_SIZE_TABLE[semantic]; } m_vdesc = [MTLVertexDescriptor vertexDescriptor]; @@ -256,15 +330,31 @@ struct MetalVertexFormat : IVertexFormat layoutDesc.stepFunction = MTLVertexStepFunctionPerVertex; layoutDesc.stepRate = 1; + layoutDesc = m_vdesc.get().layouts[1]; + layoutDesc.stride = instStride; + layoutDesc.stepFunction = MTLVertexStepFunctionPerInstance; + layoutDesc.stepRate = 1; + size_t offset = 0; + size_t instOffset = 0; for (size_t i=0 ; isemantic)]; - attrDesc.offset = offset; - attrDesc.bufferIndex = 0; - offset += SEMANTIC_SIZE_TABLE[int(elemin->semantic)]; + int semantic = int(elemin->semantic & VertexSemantic::SemanticMask); + if ((elemin->semantic & VertexSemantic::Instanced) != VertexSemantic::None) + { + attrDesc.offset = instOffset; + attrDesc.bufferIndex = 1; + instOffset += SEMANTIC_SIZE_TABLE[semantic]; + } + else + { + attrDesc.offset = offset; + attrDesc.bufferIndex = 0; + offset += SEMANTIC_SIZE_TABLE[semantic]; + } + attrDesc.format = SEMANTIC_TYPE_TABLE[semantic]; } } }; @@ -289,7 +379,7 @@ class MetalShaderPipeline : public IShaderPipeline MTLCullMode m_cullMode = MTLCullModeNone; MetalShaderPipeline(MetalContext* ctx, id vert, id frag, - const MetalVertexFormat* vtxFmt, MetalTextureR* target, + const MetalVertexFormat* vtxFmt, NSUInteger targetSamples, BlendFactor srcFac, BlendFactor dstFac, bool depthTest, bool depthWrite, bool backfaceCulling) { @@ -300,7 +390,7 @@ class MetalShaderPipeline : public IShaderPipeline desc.get().vertexFunction = vert; desc.get().fragmentFunction = frag; desc.get().vertexDescriptor = vtxFmt->m_vdesc.get(); - desc.get().sampleCount = target->samples(); + desc.get().sampleCount = targetSamples; desc.get().colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm; desc.get().colorAttachments[0].blendingEnabled = dstFac != BlendFactor::Zero; desc.get().colorAttachments[0].sourceRGBBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)]; @@ -350,21 +440,30 @@ static id GetBufferGPUResource(const IGraphicsBuffer* buf, int idx) static id GetTextureGPUResource(const ITexture* tex, int idx) { - if (tex->type() == TextureType::Dynamic) + switch (tex->type()) + { + case TextureType::Dynamic: { const MetalTextureD* ctex = static_cast(tex); return ctex->m_texs[idx].get(); } - else if (tex->type() == TextureType::Static) + case TextureType::Static: { const MetalTextureS* ctex = static_cast(tex); return ctex->m_tex.get(); } - else if (tex->type() == TextureType::Render) + case TextureType::StaticArray: + { + const MetalTextureSA* ctex = static_cast(tex); + return ctex->m_tex.get(); + } + case TextureType::Render: { const MetalTextureR* ctex = static_cast(tex); return ctex->m_tex.get(); } + default: break; + } return nullptr; } @@ -372,6 +471,7 @@ struct MetalShaderDataBinding : IShaderDataBinding { MetalShaderPipeline* m_pipeline; IGraphicsBuffer* m_vbuf; + IGraphicsBuffer* m_instVbo; IGraphicsBuffer* m_ibuf; size_t m_ubufCount; std::unique_ptr m_ubufs; @@ -379,11 +479,12 @@ struct MetalShaderDataBinding : IShaderDataBinding std::unique_ptr m_texs; MetalShaderDataBinding(MetalContext* ctx, IShaderPipeline* pipeline, - IGraphicsBuffer* vbuf, IGraphicsBuffer* ibuf, + IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf, size_t ubufCount, IGraphicsBuffer** ubufs, size_t texCount, ITexture** texs) : m_pipeline(static_cast(pipeline)), m_vbuf(vbuf), + m_instVbo(instVbo), m_ibuf(ibuf), m_ubufCount(ubufCount), m_ubufs(new IGraphicsBuffer*[ubufCount]), @@ -399,9 +500,12 @@ struct MetalShaderDataBinding : IShaderDataBinding void bind(id enc, int b) { m_pipeline->bind(enc); - [enc setVertexBuffer:GetBufferGPUResource(m_vbuf, b) offset:0 atIndex:0]; + if (m_vbuf) + [enc setVertexBuffer:GetBufferGPUResource(m_vbuf, b) offset:0 atIndex:0]; + if (m_instVbo) + [enc setVertexBuffer:GetBufferGPUResource(m_instVbo, b) offset:0 atIndex:1]; for (size_t i=0 ; i> m_texResizes; void resizeRenderTexture(ITextureR* tex, size_t width, size_t height) { @@ -654,6 +767,13 @@ ITextureS* MetalDataFactory::newStaticTexture(size_t width, size_t height, size_ static_cast(m_deferredData)->m_STexs.emplace_back(retval); return retval; } +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); + static_cast(m_deferredData)->m_SATexs.emplace_back(retval); + return retval; +} ITextureD* MetalDataFactory::newDynamicTexture(size_t width, size_t height, TextureFormat fmt) { MetalCommandQueue* q = static_cast(m_parent->getCommandQueue()); @@ -676,7 +796,7 @@ IVertexFormat* MetalDataFactory::newVertexFormat(size_t elementCount, const Vert } IShaderPipeline* MetalDataFactory::newShaderPipeline(const char* vertSource, const char* fragSource, - IVertexFormat* vtxFmt, ITextureR* target, + IVertexFormat* vtxFmt, unsigned targetSamples, BlendFactor srcFac, BlendFactor dstFac, bool depthTest, bool depthWrite, bool backfaceCulling) { @@ -699,8 +819,7 @@ IShaderPipeline* MetalDataFactory::newShaderPipeline(const char* vertSource, con NSPtr> fragFunc = [fragShaderLib.get() newFunctionWithName:@"fmain"]; MetalShaderPipeline* retval = new MetalShaderPipeline(m_ctx, vertFunc.get(), fragFunc.get(), - static_cast(vtxFmt), - static_cast(target), + static_cast(vtxFmt), targetSamples, srcFac, dstFac, depthTest, depthWrite, backfaceCulling); static_cast(m_deferredData)->m_SPs.emplace_back(retval); return retval; @@ -709,12 +828,12 @@ IShaderPipeline* MetalDataFactory::newShaderPipeline(const char* vertSource, con IShaderDataBinding* MetalDataFactory::newShaderDataBinding(IShaderPipeline* pipeline, IVertexFormat* vtxFormat, - IGraphicsBuffer* vbuf, IGraphicsBuffer* ibuf, + IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf, size_t ubufCount, IGraphicsBuffer** ubufs, size_t texCount, ITexture** texs) { MetalShaderDataBinding* retval = - new MetalShaderDataBinding(m_ctx, pipeline, vbuf, ibuf, ubufCount, ubufs, texCount, texs); + new MetalShaderDataBinding(m_ctx, pipeline, vbuf, instVbo, ibuf, ubufCount, ubufs, texCount, texs); static_cast(m_deferredData)->m_SBinds.emplace_back(retval); return retval; }