Merge pull request #1035 from cdavis5e/3d-blits
MVKCmdBlitImage: Support blits with non-2D images.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index e4e641d..42ae92b 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -428,6 +428,18 @@
MVKRPSKeyBlitImg blitKey;
blitKey.srcMTLPixelFormat = _srcImage->getMTLPixelFormat(srcPlaneIndex);
blitKey.srcMTLTextureType = _srcImage->getMTLTextureType();
+ if (blitKey.srcMTLTextureType == MTLTextureTypeCube || blitKey.srcMTLTextureType == MTLTextureTypeCubeArray) {
+ // In this case, I'll use a temp 2D array view. That way, I don't have to
+ // deal with mapping the blit coordinates to a cube direction vector.
+ blitKey.srcMTLTextureType = MTLTextureType2DArray;
+ srcMTLTex = [srcMTLTex newTextureViewWithPixelFormat: (MTLPixelFormat)blitKey.srcMTLPixelFormat
+ textureType: MTLTextureType2DArray
+ levels: NSMakeRange(0, srcMTLTex.mipmapLevelCount)
+ slices: NSMakeRange(0, srcMTLTex.arrayLength)];
+ [cmdEncoder->_mtlCmdBuffer addCompletedHandler: ^(id<MTLCommandBuffer>) {
+ [srcMTLTex release];
+ }];
+ }
blitKey.dstMTLPixelFormat = _dstImage->getMTLPixelFormat(dstPlaneIndex);
blitKey.srcFilter = mvkMTLSamplerMinMagFilterFromVkFilter(_filter);
blitKey.dstSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_dstImage->getSampleCount());
@@ -438,12 +450,31 @@
mtlColorAttDesc.level = mvkIBR.region.dstSubresource.mipLevel;
uint32_t layCnt = mvkIBR.region.srcSubresource.layerCount;
+ if (_dstImage->getMTLTextureType() == MTLTextureType3D) {
+ layCnt = mvkAbsDiff(mvkIBR.region.dstOffsets[1].z, mvkIBR.region.dstOffsets[0].z);
+ }
for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
// Update the render pass descriptor for the texture level and slice, and create a render encoder.
- mtlColorAttDesc.slice = mvkIBR.region.dstSubresource.baseArrayLayer + layIdx;
+ if (_dstImage->getMTLTextureType() == MTLTextureType3D) {
+ mtlColorAttDesc.depthPlane = mvkIBR.region.dstOffsets[0].z + (mvkIBR.region.dstOffsets[1].z > mvkIBR.region.dstOffsets[0].z ? layIdx : -(layIdx + 1));
+ } else {
+ mtlColorAttDesc.slice = mvkIBR.region.dstSubresource.baseArrayLayer + layIdx;
+ }
id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPD];
setLabelIfNotNil(mtlRendEnc, mvkMTLRenderCommandEncoderLabel(commandUse));
+ if (blitKey.srcMTLTextureType == MTLTextureType3D) {
+ // In this case, I need to interpolate along the third dimension manually.
+ VkExtent3D srcExtent = _srcImage->getExtent3D(srcPlaneIndex, mvkIBR.region.dstSubresource.mipLevel);
+ VkOffset3D so0 = mvkIBR.region.srcOffsets[0], so1 = mvkIBR.region.srcOffsets[1];
+ VkOffset3D do0 = mvkIBR.region.dstOffsets[0], do1 = mvkIBR.region.dstOffsets[1];
+ CGFloat startZ = (CGFloat)so0.z / (CGFloat)srcExtent.depth;
+ CGFloat endZ = (CGFloat)so1.z / (CGFloat)srcExtent.depth;
+ CGFloat zIncr = (endZ - startZ) / mvkAbsDiff(do1.z, do0.z);
+ for (uint32_t i = 0; i < kMVKBlitVertexCount; ++i) {
+ mvkIBR.vertices[i].texCoord.z = startZ + layIdx * zIncr;
+ }
+ }
[mtlRendEnc pushDebugGroup: @"vkCmdBlitImage"];
[mtlRendEnc setRenderPipelineState: mtlRPS];
cmdEncoder->setVertexBytes(mtlRendEnc, mvkIBR.vertices, sizeof(mvkIBR.vertices), vtxBuffIdx);
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h b/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h
index 68e60d7..d562183 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h
@@ -29,12 +29,12 @@
\n\
typedef struct { \n\
float2 a_position [[attribute(0)]]; \n\
- float2 a_texCoord [[attribute(1)]]; \n\
+ float3 a_texCoord [[attribute(1)]]; \n\
} AttributesPosTex; \n\
\n\
typedef struct { \n\
float4 v_position [[position]]; \n\
- float2 v_texCoord; \n\
+ float3 v_texCoord; \n\
} VaryingsPosTex; \n\
\n\
typedef size_t VkDeviceSize; \n\
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
index 7006fe4..1e5d460 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
@@ -58,6 +58,8 @@
inline MTLSamplerMinMagFilter getSrcMTLSamplerMinMagFilter() { return (MTLSamplerMinMagFilter)srcFilter; }
+ inline MTLTextureType getSrcMTLTextureType() { return (MTLTextureType)srcMTLTextureType; }
+
inline bool isSrcArrayType() {
return (srcMTLTextureType == MTLTextureType2DArray ||
#if MVK_MACOS
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
index 751fb18..51640ae 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
@@ -57,14 +57,14 @@
vaDesc.format = MTLVertexFormatFloat2;
vaDesc.bufferIndex = vtxBuffIdx;
vaDesc.offset = vtxStride;
- vtxStride += sizeof(simd::float2);
+ vtxStride += sizeof(simd::float4);
// Vertex texture coords
vaDesc = vaDescArray[1];
- vaDesc.format = MTLVertexFormatFloat2;
+ vaDesc.format = MTLVertexFormatFloat3;
vaDesc.bufferIndex = vtxBuffIdx;
vaDesc.offset = vtxStride;
- vtxStride += sizeof(simd::float2);
+ vtxStride += sizeof(simd::float4);
// Vertex attribute buffer.
MTLVertexBufferLayoutDescriptorArray* vbDescArray = vtxDesc.layouts;
@@ -158,7 +158,34 @@
bool isArrayType = blitKey.isSrcArrayType();
bool isLinearFilter = (blitKey.getSrcMTLSamplerMinMagFilter() == MTLSamplerMinMagFilterLinear);
- NSString* arraySuffix = isArrayType ? @"_array" : @"";
+ NSString* typeSuffix;
+ NSString* coordArg;
+ switch (blitKey.getSrcMTLTextureType()) {
+ case MTLTextureType1D:
+ typeSuffix = @"1d";
+ coordArg = @".x";
+ break;
+ case MTLTextureType1DArray:
+ typeSuffix = @"1d_array";
+ coordArg = @".x";
+ break;
+ case MTLTextureType2D:
+ typeSuffix = @"2d";
+ coordArg = @".xy";
+ break;
+ case MTLTextureType2DArray:
+ typeSuffix = @"2d_array";
+ coordArg = @".xy";
+ break;
+ case MTLTextureType3D:
+ typeSuffix = @"3d";
+ coordArg = @"";
+ break;
+ default:
+ typeSuffix = @"unsupported";
+ coordArg = @"";
+ break;
+ }
NSString* sliceArg = isArrayType ? @", subRez.slice" : @"";
NSString* srcFilter = isLinearFilter ? @"linear" : @"nearest";
@@ -168,7 +195,7 @@
[msl appendLineMVK];
[msl appendLineMVK: @"typedef struct {"];
[msl appendLineMVK: @" float4 v_position [[position]];"];
- [msl appendLineMVK: @" float2 v_texCoord;"];
+ [msl appendLineMVK: @" float3 v_texCoord;"];
[msl appendLineMVK: @"} VaryingsPosTex;"];
[msl appendLineMVK];
[msl appendLineMVK: @"typedef struct {"];
@@ -183,10 +210,10 @@
NSString* funcName = @"fragCmdBlitImage";
[msl appendFormat: @"fragment %@4 %@(VaryingsPosTex varyings [[stage_in]],", typeStr, funcName];
[msl appendLineMVK];
- [msl appendFormat: @" texture2d%@<%@> tex [[texture(0)]],", arraySuffix, typeStr];
+ [msl appendFormat: @" texture%@<%@> tex [[texture(0)]],", typeSuffix, typeStr];
[msl appendLineMVK];
[msl appendLineMVK: @" constant TexSubrez& subRez [[buffer(0)]]) {"];
- [msl appendFormat: @" return tex.sample(ce_sampler, varyings.v_texCoord%@, level(subRez.lod));", sliceArg];
+ [msl appendFormat: @" return tex.sample(ce_sampler, varyings.v_texCoord%@%@, level(subRez.lod));", coordArg, sliceArg];
[msl appendLineMVK];
[msl appendLineMVK: @"}"];
diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
index c4095dd..3ce5714 100644
--- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h
+++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
@@ -53,7 +53,7 @@
/** 2D vertex position and texcoord content. */
typedef struct {
simd::float2 position;
- simd::float2 texCoord;
+ simd::float3 texCoord;
} MVKVertexPosTex;
@@ -375,6 +375,12 @@
}
};
+/** Returns the absolute value of the difference of two numbers. */
+template<typename T, typename U>
+constexpr typename std::common_type<T, U>::type mvkAbsDiff(T x, U y) {
+ return x >= y ? x - y : y - x;
+}
+
/** Returns the greatest common divisor of two numbers. */
template<typename T>
constexpr T mvkGreatestCommonDivisorImpl(T a, T b) {