VK_EXT_host_image_copy: On discrete GPUs, sync managed-memory textures before copying.
Discrete GPUs use managed-memory textures, and these need to be synchronized from GPU memory before being available for host-copying to memory using the CPU. Metal automatically handles the reverse sync when copying from memory to a texture.
This commit is contained in:
parent
2290e86cd9
commit
b6735878f3
@ -256,11 +256,14 @@ public:
|
|||||||
/** Flush underlying buffer memory into the image if necessary */
|
/** Flush underlying buffer memory into the image if necessary */
|
||||||
void flushToDevice(VkDeviceSize offset, VkDeviceSize size);
|
void flushToDevice(VkDeviceSize offset, VkDeviceSize size);
|
||||||
|
|
||||||
/** Host-copy the content of this image to or from memory using the CPU. */
|
/** Host-copy the content of an image to another using the CPU. */
|
||||||
template<typename CopyInfo> VkResult copyContent(const CopyInfo* pCopyInfo);
|
static VkResult copyImageToImage(const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo);
|
||||||
|
|
||||||
/** Host-copy the content of one image to another using the CPU. */
|
/** Host-copy the content of an image to memory using the CPU. */
|
||||||
static VkResult copyContent(const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo);
|
VkResult copyImageToMemory(const VkCopyImageToMemoryInfoEXT* pCopyImageToMemoryInfo);
|
||||||
|
|
||||||
|
/** Host-copy the content of an image from memory using the CPU. */
|
||||||
|
VkResult copyMemoryToImage(const VkCopyMemoryToImageInfoEXT* pCopyMemoryToImageInfo);
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Metal
|
#pragma mark Metal
|
||||||
@ -359,6 +362,7 @@ protected:
|
|||||||
uint8_t getMemoryBindingCount() const { return (uint8_t)_memoryBindings.size(); }
|
uint8_t getMemoryBindingCount() const { return (uint8_t)_memoryBindings.size(); }
|
||||||
uint8_t getMemoryBindingIndex(uint8_t planeIndex) const;
|
uint8_t getMemoryBindingIndex(uint8_t planeIndex) const;
|
||||||
MVKImageMemoryBinding* getMemoryBinding(uint8_t planeIndex);
|
MVKImageMemoryBinding* getMemoryBinding(uint8_t planeIndex);
|
||||||
|
template<typename CopyInfo> VkResult copyContent(const CopyInfo* pCopyInfo);
|
||||||
VkResult copyContent(id<MTLTexture> mtlTex,
|
VkResult copyContent(id<MTLTexture> mtlTex,
|
||||||
VkMemoryToImageCopyEXT imgRgn, uint32_t mipLevel, uint32_t slice,
|
VkMemoryToImageCopyEXT imgRgn, uint32_t mipLevel, uint32_t slice,
|
||||||
void* pImgBytes, size_t rowPitch, size_t depthPitch);
|
void* pImgBytes, size_t rowPitch, size_t depthPitch);
|
||||||
|
@ -566,7 +566,7 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
|
|||||||
return { mvkMTLOriginFromVkOffset3D(imgRgn.imageOffset), mvkMTLSizeFromVkExtent3D(imgRgn.imageExtent) };
|
return { mvkMTLOriginFromVkOffset3D(imgRgn.imageOffset), mvkMTLSizeFromVkExtent3D(imgRgn.imageExtent) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Host-copy from memory to a MTLTexture.
|
// Host-copy from a MTLTexture to memory.
|
||||||
VkResult MVKImage::copyContent(id<MTLTexture> mtlTex,
|
VkResult MVKImage::copyContent(id<MTLTexture> mtlTex,
|
||||||
VkImageToMemoryCopyEXT imgRgn, uint32_t mipLevel, uint32_t slice,
|
VkImageToMemoryCopyEXT imgRgn, uint32_t mipLevel, uint32_t slice,
|
||||||
void* pImgBytes, size_t rowPitch, size_t depthPitch) {
|
void* pImgBytes, size_t rowPitch, size_t depthPitch) {
|
||||||
@ -579,7 +579,7 @@ VkResult MVKImage::copyContent(id<MTLTexture> mtlTex,
|
|||||||
return VK_SUCCESS;
|
return VK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Host-copy from a MTLTexture to memory.
|
// Host-copy from memory to a MTLTexture.
|
||||||
VkResult MVKImage::copyContent(id<MTLTexture> mtlTex,
|
VkResult MVKImage::copyContent(id<MTLTexture> mtlTex,
|
||||||
VkMemoryToImageCopyEXT imgRgn, uint32_t mipLevel, uint32_t slice,
|
VkMemoryToImageCopyEXT imgRgn, uint32_t mipLevel, uint32_t slice,
|
||||||
void* pImgBytes, size_t rowPitch, size_t depthPitch) {
|
void* pImgBytes, size_t rowPitch, size_t depthPitch) {
|
||||||
@ -646,14 +646,9 @@ VkResult MVKImage::copyContent(const CopyInfo* pCopyInfo) {
|
|||||||
return VK_SUCCESS;
|
return VK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create concrete implementations of the variations of the copyContent() template function.
|
|
||||||
// This is required since the template is called from outside this file (compilation unit).
|
|
||||||
template VkResult MVKImage::copyContent(const VkCopyMemoryToImageInfoEXT* pCopyInfo);
|
|
||||||
template VkResult MVKImage::copyContent(const VkCopyImageToMemoryInfoEXT* pCopyInfo);
|
|
||||||
|
|
||||||
// Host-copy content between images by allocating a temporary memory buffer, copying into it from the
|
// Host-copy content between images by allocating a temporary memory buffer, copying into it from the
|
||||||
// source image, and then copying from the memory buffer into the destination image, all using the CPU.
|
// source image, and then copying from the memory buffer into the destination image, all using the CPU.
|
||||||
VkResult MVKImage::copyContent(const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo) {
|
VkResult MVKImage::copyImageToImage(const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo) {
|
||||||
for (uint32_t imgRgnIdx = 0; imgRgnIdx < pCopyImageToImageInfo->regionCount; imgRgnIdx++) {
|
for (uint32_t imgRgnIdx = 0; imgRgnIdx < pCopyImageToImageInfo->regionCount; imgRgnIdx++) {
|
||||||
auto& imgRgn = pCopyImageToImageInfo->pRegions[imgRgnIdx];
|
auto& imgRgn = pCopyImageToImageInfo->pRegions[imgRgnIdx];
|
||||||
|
|
||||||
@ -716,6 +711,40 @@ VkResult MVKImage::copyContent(const VkCopyImageToImageInfoEXT* pCopyImageToImag
|
|||||||
return VK_SUCCESS;
|
return VK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkResult MVKImage::copyImageToMemory(const VkCopyImageToMemoryInfoEXT* pCopyImageToMemoryInfo) {
|
||||||
|
#if MVK_MACOS
|
||||||
|
// On macOS, if the device doesn't have unified memory, and the texture is using managed memory, we need
|
||||||
|
// to sync the managed memory from the GPU, so the texture content is accessible to be copied by the CPU.
|
||||||
|
if ( !getPhysicalDevice()->getHasUnifiedMemory() && getMTLStorageMode() == MTLStorageModeManaged ) {
|
||||||
|
@autoreleasepool {
|
||||||
|
id<MTLCommandBuffer> mtlCmdBuff = getDevice()->getAnyQueue()->getMTLCommandBuffer(kMVKCommandUseCopyImageToMemory);
|
||||||
|
id<MTLBlitCommandEncoder> mtlBlitEnc = [mtlCmdBuff blitCommandEncoder];
|
||||||
|
|
||||||
|
for (uint32_t imgRgnIdx = 0; imgRgnIdx < pCopyImageToMemoryInfo->regionCount; imgRgnIdx++) {
|
||||||
|
auto& imgRgn = pCopyImageToMemoryInfo->pRegions[imgRgnIdx];
|
||||||
|
auto& imgSubRez = imgRgn.imageSubresource;
|
||||||
|
id<MTLTexture> mtlTex = getMTLTexture(getPlaneFromVkImageAspectFlags(imgSubRez.aspectMask));
|
||||||
|
for (uint32_t imgLyrIdx = 0; imgLyrIdx < imgSubRez.layerCount; imgLyrIdx++) {
|
||||||
|
[mtlBlitEnc synchronizeTexture: mtlTex
|
||||||
|
slice: imgSubRez.baseArrayLayer + imgLyrIdx
|
||||||
|
level: imgSubRez.mipLevel];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[mtlBlitEnc endEncoding];
|
||||||
|
[mtlCmdBuff commit];
|
||||||
|
[mtlCmdBuff waitUntilCompleted];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return copyContent(pCopyImageToMemoryInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult MVKImage::copyMemoryToImage(const VkCopyMemoryToImageInfoEXT* pCopyMemoryToImageInfo) {
|
||||||
|
return copyContent(pCopyMemoryToImageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
VkImageType MVKImage::getImageType() { return mvkVkImageTypeFromMTLTextureType(_mtlTextureType); }
|
VkImageType MVKImage::getImageType() { return mvkVkImageTypeFromMTLTextureType(_mtlTextureType); }
|
||||||
|
|
||||||
bool MVKImage::getIsDepthStencil() { return getPixelFormats()->getFormatType(_vkFormat) == kMVKFormatDepthStencil; }
|
bool MVKImage::getIsDepthStencil() { return getPixelFormats()->getFormatType(_vkFormat) == kMVKFormatDepthStencil; }
|
||||||
@ -823,21 +852,22 @@ void MVKImage::applyImageMemoryBarrier(MVKPipelineBarrier& barrier,
|
|||||||
}
|
}
|
||||||
|
|
||||||
VkResult MVKImage::getMemoryRequirements(VkMemoryRequirements* pMemoryRequirements, uint8_t planeIndex) {
|
VkResult MVKImage::getMemoryRequirements(VkMemoryRequirements* pMemoryRequirements, uint8_t planeIndex) {
|
||||||
|
MVKPhysicalDevice* mvkPD = getPhysicalDevice();
|
||||||
|
VkImageUsageFlags combinedUsage = getCombinedUsage();
|
||||||
|
|
||||||
pMemoryRequirements->memoryTypeBits = (_isDepthStencilAttachment)
|
pMemoryRequirements->memoryTypeBits = (_isDepthStencilAttachment)
|
||||||
? getPhysicalDevice()->getPrivateMemoryTypes()
|
? mvkPD->getPrivateMemoryTypes()
|
||||||
: getPhysicalDevice()->getAllMemoryTypes();
|
: mvkPD->getAllMemoryTypes();
|
||||||
#if MVK_MACOS
|
#if MVK_MACOS
|
||||||
// Metal on macOS does not provide native support for host-coherent memory, but Vulkan requires it for Linear images
|
// Metal on macOS does not provide native support for host-coherent memory, but Vulkan requires it for Linear images
|
||||||
if ( !_isLinear ) {
|
if ( !_isLinear ) {
|
||||||
mvkDisableFlags(pMemoryRequirements->memoryTypeBits, getPhysicalDevice()->getHostCoherentMemoryTypes());
|
mvkDisableFlags(pMemoryRequirements->memoryTypeBits, mvkPD->getHostCoherentMemoryTypes());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VkImageUsageFlags combinedUsage = getCombinedUsage();
|
|
||||||
|
|
||||||
// If the image can be used in a host-copy transfer, the memory cannot be private.
|
// If the image can be used in a host-copy transfer, the memory cannot be private.
|
||||||
if (mvkIsAnyFlagEnabled(combinedUsage, VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT)) {
|
if (mvkIsAnyFlagEnabled(combinedUsage, VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT)) {
|
||||||
mvkDisableFlags(pMemoryRequirements->memoryTypeBits, getPhysicalDevice()->getPrivateMemoryTypes());
|
mvkDisableFlags(pMemoryRequirements->memoryTypeBits, mvkPD->getPrivateMemoryTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only transient attachments may use memoryless storage.
|
// Only transient attachments may use memoryless storage.
|
||||||
@ -845,7 +875,7 @@ VkResult MVKImage::getMemoryRequirements(VkMemoryRequirements* pMemoryRequiremen
|
|||||||
// TODO: support framebuffer fetch so VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT uses color(m) in shader instead of setFragmentTexture:, which crashes Metal
|
// TODO: support framebuffer fetch so VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT uses color(m) in shader instead of setFragmentTexture:, which crashes Metal
|
||||||
if (!mvkIsAnyFlagEnabled(combinedUsage, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) ||
|
if (!mvkIsAnyFlagEnabled(combinedUsage, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) ||
|
||||||
mvkIsAnyFlagEnabled(combinedUsage, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) ) {
|
mvkIsAnyFlagEnabled(combinedUsage, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) ) {
|
||||||
mvkDisableFlags(pMemoryRequirements->memoryTypeBits, getPhysicalDevice()->getLazilyAllocatedMemoryTypes());
|
mvkDisableFlags(pMemoryRequirements->memoryTypeBits, mvkPD->getLazilyAllocatedMemoryTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
return getMemoryBinding(planeIndex)->getMemoryRequirements(pMemoryRequirements);
|
return getMemoryBinding(planeIndex)->getMemoryRequirements(pMemoryRequirements);
|
||||||
|
@ -155,6 +155,7 @@ protected:
|
|||||||
NSString* _mtlCmdBuffLabelQueueWaitIdle = nil;
|
NSString* _mtlCmdBuffLabelQueueWaitIdle = nil;
|
||||||
NSString* _mtlCmdBuffLabelAcquireNextImage = nil;
|
NSString* _mtlCmdBuffLabelAcquireNextImage = nil;
|
||||||
NSString* _mtlCmdBuffLabelInvalidateMappedMemoryRanges = nil;
|
NSString* _mtlCmdBuffLabelInvalidateMappedMemoryRanges = nil;
|
||||||
|
NSString* _mtlCmdBuffLabelCopyImageToMemory = nil;
|
||||||
MVKGPUCaptureScope* _submissionCaptureScope = nil;
|
MVKGPUCaptureScope* _submissionCaptureScope = nil;
|
||||||
float _priority;
|
float _priority;
|
||||||
uint32_t _index;
|
uint32_t _index;
|
||||||
|
@ -195,6 +195,7 @@ NSString* MVKQueue::getMTLCommandBufferLabel(MVKCommandUse cmdUse) {
|
|||||||
CASE_GET_LABEL(DeviceWaitIdle);
|
CASE_GET_LABEL(DeviceWaitIdle);
|
||||||
CASE_GET_LABEL(AcquireNextImage);
|
CASE_GET_LABEL(AcquireNextImage);
|
||||||
CASE_GET_LABEL(InvalidateMappedMemoryRanges);
|
CASE_GET_LABEL(InvalidateMappedMemoryRanges);
|
||||||
|
CASE_GET_LABEL(CopyImageToMemory);
|
||||||
default:
|
default:
|
||||||
MVKAssert(false, "Uncached MTLCommandBuffer label for command use %s.", mvkVkCommandName(cmdUse));
|
MVKAssert(false, "Uncached MTLCommandBuffer label for command use %s.", mvkVkCommandName(cmdUse));
|
||||||
return [NSString stringWithFormat: @"%s MTLCommandBuffer on Queue %d-%d", mvkVkCommandName(cmdUse), _queueFamily->getIndex(), _index];
|
return [NSString stringWithFormat: @"%s MTLCommandBuffer on Queue %d-%d", mvkVkCommandName(cmdUse), _queueFamily->getIndex(), _index];
|
||||||
|
@ -40,6 +40,7 @@ const char* mvkVkCommandName(MVKCommandUse cmdUse) {
|
|||||||
case kMVKCommandUseResolveImage: return "vkCmdResolveImage (resolve stage)";
|
case kMVKCommandUseResolveImage: return "vkCmdResolveImage (resolve stage)";
|
||||||
case kMVKCommandUseResolveExpandImage: return "vkCmdResolveImage (expand stage)";
|
case kMVKCommandUseResolveExpandImage: return "vkCmdResolveImage (expand stage)";
|
||||||
case kMVKCommandUseResolveCopyImage: return "vkCmdResolveImage (copy stage)";
|
case kMVKCommandUseResolveCopyImage: return "vkCmdResolveImage (copy stage)";
|
||||||
|
case kMVKCommandUseCopyImageToMemory: return "vkCopyImageToMemory host sync";
|
||||||
case kMVKCommandUseCopyBuffer: return "vkCmdCopyBuffer";
|
case kMVKCommandUseCopyBuffer: return "vkCmdCopyBuffer";
|
||||||
case kMVKCommandUseCopyBufferToImage: return "vkCmdCopyBufferToImage";
|
case kMVKCommandUseCopyBufferToImage: return "vkCmdCopyBufferToImage";
|
||||||
case kMVKCommandUseCopyImageToBuffer: return "vkCmdCopyImageToBuffer";
|
case kMVKCommandUseCopyImageToBuffer: return "vkCmdCopyImageToBuffer";
|
||||||
|
@ -83,6 +83,7 @@ typedef enum : uint8_t {
|
|||||||
kMVKCommandUseResolveImage, /**< vkCmdResolveImage - resolve stage. */
|
kMVKCommandUseResolveImage, /**< vkCmdResolveImage - resolve stage. */
|
||||||
kMVKCommandUseResolveExpandImage, /**< vkCmdResolveImage - expand stage. */
|
kMVKCommandUseResolveExpandImage, /**< vkCmdResolveImage - expand stage. */
|
||||||
kMVKCommandUseResolveCopyImage, /**< vkCmdResolveImage - copy stage. */
|
kMVKCommandUseResolveCopyImage, /**< vkCmdResolveImage - copy stage. */
|
||||||
|
kMVKCommandUseCopyImageToMemory, /**< vkCopyImageToMemoryEXT host sync. */
|
||||||
kMVKCommandUseCopyBuffer, /**< vkCmdCopyBuffer. */
|
kMVKCommandUseCopyBuffer, /**< vkCmdCopyBuffer. */
|
||||||
kMVKCommandUseCopyBufferToImage, /**< vkCmdCopyBufferToImage. */
|
kMVKCommandUseCopyBufferToImage, /**< vkCmdCopyBufferToImage. */
|
||||||
kMVKCommandUseCopyImageToBuffer, /**< vkCmdCopyImageToBuffer. */
|
kMVKCommandUseCopyImageToBuffer, /**< vkCmdCopyImageToBuffer. */
|
||||||
|
@ -3909,7 +3909,7 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkCopyImageToImageEXT(
|
|||||||
const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo) {
|
const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo) {
|
||||||
|
|
||||||
MVKTraceVulkanCallStart();
|
MVKTraceVulkanCallStart();
|
||||||
VkResult rslt = MVKImage::copyContent(pCopyImageToImageInfo);
|
VkResult rslt = MVKImage::copyImageToImage(pCopyImageToImageInfo);
|
||||||
MVKTraceVulkanCallEnd();
|
MVKTraceVulkanCallEnd();
|
||||||
return rslt;
|
return rslt;
|
||||||
}
|
}
|
||||||
@ -3920,7 +3920,7 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkCopyImageToMemoryEXT(
|
|||||||
|
|
||||||
MVKTraceVulkanCallStart();
|
MVKTraceVulkanCallStart();
|
||||||
MVKImage* srcImg = (MVKImage*)pCopyImageToMemoryInfo->srcImage;
|
MVKImage* srcImg = (MVKImage*)pCopyImageToMemoryInfo->srcImage;
|
||||||
VkResult rslt = srcImg->copyContent(pCopyImageToMemoryInfo);
|
VkResult rslt = srcImg->copyImageToMemory(pCopyImageToMemoryInfo);
|
||||||
MVKTraceVulkanCallEnd();
|
MVKTraceVulkanCallEnd();
|
||||||
return rslt;
|
return rslt;
|
||||||
}
|
}
|
||||||
@ -3931,7 +3931,7 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkCopyMemoryToImageEXT(
|
|||||||
|
|
||||||
MVKTraceVulkanCallStart();
|
MVKTraceVulkanCallStart();
|
||||||
MVKImage* dstImg = (MVKImage*)pCopyMemoryToImageInfo->dstImage;
|
MVKImage* dstImg = (MVKImage*)pCopyMemoryToImageInfo->dstImage;
|
||||||
VkResult rslt = dstImg->copyContent(pCopyMemoryToImageInfo);
|
VkResult rslt = dstImg->copyMemoryToImage(pCopyMemoryToImageInfo);
|
||||||
MVKTraceVulkanCallEnd();
|
MVKTraceVulkanCallEnd();
|
||||||
return rslt;
|
return rslt;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user