Add support for VK_EXT_host_image_copy extension.
- MVKResource::getHostMemoryAddress() return nullptr if MVKDeviceMemory::getHostMemoryAddress() returns null pointer, regardless of local offset. - Remove unnecessary enum value kMVKVkFormatFeatureFlagsTexTransfer to reduce redundancy between read and transfer feature flag options. - Fix spelling of mvkVkOffset3DFromMTLOrigin() (unrelated). - MVKResource remove unnecessary inline qualifiers (unrelated). - MVKDevice remove some obsolete commentary (unrelated).
This commit is contained in:
parent
3f6a3c28f7
commit
2290e86cd9
@ -315,6 +315,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll
|
|||||||
- `VK_EXT_hdr_metadata`
|
- `VK_EXT_hdr_metadata`
|
||||||
- *macOS only.*
|
- *macOS only.*
|
||||||
- `VK_EXT_headless_surface`
|
- `VK_EXT_headless_surface`
|
||||||
|
- `VK_EXT_host_image_copy`
|
||||||
- `VK_EXT_host_query_reset`
|
- `VK_EXT_host_query_reset`
|
||||||
- `VK_EXT_image_robustness`
|
- `VK_EXT_image_robustness`
|
||||||
- `VK_EXT_inline_uniform_block`
|
- `VK_EXT_inline_uniform_block`
|
||||||
|
@ -18,6 +18,8 @@ MoltenVK 1.2.9
|
|||||||
|
|
||||||
Released TBD
|
Released TBD
|
||||||
|
|
||||||
|
- Add support for extensions:
|
||||||
|
- `VK_EXT_host_image_copy`
|
||||||
- To support legacy apps, restore `MoltenVK/dylib` directory via symlink to `MoltenVK/dynamic/dylib`.
|
- To support legacy apps, restore `MoltenVK/dylib` directory via symlink to `MoltenVK/dynamic/dylib`.
|
||||||
- Add `MVKPerformanceTracker::previous` to track latest-but-one performance measurements.
|
- Add `MVKPerformanceTracker::previous` to track latest-but-one performance measurements.
|
||||||
- Fix crash when using `VK_EXT_metal_objects` under _ARC_.
|
- Fix crash when using `VK_EXT_metal_objects` under _ARC_.
|
||||||
|
@ -452,7 +452,7 @@ static inline MTLOrigin mvkMTLOriginFromVkOffset3D(VkOffset3D vkOffset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a Vulkan VkOffset3D constructed from a Metal MTLOrigin. */
|
/** Returns a Vulkan VkOffset3D constructed from a Metal MTLOrigin. */
|
||||||
static inline VkOffset3D mvkVkOffset3DFromMTLSize(MTLOrigin mtlOrigin) {
|
static inline VkOffset3D mvkVkOffset3DFromMTLOrigin(MTLOrigin mtlOrigin) {
|
||||||
return { (int32_t)mtlOrigin.x, (int32_t)mtlOrigin.y, (int32_t)mtlOrigin.z };
|
return { (int32_t)mtlOrigin.x, (int32_t)mtlOrigin.y, (int32_t)mtlOrigin.z };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,6 +417,7 @@ protected:
|
|||||||
uint32_t getMoltenVKGitRevision();
|
uint32_t getMoltenVKGitRevision();
|
||||||
void populateDeviceIDProperties(VkPhysicalDeviceVulkan11Properties* pVk11Props);
|
void populateDeviceIDProperties(VkPhysicalDeviceVulkan11Properties* pVk11Props);
|
||||||
void populateSubgroupProperties(VkPhysicalDeviceVulkan11Properties* pVk11Props);
|
void populateSubgroupProperties(VkPhysicalDeviceVulkan11Properties* pVk11Props);
|
||||||
|
void populateHostImageCopyProperties(VkPhysicalDeviceHostImageCopyPropertiesEXT* pHostImageCopyProps);
|
||||||
void logGPUInfo();
|
void logGPUInfo();
|
||||||
|
|
||||||
id<MTLDevice> _mtlDevice;
|
id<MTLDevice> _mtlDevice;
|
||||||
|
@ -443,6 +443,11 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) {
|
|||||||
interlockFeatures->fragmentShaderShadingRateInterlock = false; // Requires variable rate shading; not supported yet in Metal
|
interlockFeatures->fragmentShaderShadingRateInterlock = false; // Requires variable rate shading; not supported yet in Metal
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT: {
|
||||||
|
auto* hostImageCopyFeatures = (VkPhysicalDeviceHostImageCopyFeaturesEXT*)next;
|
||||||
|
hostImageCopyFeatures->hostImageCopy = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT: {
|
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT: {
|
||||||
auto* pipelineCreationCacheControlFeatures = (VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT*)next;
|
auto* pipelineCreationCacheControlFeatures = (VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT*)next;
|
||||||
pipelineCreationCacheControlFeatures->pipelineCreationCacheControl = true;
|
pipelineCreationCacheControlFeatures->pipelineCreationCacheControl = true;
|
||||||
@ -817,6 +822,10 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) {
|
|||||||
extMemHostProps->minImportedHostPointerAlignment = _metalFeatures.hostMemoryPageSize;
|
extMemHostProps->minImportedHostPointerAlignment = _metalFeatures.hostMemoryPageSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES_EXT: {
|
||||||
|
populateHostImageCopyProperties((VkPhysicalDeviceHostImageCopyPropertiesEXT*)next);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT: {
|
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT: {
|
||||||
// This isn't implemented yet, but when it is, it is expected that we'll wind up doing it manually.
|
// This isn't implemented yet, but when it is, it is expected that we'll wind up doing it manually.
|
||||||
auto* robustness2Props = (VkPhysicalDeviceRobustness2PropertiesEXT*)next;
|
auto* robustness2Props = (VkPhysicalDeviceRobustness2PropertiesEXT*)next;
|
||||||
@ -845,6 +854,77 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MVKPhysicalDevice::populateHostImageCopyProperties(VkPhysicalDeviceHostImageCopyPropertiesEXT* pHostImageCopyProps) {
|
||||||
|
|
||||||
|
// Metal lacks the concept of image layouts, and so does not restrict
|
||||||
|
// host copy transfers based on them. Assume all image layouts are supported.
|
||||||
|
// TODO: As extensions that add layouts are implemented, this list should be extended.
|
||||||
|
VkImageLayout supportedImgLayouts[] = {
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_PREINITIALIZED,
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL,
|
||||||
|
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||||
|
};
|
||||||
|
uint32_t supportedImgLayoutsCnt = sizeof(supportedImgLayouts) / sizeof(VkImageLayout);
|
||||||
|
|
||||||
|
// pCopySrcLayouts
|
||||||
|
// If pCopySrcLayouts is NULL, return the number of supported layouts.
|
||||||
|
if (pHostImageCopyProps->pCopySrcLayouts) {
|
||||||
|
mvkCopy(pHostImageCopyProps->pCopySrcLayouts, supportedImgLayouts, min(pHostImageCopyProps->copySrcLayoutCount, supportedImgLayoutsCnt));
|
||||||
|
} else {
|
||||||
|
pHostImageCopyProps->copySrcLayoutCount = supportedImgLayoutsCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pCopyDstLayouts
|
||||||
|
// If pCopyDstLayouts is NULL, return the number of supported layouts.
|
||||||
|
if (pHostImageCopyProps->pCopyDstLayouts) {
|
||||||
|
mvkCopy(pHostImageCopyProps->pCopyDstLayouts, supportedImgLayouts, min(pHostImageCopyProps->copyDstLayoutCount, supportedImgLayoutsCnt));
|
||||||
|
} else {
|
||||||
|
pHostImageCopyProps->copyDstLayoutCount = supportedImgLayoutsCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// optimalTilingLayoutUUID
|
||||||
|
// Since optimalTilingLayoutUUID is an uint8_t array, use Big-Endian byte ordering,
|
||||||
|
// so a hex dump of the array is human readable in its parts.
|
||||||
|
uint8_t* uuid = pHostImageCopyProps->optimalTilingLayoutUUID;
|
||||||
|
size_t uuidComponentOffset = 0;
|
||||||
|
mvkClear(uuid, VK_UUID_SIZE);
|
||||||
|
|
||||||
|
// First 4 bytes contains GPU vendor ID.
|
||||||
|
// Use Big-Endian byte ordering, so a hex dump is human readable
|
||||||
|
*(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(_properties.vendorID);
|
||||||
|
uuidComponentOffset += sizeof(uint32_t);
|
||||||
|
|
||||||
|
// Next 4 bytes contains GPU device ID
|
||||||
|
// Use Big-Endian byte ordering, so a hex dump is human readable
|
||||||
|
*(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(_properties.deviceID);
|
||||||
|
uuidComponentOffset += sizeof(uint32_t);
|
||||||
|
|
||||||
|
// Next 4 bytes contains OS version
|
||||||
|
*(MVKOSVersion*)&uuid[uuidComponentOffset] = mvkOSVersion();
|
||||||
|
uuidComponentOffset += sizeof(MVKOSVersion);
|
||||||
|
|
||||||
|
// Last 4 bytes are left zero
|
||||||
|
|
||||||
|
// identicalMemoryTypeRequirements
|
||||||
|
// Metal cannot use Private storage mode with host memory access.
|
||||||
|
pHostImageCopyProps->identicalMemoryTypeRequirements = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Since these are uint8_t arrays, use Big-Endian byte ordering,
|
// Since these are uint8_t arrays, use Big-Endian byte ordering,
|
||||||
// so a hex dump of the array is human readable in its parts.
|
// so a hex dump of the array is human readable in its parts.
|
||||||
void MVKPhysicalDevice::populateDeviceIDProperties(VkPhysicalDeviceVulkan11Properties* pVk11Props) {
|
void MVKPhysicalDevice::populateDeviceIDProperties(VkPhysicalDeviceVulkan11Properties* pVk11Props) {
|
||||||
@ -1177,6 +1257,15 @@ VkResult MVKPhysicalDevice::getImageFormatProperties(const VkPhysicalDeviceImage
|
|||||||
samplerYcbcrConvProps->combinedImageSamplerDescriptorCount = std::max(_pixelFormats.getChromaSubsamplingPlaneCount(pImageFormatInfo->format), (uint8_t)1u);
|
samplerYcbcrConvProps->combinedImageSamplerDescriptorCount = std::max(_pixelFormats.getChromaSubsamplingPlaneCount(pImageFormatInfo->format), (uint8_t)1u);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY_EXT: {
|
||||||
|
// Under Metal, VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT does not affect either memory layout
|
||||||
|
// or access, therefore, both identicalMemoryLayout and optimalDeviceAccess should be VK_TRUE.
|
||||||
|
// Also, per Vulkan spec, if identicalMemoryLayout is VK_TRUE, optimalDeviceAccess must also be VK_TRUE.
|
||||||
|
auto* hostImgCopyPerfQry = (VkHostImageCopyDevicePerformanceQueryEXT*)nextProps;
|
||||||
|
hostImgCopyPerfQry->optimalDeviceAccess = VK_TRUE;
|
||||||
|
hostImgCopyPerfQry->identicalMemoryLayout = VK_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3068,38 +3157,6 @@ void MVKPhysicalDevice::setMemoryType(uint32_t typeIndex, uint32_t heapIndex, Vk
|
|||||||
_memoryProperties.memoryTypes[typeIndex].propertyFlags = propertyFlags;
|
_memoryProperties.memoryTypes[typeIndex].propertyFlags = propertyFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the memory properties of this instance.
|
|
||||||
// Metal Shared:
|
|
||||||
// - applies to both buffers and textures
|
|
||||||
// - default mode for buffers on both iOS & macOS
|
|
||||||
// - default mode for textures on iOS
|
|
||||||
// - one copy of memory visible to both CPU & GPU
|
|
||||||
// - coherent at command buffer boundaries
|
|
||||||
// Metal Private:
|
|
||||||
// - applies to both buffers and textures
|
|
||||||
// - accessed only by GPU through render, compute, or BLIT operations
|
|
||||||
// - no access by CPU
|
|
||||||
// - always use for framebuffers and renderable textures
|
|
||||||
// Metal Managed:
|
|
||||||
// - applies to both buffers and textures
|
|
||||||
// - default mode for textures on macOS
|
|
||||||
// - two copies of each buffer or texture when discrete memory available
|
|
||||||
// - convenience of shared mode, performance of private mode
|
|
||||||
// - on unified systems behaves like shared memory and has only one copy of content
|
|
||||||
// - when writing, use:
|
|
||||||
// - buffer didModifyRange:
|
|
||||||
// - texture replaceRegion:
|
|
||||||
// - when reading, use:
|
|
||||||
// - encoder synchronizeResource: followed by
|
|
||||||
// - cmdbuff waitUntilCompleted (or completion handler)
|
|
||||||
// - buffer/texture getBytes:
|
|
||||||
// Metal Memoryless:
|
|
||||||
// - applies only to textures used as transient render targets
|
|
||||||
// - only available with TBDR devices (i.e. on iOS)
|
|
||||||
// - no device memory is reserved at all
|
|
||||||
// - storage comes from tile memory
|
|
||||||
// - contents are undefined after rendering
|
|
||||||
// - use for temporary renderable textures
|
|
||||||
void MVKPhysicalDevice::initMemoryProperties() {
|
void MVKPhysicalDevice::initMemoryProperties() {
|
||||||
|
|
||||||
mvkClear(&_memoryProperties); // Start with everything cleared
|
mvkClear(&_memoryProperties); // Start with everything cleared
|
||||||
|
@ -69,6 +69,7 @@ MVK_DEVICE_FEATURE_EXTN(ExtendedDynamicState, EXTENDED_DYNAMIC_STATE,
|
|||||||
MVK_DEVICE_FEATURE_EXTN(ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, EXT, 3)
|
MVK_DEVICE_FEATURE_EXTN(ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, EXT, 3)
|
||||||
MVK_DEVICE_FEATURE_EXTN(ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, EXT, 31)
|
MVK_DEVICE_FEATURE_EXTN(ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, EXT, 31)
|
||||||
MVK_DEVICE_FEATURE_EXTN(FragmentShaderInterlock, FRAGMENT_SHADER_INTERLOCK, EXT, 3)
|
MVK_DEVICE_FEATURE_EXTN(FragmentShaderInterlock, FRAGMENT_SHADER_INTERLOCK, EXT, 3)
|
||||||
|
MVK_DEVICE_FEATURE_EXTN(HostImageCopy, HOST_IMAGE_COPY, EXT, 1)
|
||||||
MVK_DEVICE_FEATURE_EXTN(PipelineCreationCacheControl, PIPELINE_CREATION_CACHE_CONTROL, EXT, 1)
|
MVK_DEVICE_FEATURE_EXTN(PipelineCreationCacheControl, PIPELINE_CREATION_CACHE_CONTROL, EXT, 1)
|
||||||
MVK_DEVICE_FEATURE_EXTN(Robustness2, ROBUSTNESS_2, EXT, 3)
|
MVK_DEVICE_FEATURE_EXTN(Robustness2, ROBUSTNESS_2, EXT, 3)
|
||||||
MVK_DEVICE_FEATURE_EXTN(ShaderAtomicFloat, SHADER_ATOMIC_FLOAT, EXT, 12)
|
MVK_DEVICE_FEATURE_EXTN(ShaderAtomicFloat, SHADER_ATOMIC_FLOAT, EXT, 12)
|
||||||
|
@ -69,8 +69,8 @@ public:
|
|||||||
inline VkDeviceSize getDeviceMemoryCommitment() { return _allocationSize; }
|
inline VkDeviceSize getDeviceMemoryCommitment() { return _allocationSize; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the host memory address of this memory, or NULL if the memory
|
* Returns the host memory address of this memory, or NULL if the memory has not been
|
||||||
* is marked as device-only and cannot be mapped to a host address.
|
* mapped yet, or is marked as device-only and cannot be mapped to a host address.
|
||||||
*/
|
*/
|
||||||
inline void* getHostMemoryAddress() { return _pMemory; }
|
inline void* getHostMemoryAddress() { return _pMemory; }
|
||||||
|
|
||||||
|
@ -226,6 +226,10 @@ public:
|
|||||||
VkResult getSubresourceLayout(const VkImageSubresource* pSubresource,
|
VkResult getSubresourceLayout(const VkImageSubresource* pSubresource,
|
||||||
VkSubresourceLayout* pLayout);
|
VkSubresourceLayout* pLayout);
|
||||||
|
|
||||||
|
/** Populates the specified layout for the specified sub-resource. */
|
||||||
|
VkResult getSubresourceLayout(const VkImageSubresource2KHR* pSubresource,
|
||||||
|
VkSubresourceLayout2KHR* pLayout);
|
||||||
|
|
||||||
/** Populates the specified transfer image descriptor data structure. */
|
/** Populates the specified transfer image descriptor data structure. */
|
||||||
void getTransferDescriptorData(MVKImageDescriptorData& imgData);
|
void getTransferDescriptorData(MVKImageDescriptorData& imgData);
|
||||||
|
|
||||||
@ -252,6 +256,13 @@ 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. */
|
||||||
|
template<typename CopyInfo> VkResult copyContent(const CopyInfo* pCopyInfo);
|
||||||
|
|
||||||
|
/** Host-copy the content of one image to another using the CPU. */
|
||||||
|
static VkResult copyContent(const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo);
|
||||||
|
|
||||||
|
|
||||||
#pragma mark Metal
|
#pragma mark Metal
|
||||||
|
|
||||||
/** Returns the Metal texture underlying this image. */
|
/** Returns the Metal texture underlying this image. */
|
||||||
@ -348,6 +359,12 @@ 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);
|
||||||
|
VkResult copyContent(id<MTLTexture> mtlTex,
|
||||||
|
VkMemoryToImageCopyEXT imgRgn, uint32_t mipLevel, uint32_t slice,
|
||||||
|
void* pImgBytes, size_t rowPitch, size_t depthPitch);
|
||||||
|
VkResult copyContent(id<MTLTexture> mtlTex,
|
||||||
|
VkImageToMemoryCopyEXT imgRgn, uint32_t mipLevel, uint32_t slice,
|
||||||
|
void* pImgBytes, size_t rowPitch, size_t depthPitch);
|
||||||
|
|
||||||
MVKSmallVector<MVKImageMemoryBinding*, 3> _memoryBindings;
|
MVKSmallVector<MVKImageMemoryBinding*, 3> _memoryBindings;
|
||||||
MVKSmallVector<MVKImagePlane*, 3> _planes;
|
MVKSmallVector<MVKImagePlane*, 3> _planes;
|
||||||
|
@ -191,7 +191,7 @@ void MVKImagePlane::initSubresources(const VkImageCreateInfo* pCreateInfo) {
|
|||||||
// Returns a pointer to the internal subresource for the specified MIP level layer.
|
// Returns a pointer to the internal subresource for the specified MIP level layer.
|
||||||
MVKImageSubresource* MVKImagePlane::getSubresource(uint32_t mipLevel, uint32_t arrayLayer) {
|
MVKImageSubresource* MVKImagePlane::getSubresource(uint32_t mipLevel, uint32_t arrayLayer) {
|
||||||
uint32_t srIdx = (mipLevel * _image->_arrayLayers) + arrayLayer;
|
uint32_t srIdx = (mipLevel * _image->_arrayLayers) + arrayLayer;
|
||||||
return (srIdx < _subresources.size()) ? &_subresources[srIdx] : NULL;
|
return (srIdx < _subresources.size()) ? &_subresources[srIdx] : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates the contents of the underlying MTLTexture, corresponding to the
|
// Updates the contents of the underlying MTLTexture, corresponding to the
|
||||||
@ -219,8 +219,8 @@ void MVKImagePlane::updateMTLTextureContent(MVKImageSubresource& subresource,
|
|||||||
#if MVK_MACOS
|
#if MVK_MACOS
|
||||||
std::unique_ptr<char[]> decompBuffer;
|
std::unique_ptr<char[]> decompBuffer;
|
||||||
if (_image->_is3DCompressed) {
|
if (_image->_is3DCompressed) {
|
||||||
// We cannot upload the texture data directly in this case. But we
|
// We cannot upload the texture data directly in this case.
|
||||||
// can upload the decompressed image data.
|
// But we can upload the decompressed image data.
|
||||||
std::unique_ptr<MVKCodec> codec = mvkCreateCodec(_image->getVkFormat());
|
std::unique_ptr<MVKCodec> codec = mvkCreateCodec(_image->getVkFormat());
|
||||||
if (!codec) {
|
if (!codec) {
|
||||||
_image->reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "A 3D texture used a compressed format that MoltenVK does not yet support.");
|
_image->reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "A 3D texture used a compressed format that MoltenVK does not yet support.");
|
||||||
@ -561,6 +561,161 @@ void MVKImage::flushToDevice(VkDeviceSize offset, VkDeviceSize size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename ImgRgn>
|
||||||
|
static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
|
||||||
|
return { mvkMTLOriginFromVkOffset3D(imgRgn.imageOffset), mvkMTLSizeFromVkExtent3D(imgRgn.imageExtent) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Host-copy from memory to a MTLTexture.
|
||||||
|
VkResult MVKImage::copyContent(id<MTLTexture> mtlTex,
|
||||||
|
VkImageToMemoryCopyEXT imgRgn, uint32_t mipLevel, uint32_t slice,
|
||||||
|
void* pImgBytes, size_t rowPitch, size_t depthPitch) {
|
||||||
|
[mtlTex getBytes: pImgBytes
|
||||||
|
bytesPerRow: rowPitch
|
||||||
|
bytesPerImage: depthPitch
|
||||||
|
fromRegion: getMTLRegion(imgRgn)
|
||||||
|
mipmapLevel: mipLevel
|
||||||
|
slice: slice];
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Host-copy from a MTLTexture to memory.
|
||||||
|
VkResult MVKImage::copyContent(id<MTLTexture> mtlTex,
|
||||||
|
VkMemoryToImageCopyEXT imgRgn, uint32_t mipLevel, uint32_t slice,
|
||||||
|
void* pImgBytes, size_t rowPitch, size_t depthPitch) {
|
||||||
|
VkSubresourceLayout imgLayout = { 0, 0, rowPitch, 0, depthPitch};
|
||||||
|
#if MVK_MACOS
|
||||||
|
// Compressed content cannot be directly uploaded to a compressed 3D texture.
|
||||||
|
// But we can upload the decompressed image data.
|
||||||
|
std::unique_ptr<char[]> decompBuffer;
|
||||||
|
if (_is3DCompressed) {
|
||||||
|
std::unique_ptr<MVKCodec> codec = mvkCreateCodec(getPixelFormats()->getVkFormat(mtlTex.pixelFormat));
|
||||||
|
if ( !codec ) { return reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "A 3D texture used a compressed format that MoltenVK does not yet support."); }
|
||||||
|
VkSubresourceLayout linearLayout = {};
|
||||||
|
linearLayout.rowPitch = 4 * imgRgn.imageExtent.width;
|
||||||
|
linearLayout.depthPitch = linearLayout.rowPitch * imgRgn.imageExtent.height;
|
||||||
|
linearLayout.size = linearLayout.depthPitch * imgRgn.imageExtent.depth;
|
||||||
|
decompBuffer = std::unique_ptr<char[]>(new char[linearLayout.size]);
|
||||||
|
codec->decompress(decompBuffer.get(), pImgBytes, linearLayout, imgLayout, imgRgn.imageExtent);
|
||||||
|
pImgBytes = decompBuffer.get();
|
||||||
|
imgLayout = linearLayout;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
[mtlTex replaceRegion: getMTLRegion(imgRgn)
|
||||||
|
mipmapLevel: mipLevel
|
||||||
|
slice: slice
|
||||||
|
withBytes: pImgBytes
|
||||||
|
bytesPerRow: imgLayout.rowPitch
|
||||||
|
bytesPerImage: imgLayout.depthPitch];
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename CopyInfo>
|
||||||
|
VkResult MVKImage::copyContent(const CopyInfo* pCopyInfo) {
|
||||||
|
MVKPixelFormats* pixFmts = getPixelFormats();
|
||||||
|
VkImageType imgType = getImageType();
|
||||||
|
bool is1D = imgType == VK_IMAGE_TYPE_1D;
|
||||||
|
bool is3D = imgType == VK_IMAGE_TYPE_3D;
|
||||||
|
|
||||||
|
for (uint32_t imgRgnIdx = 0; imgRgnIdx < pCopyInfo->regionCount; imgRgnIdx++) {
|
||||||
|
auto& imgRgn = pCopyInfo->pRegions[imgRgnIdx];
|
||||||
|
auto& imgSubRez = imgRgn.imageSubresource;
|
||||||
|
|
||||||
|
id<MTLTexture> mtlTex = getMTLTexture(getPlaneFromVkImageAspectFlags(imgSubRez.aspectMask));
|
||||||
|
MTLPixelFormat mtlPixFmt = mtlTex.pixelFormat;
|
||||||
|
bool isPVRTC = pixFmts->isPVRTCFormat(mtlPixFmt);
|
||||||
|
|
||||||
|
uint32_t texelsWidth = imgRgn.memoryRowLength ? imgRgn.memoryRowLength : imgRgn.imageExtent.width;
|
||||||
|
uint32_t texelsHeight = imgRgn.memoryImageHeight ? imgRgn.memoryImageHeight : imgRgn.imageExtent.height;
|
||||||
|
uint32_t texelsDepth = imgRgn.imageExtent.depth;
|
||||||
|
size_t rowPitch = pixFmts->getBytesPerRow(mtlPixFmt, texelsWidth);
|
||||||
|
size_t depthPitch = pixFmts->getBytesPerLayer(mtlPixFmt, rowPitch, texelsHeight);
|
||||||
|
size_t arrayPitch = depthPitch * texelsDepth;
|
||||||
|
|
||||||
|
for (uint32_t imgLyrIdx = 0; imgLyrIdx < imgSubRez.layerCount; imgLyrIdx++) {
|
||||||
|
VkResult rslt = copyContent(mtlTex,
|
||||||
|
imgRgn,
|
||||||
|
imgSubRez.mipLevel,
|
||||||
|
imgSubRez.baseArrayLayer + imgLyrIdx,
|
||||||
|
(void*)((uintptr_t)imgRgn.pHostPointer + (arrayPitch * imgLyrIdx)),
|
||||||
|
(isPVRTC || is1D) ? 0 : rowPitch,
|
||||||
|
(isPVRTC || !is3D) ? 0 : depthPitch);
|
||||||
|
if (rslt) { return rslt; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
|
// source image, and then copying from the memory buffer into the destination image, all using the CPU.
|
||||||
|
VkResult MVKImage::copyContent(const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo) {
|
||||||
|
for (uint32_t imgRgnIdx = 0; imgRgnIdx < pCopyImageToImageInfo->regionCount; imgRgnIdx++) {
|
||||||
|
auto& imgRgn = pCopyImageToImageInfo->pRegions[imgRgnIdx];
|
||||||
|
|
||||||
|
// Create a temporary memory buffer to copy the image region content.
|
||||||
|
MVKImage* srcMVKImg = (MVKImage*)pCopyImageToImageInfo->srcImage;
|
||||||
|
MVKPixelFormats* pixFmts = srcMVKImg->getPixelFormats();
|
||||||
|
MTLPixelFormat srcMTLPixFmt = srcMVKImg->getMTLPixelFormat(getPlaneFromVkImageAspectFlags(imgRgn.srcSubresource.aspectMask));
|
||||||
|
size_t rowPitch = pixFmts->getBytesPerRow(srcMTLPixFmt, imgRgn.extent.width);
|
||||||
|
size_t depthPitch = pixFmts->getBytesPerLayer(srcMTLPixFmt, rowPitch, imgRgn.extent.height);
|
||||||
|
size_t arrayPitch = depthPitch * imgRgn.extent.depth;
|
||||||
|
size_t rgnSizeInBytes = arrayPitch * imgRgn.srcSubresource.layerCount;
|
||||||
|
auto xfrBuffer = unique_ptr<char[]>(new char[rgnSizeInBytes]);
|
||||||
|
void* pImgBytes = xfrBuffer.get();
|
||||||
|
|
||||||
|
// Host-copy the source image content into the memory buffer using the CPU.
|
||||||
|
VkImageToMemoryCopyEXT srcCopy = {
|
||||||
|
VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY_EXT,
|
||||||
|
nullptr,
|
||||||
|
pImgBytes,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
imgRgn.srcSubresource,
|
||||||
|
imgRgn.srcOffset,
|
||||||
|
imgRgn.extent
|
||||||
|
};
|
||||||
|
VkCopyImageToMemoryInfoEXT srcCopyInfo = {
|
||||||
|
VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT,
|
||||||
|
nullptr,
|
||||||
|
pCopyImageToImageInfo->flags,
|
||||||
|
pCopyImageToImageInfo->srcImage,
|
||||||
|
pCopyImageToImageInfo->srcImageLayout,
|
||||||
|
1,
|
||||||
|
&srcCopy
|
||||||
|
};
|
||||||
|
srcMVKImg->copyContent(&srcCopyInfo);
|
||||||
|
|
||||||
|
// Host-copy the image content from the memory buffer into the destination image using the CPU.
|
||||||
|
MVKImage* dstMVKImg = (MVKImage*)pCopyImageToImageInfo->dstImage;
|
||||||
|
VkMemoryToImageCopyEXT dstCopy = {
|
||||||
|
VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT,
|
||||||
|
nullptr,
|
||||||
|
pImgBytes,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
imgRgn.dstSubresource,
|
||||||
|
imgRgn.dstOffset,
|
||||||
|
imgRgn.extent
|
||||||
|
};
|
||||||
|
VkCopyMemoryToImageInfoEXT dstCopyInfo = {
|
||||||
|
VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT,
|
||||||
|
nullptr,
|
||||||
|
pCopyImageToImageInfo->flags,
|
||||||
|
pCopyImageToImageInfo->dstImage,
|
||||||
|
pCopyImageToImageInfo->dstImageLayout,
|
||||||
|
1,
|
||||||
|
&dstCopy
|
||||||
|
};
|
||||||
|
dstMVKImg->copyContent(&dstCopyInfo);
|
||||||
|
}
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
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; }
|
||||||
@ -591,11 +746,36 @@ VkDeviceSize MVKImage::getBytesPerLayer(uint8_t planeIndex, uint32_t mipLevel) {
|
|||||||
|
|
||||||
VkResult MVKImage::getSubresourceLayout(const VkImageSubresource* pSubresource,
|
VkResult MVKImage::getSubresourceLayout(const VkImageSubresource* pSubresource,
|
||||||
VkSubresourceLayout* pLayout) {
|
VkSubresourceLayout* pLayout) {
|
||||||
uint8_t planeIndex = MVKImage::getPlaneFromVkImageAspectFlags(pSubresource->aspectMask);
|
VkImageSubresource2KHR subresource2 = { VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_KHR, nullptr, *pSubresource};
|
||||||
MVKImageSubresource* pImgRez = _planes[planeIndex]->getSubresource(pSubresource->mipLevel, pSubresource->arrayLayer);
|
VkSubresourceLayout2KHR layout2 = { VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_KHR, nullptr, *pLayout};
|
||||||
|
VkResult rslt = getSubresourceLayout(&subresource2, &layout2);
|
||||||
|
*pLayout = layout2.subresourceLayout;
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult MVKImage::getSubresourceLayout(const VkImageSubresource2KHR* pSubresource,
|
||||||
|
VkSubresourceLayout2KHR* pLayout) {
|
||||||
|
pLayout->sType = VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_KHR;
|
||||||
|
VkSubresourceHostMemcpySizeEXT* pMemcpySize = nullptr;
|
||||||
|
for (auto* next = (VkBaseOutStructure*)pLayout->pNext; next; next = next->pNext) {
|
||||||
|
switch (next->sType) {
|
||||||
|
case VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE_EXT: {
|
||||||
|
pMemcpySize = (VkSubresourceHostMemcpySizeEXT*)next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t planeIndex = MVKImage::getPlaneFromVkImageAspectFlags(pSubresource->imageSubresource.aspectMask);
|
||||||
|
MVKImageSubresource* pImgRez = _planes[planeIndex]->getSubresource(pSubresource->imageSubresource.mipLevel,
|
||||||
|
pSubresource->imageSubresource.arrayLayer);
|
||||||
if ( !pImgRez ) { return VK_INCOMPLETE; }
|
if ( !pImgRez ) { return VK_INCOMPLETE; }
|
||||||
|
|
||||||
*pLayout = pImgRez->layout;
|
pLayout->subresourceLayout = pImgRez->layout;
|
||||||
|
if (pMemcpySize) { pMemcpySize->size = pImgRez->layout.size; }
|
||||||
|
|
||||||
return VK_SUCCESS;
|
return VK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,11 +832,19 @@ VkResult MVKImage::getMemoryRequirements(VkMemoryRequirements* pMemoryRequiremen
|
|||||||
mvkDisableFlags(pMemoryRequirements->memoryTypeBits, getPhysicalDevice()->getHostCoherentMemoryTypes());
|
mvkDisableFlags(pMemoryRequirements->memoryTypeBits, getPhysicalDevice()->getHostCoherentMemoryTypes());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
VkImageUsageFlags combinedUsage = getCombinedUsage();
|
||||||
|
|
||||||
|
// 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)) {
|
||||||
|
mvkDisableFlags(pMemoryRequirements->memoryTypeBits, getPhysicalDevice()->getPrivateMemoryTypes());
|
||||||
|
}
|
||||||
|
|
||||||
// Only transient attachments may use memoryless storage.
|
// Only transient attachments may use memoryless storage.
|
||||||
// Using memoryless as an input attachment requires shader framebuffer fetch, which MoltenVK does not support yet.
|
// Using memoryless as an input attachment requires shader framebuffer fetch, which MoltenVK does not support yet.
|
||||||
// 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(getCombinedUsage(), VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) ||
|
if (!mvkIsAnyFlagEnabled(combinedUsage, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) ||
|
||||||
mvkIsAnyFlagEnabled(getCombinedUsage(), VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) ) {
|
mvkIsAnyFlagEnabled(combinedUsage, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) ) {
|
||||||
mvkDisableFlags(pMemoryRequirements->memoryTypeBits, getPhysicalDevice()->getLazilyAllocatedMemoryTypes());
|
mvkDisableFlags(pMemoryRequirements->memoryTypeBits, getPhysicalDevice()->getLazilyAllocatedMemoryTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -768,6 +768,11 @@ void MVKInstance::initProcAddrs() {
|
|||||||
ADD_DVC_EXT_ENTRY_POINT(vkCmdSetSampleLocationsEnableEXT, EXT_EXTENDED_DYNAMIC_STATE_3);
|
ADD_DVC_EXT_ENTRY_POINT(vkCmdSetSampleLocationsEnableEXT, EXT_EXTENDED_DYNAMIC_STATE_3);
|
||||||
ADD_DVC_EXT_ENTRY_POINT(vkCmdSetSampleMaskEXT, EXT_EXTENDED_DYNAMIC_STATE_3);
|
ADD_DVC_EXT_ENTRY_POINT(vkCmdSetSampleMaskEXT, EXT_EXTENDED_DYNAMIC_STATE_3);
|
||||||
ADD_DVC_EXT_ENTRY_POINT(vkCmdSetTessellationDomainOriginEXT, EXT_EXTENDED_DYNAMIC_STATE_3);
|
ADD_DVC_EXT_ENTRY_POINT(vkCmdSetTessellationDomainOriginEXT, EXT_EXTENDED_DYNAMIC_STATE_3);
|
||||||
|
ADD_DVC_EXT_ENTRY_POINT(vkCopyImageToImageEXT, EXT_HOST_IMAGE_COPY);
|
||||||
|
ADD_DVC_EXT_ENTRY_POINT(vkCopyImageToMemoryEXT, EXT_HOST_IMAGE_COPY);
|
||||||
|
ADD_DVC_EXT_ENTRY_POINT(vkCopyMemoryToImageEXT, EXT_HOST_IMAGE_COPY);
|
||||||
|
ADD_DVC_EXT_ENTRY_POINT(vkGetImageSubresourceLayout2EXT, EXT_HOST_IMAGE_COPY);
|
||||||
|
ADD_DVC_EXT_ENTRY_POINT(vkTransitionImageLayoutEXT, EXT_HOST_IMAGE_COPY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MVKInstance::logVersions() {
|
void MVKInstance::logVersions() {
|
||||||
|
@ -2061,6 +2061,7 @@ typedef enum : VkFormatFeatureFlags2 {
|
|||||||
kMVKVkFormatFeatureFlagsTexRead = (VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT |
|
kMVKVkFormatFeatureFlagsTexRead = (VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT |
|
||||||
VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT |
|
VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT |
|
||||||
VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT |
|
VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT |
|
||||||
|
VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT |
|
||||||
VK_FORMAT_FEATURE_2_BLIT_SRC_BIT),
|
VK_FORMAT_FEATURE_2_BLIT_SRC_BIT),
|
||||||
kMVKVkFormatFeatureFlagsTexFilter = (VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT),
|
kMVKVkFormatFeatureFlagsTexFilter = (VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT),
|
||||||
kMVKVkFormatFeatureFlagsTexWrite = (VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT |
|
kMVKVkFormatFeatureFlagsTexWrite = (VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT |
|
||||||
@ -2072,8 +2073,6 @@ typedef enum : VkFormatFeatureFlags2 {
|
|||||||
kMVKVkFormatFeatureFlagsTexDSAtt = (VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT |
|
kMVKVkFormatFeatureFlagsTexDSAtt = (VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT |
|
||||||
VK_FORMAT_FEATURE_2_BLIT_DST_BIT),
|
VK_FORMAT_FEATURE_2_BLIT_DST_BIT),
|
||||||
kMVKVkFormatFeatureFlagsTexBlend = (VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT),
|
kMVKVkFormatFeatureFlagsTexBlend = (VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT),
|
||||||
kMVKVkFormatFeatureFlagsTexTransfer = (VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT |
|
|
||||||
VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT),
|
|
||||||
kMVKVkFormatFeatureFlagsTexChromaSubsampling = (VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT_KHR |
|
kMVKVkFormatFeatureFlagsTexChromaSubsampling = (VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT_KHR |
|
||||||
VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR),
|
VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR),
|
||||||
kMVKVkFormatFeatureFlagsTexMultiPlanar = (VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT_KHR |
|
kMVKVkFormatFeatureFlagsTexMultiPlanar = (VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT_KHR |
|
||||||
@ -2106,7 +2105,6 @@ void MVKPixelFormats::setFormatProperties(id<MTLDevice> mtlDevice, MVKVkFormatDe
|
|||||||
if (chromaSubsamplingComponentBits > 0) {
|
if (chromaSubsamplingComponentBits > 0) {
|
||||||
if (mtlPixFmtCaps != 0 || chromaSubsamplingPlaneCount > 1) {
|
if (mtlPixFmtCaps != 0 || chromaSubsamplingPlaneCount > 1) {
|
||||||
mtlPixFmtCaps = kMVKMTLFmtCapsRF;
|
mtlPixFmtCaps = kMVKMTLFmtCapsRF;
|
||||||
vkProps.optimalTilingFeatures = kMVKVkFormatFeatureFlagsTexTransfer;
|
|
||||||
}
|
}
|
||||||
enableFormatFeatures(ChromaSubsampling, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
|
enableFormatFeatures(ChromaSubsampling, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
|
||||||
}
|
}
|
||||||
|
@ -34,29 +34,30 @@ class MVKResource : public MVKVulkanAPIDeviceObject {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
/** Returns the number of bytes required for the entire resource. */
|
/** Returns the number of bytes required for the entire resource. */
|
||||||
inline VkDeviceSize getByteCount() { return _byteCount; }
|
VkDeviceSize getByteCount() { return _byteCount; }
|
||||||
|
|
||||||
/** Returns the byte offset in the bound device memory. */
|
/** Returns the byte offset in the bound device memory. */
|
||||||
inline VkDeviceSize getDeviceMemoryOffset() { return _deviceMemoryOffset; }
|
VkDeviceSize getDeviceMemoryOffset() { return _deviceMemoryOffset; }
|
||||||
|
|
||||||
/** Binds this resource to the specified offset within the specified memory allocation. */
|
/** Binds this resource to the specified offset within the specified memory allocation. */
|
||||||
virtual VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset);
|
virtual VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset);
|
||||||
|
|
||||||
/** Returns the device memory underlying this resource. */
|
/** Returns the device memory underlying this resource. */
|
||||||
inline MVKDeviceMemory* getDeviceMemory() { return _deviceMemory; }
|
MVKDeviceMemory* getDeviceMemory() { return _deviceMemory; }
|
||||||
|
|
||||||
/** Returns whether the memory is accessible from the host. */
|
/** Returns whether the memory is accessible from the host. */
|
||||||
inline bool isMemoryHostAccessible() { return _deviceMemory && _deviceMemory->isMemoryHostAccessible(); }
|
bool isMemoryHostAccessible() { return _deviceMemory && _deviceMemory->isMemoryHostAccessible(); }
|
||||||
|
|
||||||
/** Returns whether the memory is automatically coherent between device and host. */
|
/** Returns whether the memory is automatically coherent between device and host. */
|
||||||
inline bool isMemoryHostCoherent() { return _deviceMemory && _deviceMemory->isMemoryHostCoherent(); }
|
bool isMemoryHostCoherent() { return _deviceMemory && _deviceMemory->isMemoryHostCoherent(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the host memory address of this resource, or NULL if the memory
|
* Returns the host memory address of this resource, or NULL if the memory is not mapped to a
|
||||||
* is marked as device-only and cannot be mapped to a host address.
|
* host address yet, or if the memory is marked as device-only and cannot be mapped to a host address.
|
||||||
*/
|
*/
|
||||||
inline void* getHostMemoryAddress() {
|
void* getHostMemoryAddress() {
|
||||||
return (_deviceMemory ? (void*)((uintptr_t)_deviceMemory->getHostMemoryAddress() + _deviceMemoryOffset) : nullptr);
|
void* devMemHostAddr = _deviceMemory ? _deviceMemory->getHostMemoryAddress() : nullptr;
|
||||||
|
return devMemHostAddr ? (void*)((uintptr_t)devMemHostAddr + _deviceMemoryOffset) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Applies the specified global memory barrier. */
|
/** Applies the specified global memory barrier. */
|
||||||
|
@ -114,6 +114,7 @@ MVK_EXTENSION(EXT_external_memory_host, EXT_EXTERNAL_MEMORY_HOST,
|
|||||||
MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE, 10.13, 11.0, 1.0)
|
MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE, 10.13, 11.0, 1.0)
|
||||||
MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE, 10.15, MVK_NA, MVK_NA)
|
MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE, 10.15, MVK_NA, MVK_NA)
|
||||||
MVK_EXTENSION(EXT_headless_surface, EXT_HEADLESS_SURFACE, INSTANCE, 10.11, 8.0, 1.0)
|
MVK_EXTENSION(EXT_headless_surface, EXT_HEADLESS_SURFACE, INSTANCE, 10.11, 8.0, 1.0)
|
||||||
|
MVK_EXTENSION(EXT_host_image_copy, EXT_HOST_IMAGE_COPY, DEVICE, 10.11, 8.0, 1.0)
|
||||||
MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE, 10.11, 8.0, 1.0)
|
MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE, 10.11, 8.0, 1.0)
|
||||||
MVK_EXTENSION(EXT_image_robustness, EXT_IMAGE_ROBUSTNESS, DEVICE, 10.11, 8.0, 1.0)
|
MVK_EXTENSION(EXT_image_robustness, EXT_IMAGE_ROBUSTNESS, DEVICE, 10.11, 8.0, 1.0)
|
||||||
MVK_EXTENSION(EXT_inline_uniform_block, EXT_INLINE_UNIFORM_BLOCK, DEVICE, 10.11, 8.0, 1.0)
|
MVK_EXTENSION(EXT_inline_uniform_block, EXT_INLINE_UNIFORM_BLOCK, DEVICE, 10.11, 8.0, 1.0)
|
||||||
|
@ -3901,6 +3901,65 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkCreateHeadlessSurfaceEXT(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark VK_EXT_host_image_copy extension
|
||||||
|
|
||||||
|
MVK_PUBLIC_VULKAN_SYMBOL VkResult vkCopyImageToImageEXT(
|
||||||
|
VkDevice device,
|
||||||
|
const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo) {
|
||||||
|
|
||||||
|
MVKTraceVulkanCallStart();
|
||||||
|
VkResult rslt = MVKImage::copyContent(pCopyImageToImageInfo);
|
||||||
|
MVKTraceVulkanCallEnd();
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
MVK_PUBLIC_VULKAN_SYMBOL VkResult vkCopyImageToMemoryEXT(
|
||||||
|
VkDevice device,
|
||||||
|
const VkCopyImageToMemoryInfoEXT* pCopyImageToMemoryInfo) {
|
||||||
|
|
||||||
|
MVKTraceVulkanCallStart();
|
||||||
|
MVKImage* srcImg = (MVKImage*)pCopyImageToMemoryInfo->srcImage;
|
||||||
|
VkResult rslt = srcImg->copyContent(pCopyImageToMemoryInfo);
|
||||||
|
MVKTraceVulkanCallEnd();
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
MVK_PUBLIC_VULKAN_SYMBOL VkResult vkCopyMemoryToImageEXT(
|
||||||
|
VkDevice device,
|
||||||
|
const VkCopyMemoryToImageInfoEXT* pCopyMemoryToImageInfo) {
|
||||||
|
|
||||||
|
MVKTraceVulkanCallStart();
|
||||||
|
MVKImage* dstImg = (MVKImage*)pCopyMemoryToImageInfo->dstImage;
|
||||||
|
VkResult rslt = dstImg->copyContent(pCopyMemoryToImageInfo);
|
||||||
|
MVKTraceVulkanCallEnd();
|
||||||
|
return rslt;
|
||||||
|
}
|
||||||
|
|
||||||
|
MVK_PUBLIC_VULKAN_SYMBOL void vkGetImageSubresourceLayout2EXT(
|
||||||
|
VkDevice device,
|
||||||
|
VkImage image,
|
||||||
|
const VkImageSubresource2KHR* pSubresource,
|
||||||
|
VkSubresourceLayout2KHR* pLayout) {
|
||||||
|
|
||||||
|
MVKTraceVulkanCallStart();
|
||||||
|
MVKImage* mvkImg = (MVKImage*)image;
|
||||||
|
mvkImg->getSubresourceLayout(pSubresource, pLayout);
|
||||||
|
MVKTraceVulkanCallEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
MVK_PUBLIC_VULKAN_SYMBOL VkResult vkTransitionImageLayoutEXT(
|
||||||
|
VkDevice device,
|
||||||
|
uint32_t transitionCount,
|
||||||
|
const VkHostImageLayoutTransitionInfoEXT* pTransitions) {
|
||||||
|
|
||||||
|
MVKTraceVulkanCallStart();
|
||||||
|
// Metal lacks the concept of image layouts, so nothing to do.
|
||||||
|
MVKTraceVulkanCallEnd();
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark VK_EXT_host_query_reset extension
|
#pragma mark VK_EXT_host_query_reset extension
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user