diff --git a/plume_d3d12.cpp b/plume_d3d12.cpp index 2cdcf18..30aae2b 100644 --- a/plume_d3d12.cpp +++ b/plume_d3d12.cpp @@ -2312,7 +2312,13 @@ namespace plume { const D3D12_TEXTURE_COPY_LOCATION copyDstLocation = toD3D12(dstLocation); const D3D12_TEXTURE_COPY_LOCATION copySrcLocation = toD3D12(srcLocation); - setSamplePositions(dstLocation.texture); + + const bool hasDestinationTexture = (dstLocation.texture != nullptr); + + if (hasDestinationTexture) { + setSamplePositions(dstLocation.texture); + } + d3d->CopyTextureRegion(©DstLocation, dstX, dstY, dstZ, ©SrcLocation, (srcBox != nullptr) ? ©Box : nullptr); resetSamplePositions(); } diff --git a/plume_metal.cpp b/plume_metal.cpp index 373c87e..750e569 100644 --- a/plume_metal.cpp +++ b/plume_metal.cpp @@ -3022,6 +3022,37 @@ namespace plume { dstOrigin ); activeBlitEncoder->popDebugGroup(); + } else if (dstLocation.type == RenderTextureCopyType::PLACED_FOOTPRINT && srcLocation.type == RenderTextureCopyType::SUBRESOURCE) { + assert(dstBuffer != nullptr); + assert(srcTexture != nullptr); + + // Calculate block size based on source texture format + const uint32_t blockWidth = RenderFormatBlockWidth(srcTexture->desc.format); + + const MTL::Size size = { dstLocation.placedFootprint.width, dstLocation.placedFootprint.height, dstLocation.placedFootprint.depth }; + + const uint32_t horizontalBlocks = (dstLocation.placedFootprint.rowWidth + blockWidth - 1) / blockWidth; + const uint32_t verticalBlocks = (dstLocation.placedFootprint.height + blockWidth - 1) / blockWidth; + const uint32_t bytesPerRow = horizontalBlocks * RenderFormatSize(srcTexture->desc.format); + const uint32_t bytesPerImage = bytesPerRow * verticalBlocks; + + const MTL::Origin srcOrigin = (srcBox != nullptr) + ? MTL::Origin { NS::UInteger(srcBox->left), NS::UInteger(srcBox->top), NS::UInteger(srcBox->front) } + : MTL::Origin { 0, 0, 0 }; + + activeBlitEncoder->pushDebugGroup(MTLSTR("CopyTextureRegion")); + activeBlitEncoder->copyFromTexture( + srcTexture->mtl, + srcLocation.subresource.arrayIndex, + srcLocation.subresource.mipLevel, + srcOrigin, + size, + dstBuffer->mtl, + dstLocation.placedFootprint.offset, + bytesPerRow, + bytesPerImage + ); + activeBlitEncoder->popDebugGroup(); } else { assert(dstTexture != nullptr); assert(srcTexture != nullptr); diff --git a/plume_vulkan.cpp b/plume_vulkan.cpp index f1dd503..9b9745a 100644 --- a/plume_vulkan.cpp +++ b/plume_vulkan.cpp @@ -3229,6 +3229,27 @@ namespace plume { imageCopy.imageExtent.depth = srcLocation.placedFootprint.depth; vkCmdCopyBufferToImage(vk, srcBuffer->vk, dstTexture->vk, toImageLayout(dstTexture->textureLayout), 1, &imageCopy); } + else if ((dstLocation.type == RenderTextureCopyType::PLACED_FOOTPRINT) && (srcLocation.type == RenderTextureCopyType::SUBRESOURCE)) { + assert(dstBuffer != nullptr); + assert(srcTexture != nullptr); + + const uint32_t blockWidth = RenderFormatBlockWidth(srcTexture->desc.format); + VkBufferImageCopy imageCopy = {}; + imageCopy.bufferOffset = dstLocation.placedFootprint.offset; + imageCopy.bufferRowLength = ((dstLocation.placedFootprint.rowWidth + blockWidth - 1) / blockWidth) * blockWidth; + imageCopy.bufferImageHeight = ((dstLocation.placedFootprint.height + blockWidth - 1) / blockWidth) * blockWidth; + imageCopy.imageSubresource.aspectMask = toAspectFlags(srcTexture->desc.format, srcTexture->desc.flags); + imageCopy.imageSubresource.baseArrayLayer = srcLocation.subresource.arrayIndex; + imageCopy.imageSubresource.layerCount = 1; + imageCopy.imageSubresource.mipLevel = srcLocation.subresource.mipLevel; + imageCopy.imageOffset.x = srcBox != nullptr ? srcBox->left : 0; + imageCopy.imageOffset.y = srcBox != nullptr ? srcBox->top : 0; + imageCopy.imageOffset.z = srcBox != nullptr ? srcBox->front : 0; + imageCopy.imageExtent.width = dstLocation.placedFootprint.width; + imageCopy.imageExtent.height = dstLocation.placedFootprint.height; + imageCopy.imageExtent.depth = dstLocation.placedFootprint.depth; + vkCmdCopyImageToBuffer(vk, srcTexture->vk, toImageLayout(srcTexture->textureLayout), dstBuffer->vk, 1, &imageCopy); + } else { VkImageCopy imageCopy = {}; imageCopy.srcSubresource.aspectMask = toAspectFlags(srcTexture->desc.format, srcTexture->desc.flags);