diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h index 86e56980..a349da28 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h @@ -36,12 +36,12 @@ class MVKBuffer; /** Describes the Metal texture copying parameters. */ typedef struct { - NSUInteger srcLevel; - NSUInteger srcSlice; + uint32_t srcLevel; + uint32_t srcSlice; MTLOrigin srcOrigin; MTLSize srcSize; - NSUInteger dstLevel; - NSUInteger dstSlice; + uint32_t dstLevel; + uint32_t dstSlice; MTLOrigin dstOrigin; } MVKMetalCopyTextureRegion; @@ -81,10 +81,10 @@ protected: /** Describes Metal texture rendering parameters. */ typedef struct { - NSUInteger srcLevel; - NSUInteger srcSlice; - NSUInteger dstLevel; - NSUInteger dstSlice; + uint32_t srcLevel; + uint32_t srcSlice; + uint32_t dstLevel; + uint32_t dstSlice; MVKVertexPosTex vertices[kMVKBlitVertexCount]; } MVKMetalBlitTextureRender; @@ -117,8 +117,8 @@ protected: MTLRenderPassDescriptor* _mtlRenderPassDescriptor; MTLSamplerMinMagFilter _mtlFilter; MTLPixelFormat _mtlPixFmt; + MVKRPSKeyBlitImg _blitKey; std::vector _mtlTexBlitRenders; - bool _isDepthFormat; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 6b0fe1cd..c7fb3407 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -125,9 +125,11 @@ void MVKCmdBlitImage::setContent(VkImage srcImage, _dstLayout = dstImageLayout; _mtlPixFmt = _dstImage->getMTLPixelFormat(); - _isDepthFormat = mvkMTLPixelFormatIsDepthFormat(_mtlPixFmt); _mtlFilter = mvkMTLSamplerMinMagFilterFromVkFilter(filter); + _blitKey.mtlPixFmt = (uint32_t)_mtlPixFmt; + _blitKey.mtlTexType = (uint32_t)_srcImage->getMTLTextureType(); + _commandUse = commandUse; // Determine which regions can be copied and which must be rendered to the destination texture @@ -298,8 +300,11 @@ void MVKCmdBlitImage::encode(MVKCommandEncoder* cmdEncoder) { id dstMTLTex = _dstImage->getMTLTexture(); if ( !srcMTLTex || !dstMTLTex ) { return; } + bool isDepthFormat = _blitKey.isDepthFormat(); + bool isArrayType = _blitKey.isArrayType(); + MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = _mtlRenderPassDescriptor.colorAttachments[0]; - mtlColorAttDesc.texture = _isDepthFormat ? nil : dstMTLTex; + mtlColorAttDesc.texture = isDepthFormat ? nil : dstMTLTex; uint32_t vtxBuffIdx = getDevice()->getMetalBufferIndexForVertexAttributeBinding(kMVKVertexContentBufferIndex); @@ -314,12 +319,18 @@ void MVKCmdBlitImage::encode(MVKCommandEncoder* cmdEncoder) { mtlRendEnc.label = mvkMTLRenderCommandEncoderLabel(_commandUse); [mtlRendEnc pushDebugGroup: @"vkCmdBlitImage"]; - [mtlRendEnc setRenderPipelineState: cmdEncPool->getCmdBlitImageMTLRenderPipelineState(_mtlPixFmt)]; + [mtlRendEnc setRenderPipelineState: cmdEncPool->getCmdBlitImageMTLRenderPipelineState(_blitKey)]; cmdEncoder->setVertexBytes(mtlRendEnc, bltRend.vertices, sizeof(bltRend.vertices), vtxBuffIdx); - if (_isDepthFormat) { - [mtlRendEnc setDepthStencilState: cmdEncPool->getMTLDepthStencilState(_isDepthFormat, false)]; + if (isArrayType) { + cmdEncoder->setFragmentBytes(mtlRendEnc, &bltRend, sizeof(bltRend), 0); + } + if (isDepthFormat) { + [mtlRendEnc setDepthStencilState: cmdEncPool->getMTLDepthStencilState(isDepthFormat, false)]; [mtlRendEnc setVertexTexture: srcMTLTex atIndex: 0]; [mtlRendEnc setVertexSamplerState: cmdEncPool->getCmdBlitImageMTLSamplerState(_mtlFilter) atIndex: 0]; + if (isArrayType) { + cmdEncoder->setVertexBytes(mtlRendEnc, &bltRend, sizeof(bltRend), 0); + } } else { [mtlRendEnc setFragmentTexture: srcMTLTex atIndex: 0]; [mtlRendEnc setFragmentSamplerState: cmdEncPool->getCmdBlitImageMTLSamplerState(_mtlFilter) atIndex: 0]; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h index 613f66b1..705e9617 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h @@ -43,11 +43,8 @@ public: #pragma mark Command resources - /** - * Returns a MTLRenderPipelineState dedicated to rendering to a texture - * in the specified pixel format to support certain Vulkan BLIT commands. - */ - id getCmdBlitImageMTLRenderPipelineState(MTLPixelFormat mtlPixFmt); + /** Returns a MTLRenderPipelineState to support certain Vulkan BLIT commands. */ + id getCmdBlitImageMTLRenderPipelineState(MVKRPSKeyBlitImg& blitKey); /** * Returns a MTLSamplerState dedicated to rendering to a texture using the @@ -110,7 +107,7 @@ private: void initTextureDeviceMemory(); void destroyMetalResources(); - std::unordered_map> _cmdBlitImageMTLRenderPipelineStates; + std::unordered_map> _cmdBlitImageMTLRenderPipelineStates; std::unordered_map> _cmdClearMTLRenderPipelineStates; std::unordered_map> _mtlDepthStencilStates; std::unordered_map _transferImages; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm index 2a07854c..bfe070ae 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm @@ -33,11 +33,11 @@ id MVKCommandEncodingPool::getCmdClearMTLRenderPipelineS return rps; } -id MVKCommandEncodingPool::getCmdBlitImageMTLRenderPipelineState(MTLPixelFormat mtlPixFmt) { - id rps = _cmdBlitImageMTLRenderPipelineStates[mtlPixFmt]; +id MVKCommandEncodingPool::getCmdBlitImageMTLRenderPipelineState(MVKRPSKeyBlitImg& blitKey) { + id rps = _cmdBlitImageMTLRenderPipelineStates[blitKey]; if ( !rps ) { - rps = _device->getCommandResourceFactory()->newCmdBlitImageMTLRenderPipelineState(mtlPixFmt); // retained - _cmdBlitImageMTLRenderPipelineStates[mtlPixFmt] = rps; + rps = _device->getCommandResourceFactory()->newCmdBlitImageMTLRenderPipelineState(blitKey); // retained + _cmdBlitImageMTLRenderPipelineStates[blitKey] = rps; } return rps; } diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h b/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h index c7233f3a..26e5381d 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h @@ -28,7 +28,7 @@ typedef struct { } AttributesPos; \n\ \n\ typedef struct { \n\ - float4 gl_Position [[position]]; \n\ + float4 v_position [[position]]; \n\ } VaryingsPos; \n\ \n\ typedef struct { \n\ @@ -37,23 +37,40 @@ typedef struct { } AttributesPosTex; \n\ \n\ typedef struct { \n\ - float4 gl_Position [[position]]; \n\ + float4 v_position [[position]]; \n\ float2 v_texCoord; \n\ } VaryingsPosTex; \n\ \n\ +typedef struct { \n\ + uint srcLevel; \n\ + uint srcSlice; \n\ + uint dstLevel; \n\ + uint dstSlice; \n\ +} BlitInfo; \n\ + \n\ vertex VaryingsPosTex vtxCmdBlitImage(AttributesPosTex attributes [[stage_in]]) { \n\ VaryingsPosTex varyings; \n\ - varyings.gl_Position = float4(attributes.a_position, 0.0, 1.0); \n\ + varyings.v_position = float4(attributes.a_position, 0.0, 1.0); \n\ varyings.v_texCoord = attributes.a_texCoord; \n\ return varyings; \n\ } \n\ \n\ vertex VaryingsPos vtxCmdBlitImageD(AttributesPosTex attributes [[stage_in]], \n\ depth2d texture [[texture(0)]], \n\ - sampler sampler [[ sampler(0) ]]) { \n\ + sampler sampler [[sampler(0)]]) { \n\ float depth = texture.sample(sampler, attributes.a_texCoord); \n\ VaryingsPos varyings; \n\ - varyings.gl_Position = float4(attributes.a_position, depth, 1.0); \n\ + varyings.v_position = float4(attributes.a_position, depth, 1.0); \n\ + return varyings; \n\ +} \n\ + \n\ +vertex VaryingsPos vtxCmdBlitImageDA(AttributesPosTex attributes [[stage_in]], \n\ + depth2d_array texture [[texture(0)]], \n\ + sampler sampler [[sampler(0)]], \n\ + constant BlitInfo& blitInfo [[buffer(0)]]) { \n\ + float depth = texture.sample(sampler, attributes.a_texCoord, blitInfo.srcSlice); \n\ + VaryingsPos varyings; \n\ + varyings.v_position = float4(attributes.a_position, depth, 1.0); \n\ return varyings; \n\ } \n\ \n\ @@ -64,7 +81,7 @@ typedef struct { vertex VaryingsPos vtxCmdClearAttachments(AttributesPos attributes [[stage_in]], \n\ constant ClearColorsIn& ccIn [[buffer(0)]]) { \n\ VaryingsPos varyings; \n\ - varyings.gl_Position = float4(attributes.a_position.x, -attributes.a_position.y, ccIn.colors[8].r, 1.0); \n\ + varyings.v_position = float4(attributes.a_position.x, -attributes.a_position.y, ccIn.colors[8].r, 1.0); \n\ return varyings; \n\ } \n\ \n\ diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h index d18bb13f..fc81e18a 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h @@ -26,6 +26,51 @@ #import +#pragma mark - +#pragma mark MVKRPSKeyBlitImg + +/** + * Key to use for looking up cached MTLRenderPipelineState instances based on MTLPixelFormat and MTLTextureType. + * + * This structure can be used as a key in a std::map and std::unordered_map. + */ +typedef struct MVKRPSKeyBlitImg_t { + uint16_t mtlPixFmt = 0; /**< MTLPixelFormat */ + uint16_t mtlTexType = 0; /**< MTLTextureType */ + + bool operator==(const MVKRPSKeyBlitImg_t& rhs) const { + return ((mtlPixFmt == rhs.mtlPixFmt) && (mtlTexType == rhs.mtlTexType)); + } + + inline MTLPixelFormat getMTLPixelFormat() { return (MTLPixelFormat)mtlPixFmt; } + + inline bool isDepthFormat() { return mvkMTLPixelFormatIsDepthFormat(getMTLPixelFormat()); } + + inline MTLTextureType getMTLTextureType() { return (MTLTextureType)mtlTexType; } + + inline bool isArrayType() { return (mtlTexType == MTLTextureType2DArray) || (mtlTexType == MTLTextureType1DArray); } + + std::size_t hash() const { + std::size_t hash = mtlTexType; + hash <<= 16; + hash |= mtlPixFmt; + return hash; + } + +} MVKRPSKeyBlitImg; + +/** + * Hash structure implementation for MVKRPSKeyBlitImg in std namespace, + * so MVKRPSKeyBlitImg can be used as a key in a std::map and std::unordered_map. + */ +namespace std { + template <> + struct hash { + std::size_t operator()(const MVKRPSKeyBlitImg& k) const { return k.hash(); } + }; +} + + #pragma mark - #pragma mark MVKRPSKeyClearAtt @@ -226,11 +271,8 @@ public: #pragma mark Command resources - /** - * Returns a new MTLRenderPipelineState dedicated to rendering to a texture - * in the specified pixel format to support certain Vulkan BLIT commands. - */ - id newCmdBlitImageMTLRenderPipelineState(MTLPixelFormat mtlPixFmt); + /** Returns a new MTLRenderPipelineState to support certain Vulkan BLIT commands. */ + id newCmdBlitImageMTLRenderPipelineState(MVKRPSKeyBlitImg& blitKey); /** * Returns a new MTLSamplerState dedicated to rendering to a texture using the @@ -281,7 +323,7 @@ public: protected: void initMTLLibrary(); - id getBlitFragFunction(MTLPixelFormat mtlPixFmt); + id getBlitFragFunction(MVKRPSKeyBlitImg& blitKey); id getClearFragFunction(MVKRPSKeyClearAtt& attKey); NSString* getMTLFormatTypeString(MTLPixelFormat mtlPixFmt); id getFunctionNamed(const char* funcName); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm index ce1fdc3c..9e5bc7d1 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm @@ -20,7 +20,6 @@ #include "MVKCommandPipelineStateFactoryShaderSource.h" #include "MVKPipeline.h" #include "MVKFoundation.h" -#include "mvk_datatypes.h" #include "NSString+MoltenVK.h" #include "MVKLogging.h" @@ -30,19 +29,20 @@ using namespace std; #pragma mark - #pragma mark MVKCommandResourceFactory -id MVKCommandResourceFactory::newCmdBlitImageMTLRenderPipelineState(MTLPixelFormat mtlPixFmt) { - bool isDepthFormat = mvkMTLPixelFormatIsDepthFormat(mtlPixFmt); +id MVKCommandResourceFactory::newCmdBlitImageMTLRenderPipelineState(MVKRPSKeyBlitImg& blitKey) { + bool isDepthFormat = blitKey.isDepthFormat(); + bool isArrayType = blitKey.isArrayType(); MTLRenderPipelineDescriptor* plDesc = [[[MTLRenderPipelineDescriptor alloc] init] autorelease]; plDesc.label = [NSString stringWithFormat: @"CmdBlitImage"]; - plDesc.vertexFunction = getFunctionNamed(isDepthFormat ? "vtxCmdBlitImageD" : "vtxCmdBlitImage"); - plDesc.fragmentFunction = getBlitFragFunction(mtlPixFmt); + plDesc.vertexFunction = getFunctionNamed(isDepthFormat ? (isArrayType ? "vtxCmdBlitImageDA" : "vtxCmdBlitImageD") : "vtxCmdBlitImage"); + plDesc.fragmentFunction = getBlitFragFunction(blitKey); if (isDepthFormat) { - plDesc.depthAttachmentPixelFormat = mtlPixFmt; + plDesc.depthAttachmentPixelFormat = blitKey.getMTLPixelFormat(); } else { - plDesc.colorAttachments[0].pixelFormat = mtlPixFmt; + plDesc.colorAttachments[0].pixelFormat = blitKey.getMTLPixelFormat(); } MTLVertexDescriptor* vtxDesc = plDesc.vertexDescriptor; @@ -131,10 +131,15 @@ id MVKCommandResourceFactory::newCmdClearMTLRenderPipeli return newMTLRenderPipelineState(plDesc); } -id MVKCommandResourceFactory::getBlitFragFunction(MTLPixelFormat mtlPixFmt) { +id MVKCommandResourceFactory::getBlitFragFunction(MVKRPSKeyBlitImg& blitKey) { id mtlFunc = nil; - bool isDepthFormat = mvkMTLPixelFormatIsDepthFormat(mtlPixFmt); - NSString* typeStr = getMTLFormatTypeString(mtlPixFmt); + + bool isDepthFormat = blitKey.isDepthFormat(); + NSString* typeStr = getMTLFormatTypeString(blitKey.getMTLPixelFormat()); + + bool isArrayType = blitKey.isArrayType(); + NSString* arraySuffix = isArrayType ? @"_array" : @""; + NSString* sliceArg = isArrayType ? @", blitInfo.srcSlice" : @""; @autoreleasepool { NSMutableString* msl = [NSMutableString stringWithCapacity: (2 * KIBI) ]; @@ -142,27 +147,41 @@ id MVKCommandResourceFactory::getBlitFragFunction(MTLPixelFormat mt [msl appendLineMVK: @"using namespace metal;"]; [msl appendLineMVK]; [msl appendLineMVK: @"typedef struct {"]; - [msl appendLineMVK: @" float4 gl_Position [[position]];"]; + [msl appendLineMVK: @" float4 v_position [[position]];"]; [msl appendLineMVK: @" float2 v_texCoord;"]; [msl appendLineMVK: @"} VaryingsPosTex;"]; [msl appendLineMVK]; + if (isArrayType) { + [msl appendLineMVK: @"typedef struct {"]; + [msl appendLineMVK: @" uint srcLevel;"]; + [msl appendLineMVK: @" uint srcSlice;"]; + [msl appendLineMVK: @" uint dstLevel;"]; + [msl appendLineMVK: @" uint dstSlice;"]; + [msl appendLineMVK: @"} BlitInfo;"]; + [msl appendLineMVK]; + } NSString* funcName = @"fragBlit"; [msl appendFormat: @"fragment %@4 %@(VaryingsPosTex varyings [[stage_in]],", typeStr, funcName]; [msl appendLineMVK]; if (isDepthFormat) { - [msl appendLineMVK: @" depth2d texture [[texture(0)]],"]; + [msl appendFormat: @" depth2d%@ texture [[texture(0)]],", arraySuffix]; } else { - [msl appendFormat: @" texture2d<%@> texture [[texture(0)]],", typeStr]; - [msl appendLineMVK]; + [msl appendFormat: @" texture2d%@<%@> texture [[texture(0)]],", arraySuffix, typeStr]; + } + [msl appendLineMVK]; + if (isArrayType) { + [msl appendLineMVK: @" sampler sampler [[sampler(0)]],"]; + [msl appendLineMVK: @" constant BlitInfo& blitInfo [[buffer(0)]]) {"]; + } else { + [msl appendLineMVK: @" sampler sampler [[sampler(0)]]) {"]; } - [msl appendLineMVK: @" sampler sampler [[ sampler(0) ]]) {"]; if (isDepthFormat) { - [msl appendFormat: @" return %@4(texture.sample(sampler, varyings.v_texCoord));", typeStr]; - [msl appendLineMVK]; + [msl appendFormat: @" return %@4(texture.sample(sampler, varyings.v_texCoord)%@);", typeStr, sliceArg]; } else { - [msl appendLineMVK: @" return texture.sample(sampler, varyings.v_texCoord);"]; + [msl appendFormat: @" return texture.sample(sampler, varyings.v_texCoord%@);", sliceArg]; } + [msl appendLineMVK]; [msl appendLineMVK: @"}"]; mtlFunc = newMTLFunction(msl, funcName); @@ -179,7 +198,7 @@ id MVKCommandResourceFactory::getClearFragFunction(MVKRPSKeyClearAt [msl appendLineMVK: @"using namespace metal;"]; [msl appendLineMVK]; [msl appendLineMVK: @"typedef struct {"]; - [msl appendLineMVK: @" float4 gl_Position [[position]];"]; + [msl appendLineMVK: @" float4 v_position [[position]];"]; [msl appendLineMVK: @"} VaryingsPos;"]; [msl appendLineMVK]; [msl appendLineMVK: @"typedef struct {"]; diff --git a/MoltenVK/MoltenVK/Utility/MVKWatermarkShaderSource.h b/MoltenVK/MoltenVK/Utility/MVKWatermarkShaderSource.h index fc4a2b72..31029e5c 100644 --- a/MoltenVK/MoltenVK/Utility/MVKWatermarkShaderSource.h +++ b/MoltenVK/MoltenVK/Utility/MVKWatermarkShaderSource.h @@ -36,7 +36,7 @@ typedef struct { \n\ } Attributes; \n\ \n\ typedef struct { \n\ - float4 gl_Position [[position]]; \n\ + float4 v_position [[position]]; \n\ float2 v_texCoord; \n\ float4 v_fragColor; \n\ } Varyings; \n\ @@ -44,7 +44,7 @@ typedef struct { \n\ vertex Varyings watermarkVertex(Attributes attributes [[stage_in]], \n\ constant Uniforms& uniforms [[ buffer(0) ]]) { \n\ Varyings varyings; \n\ - varyings.gl_Position = uniforms.mvpMtx * float4(attributes.a_position, 0.0, 1.0); \n\ + varyings.v_position = uniforms.mvpMtx * float4(attributes.a_position, 0.0, 1.0); \n\ varyings.v_fragColor = uniforms.color; \n\ varyings.v_texCoord = attributes.a_texCoord; \n\ return varyings; \n\