Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Add: KHR_maintenance4 #2116

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Docs/MoltenVK_Runtime_UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll
- `VK_KHR_maintenance1`
- `VK_KHR_maintenance2`
- `VK_KHR_maintenance3`
- `VK_KHR_maintenance4`
- `VK_KHR_map_memory2`
- `VK_KHR_multiview`
- `VK_KHR_portability_subset`
Expand Down
2 changes: 1 addition & 1 deletion MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class MVKBuffer : public MVKResource {

/** Returns the memory requirements of this resource by populating the specified structure. */
VkResult getMemoryRequirements(const void* pInfo, VkMemoryRequirements2* pMemoryRequirements);

/** Binds this resource to the specified offset within the specified memory allocation. */
VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset) override;

Expand Down
4 changes: 2 additions & 2 deletions MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@
// Multiple rows will automatically align with PoT max texture dimension, but need to align upwards if less than full single row.
size_t maxBlocksPerRow = _device->_pMetalFeatures->maxTextureDimension / fmtBlockSize.width;
size_t blocksPerRow = min(blockCount, maxBlocksPerRow);
_mtlBytesPerRow = mvkAlignByteCount(blocksPerRow * bytesPerBlock, _device->getVkFormatTexelBufferAlignment(pCreateInfo->format, this));
_mtlBytesPerRow = mvkAlignByteCount(blocksPerRow * bytesPerBlock, _device->getVkFormatTexelBufferAlignment(pCreateInfo->format));

size_t rowCount = blockCount / blocksPerRow;
if (blockCount % blocksPerRow) { rowCount++; }
Expand All @@ -358,7 +358,7 @@
// We can just use a simple 1D texel array.
_textureSize.width = uint32_t(blockCount * fmtBlockSize.width);
_textureSize.height = 1;
_mtlBytesPerRow = mvkAlignByteCount(byteCount, _device->getVkFormatTexelBufferAlignment(pCreateInfo->format, this));
_mtlBytesPerRow = mvkAlignByteCount(byteCount, _device->getVkFormatTexelBufferAlignment(pCreateInfo->format));
}

if ( !_device->_pMetalFeatures->texelBuffers ) {
Expand Down
2 changes: 1 addition & 1 deletion MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ class MVKDevice : public MVKDispatchableVulkanAPIObject {
uint32_t getMetalBufferIndexForVertexAttributeBinding(uint32_t binding);

/** Returns the memory alignment required for the format when used in a texel buffer. */
VkDeviceSize getVkFormatTexelBufferAlignment(VkFormat format, MVKBaseObject* mvkObj);
VkDeviceSize getVkFormatTexelBufferAlignment(VkFormat format);

/**
* Returns the MTLBuffer used to hold occlusion query results,
Expand Down
14 changes: 12 additions & 2 deletions MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@
inlineUniformBlockFeatures->descriptorBindingInlineUniformBlockUpdateAfterBind = true;
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES: {
auto* maintenace4Features = (VkPhysicalDeviceMaintenance4Features*)next;
maintenace4Features->maintenance4 = true;
break;
}
spnda marked this conversation as resolved.
Show resolved Hide resolved
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: {
auto* multiviewFeatures = (VkPhysicalDeviceMultiviewFeatures*)next;
multiviewFeatures->multiview = supportedFeats11.multiview;
Expand Down Expand Up @@ -645,7 +650,11 @@
maint3Props->maxMemoryAllocationSize = supportedProps11.maxMemoryAllocationSize;
break;
}

case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES: {
auto* maintenance4Props = (VkPhysicalDeviceMaintenance4Properties*)next;
maintenance4Props->maxBufferSize = _metalFeatures.maxMTLBufferSize;
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES: {
auto* depthStencilResolveProps = (VkPhysicalDeviceDepthStencilResolveProperties*)next;
depthStencilResolveProps->supportedDepthResolveModes = supportedProps12.supportedDepthResolveModes;
Expand Down Expand Up @@ -3730,6 +3739,7 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope
*pMaxDeviation = cpuEnd - cpuStart;
}


#pragma mark Object lifecycle

uint32_t MVKDevice::getVulkanMemoryTypeIndex(MTLStorageMode mtlStorageMode) {
Expand Down Expand Up @@ -4488,7 +4498,7 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope
return ((_pMetalFeatures->maxPerStageBufferCount - 1) - binding);
}

VkDeviceSize MVKDevice::getVkFormatTexelBufferAlignment(VkFormat format, MVKBaseObject* mvkObj) {
VkDeviceSize MVKDevice::getVkFormatTexelBufferAlignment(VkFormat format) {
VkDeviceSize deviceAlignment = 0;
id<MTLDevice> mtlDev = getMTLDevice();
MVKPixelFormats* mvkPixFmts = getPixelFormats();
Expand Down
26 changes: 14 additions & 12 deletions MoltenVK/MoltenVK/GPUObjects/MVKImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,22 +200,22 @@ class MVKImage : public MVKVulkanAPIDeviceObject {
/** Returns the number of samples for each pixel of this image. */
VkSampleCountFlagBits getSampleCount() { return _samples; }

/**
* Returns the number of bytes per image row at the specified zero-based mip level.
* For non-compressed formats, this is the number of bytes in a row of texels.
* For compressed formats, this is the number of bytes in a row of blocks, which
* will typically span more than one row of texels.
*/
VkDeviceSize getBytesPerRow(uint8_t planeIndex, uint32_t mipLevel);

/**
* Returns the number of bytes per image row for the mip with the given width.
* For non-compressed formats, this is the number of bytes in a row of texels.
* For compressed formats, this is the number of bytes in a row of blocks, which
* will typically span more than one row of texels.
*/
VkDeviceSize getBytesPerRow(MTLPixelFormat planePixelFormat, uint32_t mipWidth);
/**
* Returns the number of bytes per image layer (for cube, array, or 3D images)
* at the specified zero-based mip level. This value will normally be the number
* of bytes per row (as returned by the getBytesPerRow() function, multiplied by
* for the mip with the given extent. This value will normally be the number
* of bytes per row (as returned by the getBytesPerRow() function, multiplied by
* the height of each 2D image.
*/
VkDeviceSize getBytesPerLayer(uint8_t planeIndex, uint32_t mipLevel);
VkDeviceSize getBytesPerLayer(uint8_t planeIndex, VkExtent3D mipExtent);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the need for making the changes to getBytesPerRow() and getBytesPerLayer()?

I might be missing something, but I don't see how it changes the use of these functions in the code in this PR.

If the change is required, neither of these functions are connected to MIP levels now, so the function documentation should be changed, at the very least.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried explaining it at the bottom of the PR message. When I originally transformed the code to be all in MVKDevice I came across these functions and it just bugged me that it would call getExtent3D 3 times and getBytesPerRow 2 times, when every caller of getBytesPerLayer would need the values themselves and could instead just pass them as a parameter. So I decided to refactor this a bit just to remove some wasted function calls.

Not entirely related to the current state of the PR, but it was relevant to the original change where I re-implemented the memory requirement functions in the MVKDevice object.

/** Returns the number of planes of this image view. */
uint8_t getPlaneCount() { return _planes.size(); }

Expand All @@ -237,6 +237,8 @@ class MVKImage : public MVKVulkanAPIDeviceObject {

/** Returns the memory requirements of this resource by populating the specified structure. */
VkResult getMemoryRequirements(const void* pInfo, VkMemoryRequirements2* pMemoryRequirements);

VkResult getMemoryRequirements(VkMemoryRequirements2* pMemoryRequirements, uint8_t planeIndex);

spnda marked this conversation as resolved.
Show resolved Hide resolved
/** Binds this resource to the specified offset within the specified memory allocation. */
virtual VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset, uint8_t planeIndex);
Expand Down
37 changes: 20 additions & 17 deletions MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,10 @@

for (uint32_t mipLvl = 0; mipLvl < _image->_mipLevels; mipLvl++) {
subRez.subresource.mipLevel = mipLvl;
VkDeviceSize rowPitch = _image->getBytesPerRow(_planeIndex, mipLvl);
VkDeviceSize depthPitch = _image->getBytesPerLayer(_planeIndex, mipLvl);

VkExtent3D mipExtent = _image->getExtent3D(_planeIndex, mipLvl);
VkExtent3D mipExtent = _image->getExtent3D(_planeIndex, mipLvl);
auto planeMTLPixFmt = _image->getPixelFormats()->getChromaSubsamplingPlaneMTLPixelFormat(_image->_vkFormat, _planeIndex);
VkDeviceSize rowPitch = _image->getBytesPerRow(planeMTLPixFmt, mipExtent.width);
VkDeviceSize depthPitch = _image->getPixelFormats()->getBytesPerLayer(planeMTLPixFmt, rowPitch, mipExtent.height);

for (uint32_t layer = 0; layer < _image->_arrayLayers; layer++) {
subRez.subresource.arrayLayer = layer;
Expand Down Expand Up @@ -575,17 +575,15 @@
return mvkMipmapLevelSizeFromBaseSize3D(extent, mipLevel);
}

VkDeviceSize MVKImage::getBytesPerRow(uint8_t planeIndex, uint32_t mipLevel) {
MTLPixelFormat planeMTLPixFmt = getPixelFormats()->getChromaSubsamplingPlaneMTLPixelFormat(_vkFormat, planeIndex);
size_t bytesPerRow = getPixelFormats()->getBytesPerRow(planeMTLPixFmt, getExtent3D(planeIndex, mipLevel).width);
VkDeviceSize MVKImage::getBytesPerRow(MTLPixelFormat planePixelFormat, uint32_t mipWidth) {
size_t bytesPerRow = getPixelFormats()->getBytesPerRow(planePixelFormat, mipWidth);
return mvkAlignByteCount(bytesPerRow, _rowByteAlignment);
}

VkDeviceSize MVKImage::getBytesPerLayer(uint8_t planeIndex, uint32_t mipLevel) {
MTLPixelFormat planeMTLPixFmt = getPixelFormats()->getChromaSubsamplingPlaneMTLPixelFormat(_vkFormat, planeIndex);
VkExtent3D extent = getExtent3D(planeIndex, mipLevel);
size_t bytesPerRow = getBytesPerRow(planeIndex, mipLevel);
return getPixelFormats()->getBytesPerLayer(planeMTLPixFmt, bytesPerRow, extent.height);
VkDeviceSize MVKImage::getBytesPerLayer(uint8_t planeIndex, VkExtent3D mipExtent) {
MTLPixelFormat planeMTLPixFmt = getPixelFormats()->getChromaSubsamplingPlaneMTLPixelFormat(_vkFormat, planeIndex);
VkDeviceSize bytesPerRow = getBytesPerRow(planeMTLPixFmt, mipExtent.width);
return getPixelFormats()->getBytesPerLayer(planeMTLPixFmt, bytesPerRow, mipExtent.height);
}

VkResult MVKImage::getSubresourceLayout(const VkImageSubresource* pSubresource,
Expand Down Expand Up @@ -618,7 +616,6 @@
return _viewFormats.empty();
}


#pragma mark Resource memory

void MVKImage::applyImageMemoryBarrier(MVKPipelineBarrier& barrier,
Expand Down Expand Up @@ -672,6 +669,12 @@
return _memoryBindings[planeIndex]->getMemoryRequirements(pInfo, pMemoryRequirements);
}

VkResult MVKImage::getMemoryRequirements(VkMemoryRequirements2 *pMemoryRequirements, uint8_t planeIndex) {
VkResult rslt = getMemoryRequirements(&pMemoryRequirements->memoryRequirements, planeIndex);
if (rslt != VK_SUCCESS) { return rslt; }
return _memoryBindings[planeIndex]->getMemoryRequirements(nullptr, pMemoryRequirements);
}

VkResult MVKImage::bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset, uint8_t planeIndex) {
return _memoryBindings[planeIndex]->bindDeviceMemory(mvkMem, memOffset);
}
Expand Down Expand Up @@ -933,7 +936,7 @@
_isDepthStencilAttachment = (mvkAreAllFlagsEnabled(pCreateInfo->usage, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ||
mvkAreAllFlagsEnabled(pixFmts->getVkFormatProperties3(pCreateInfo->format).optimalTilingFeatures, VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT));
_canSupportMTLTextureView = !_isDepthStencilAttachment || _device->_pMetalFeatures->stencilViews;
_rowByteAlignment = _isLinear || _isLinearForAtomics ? _device->getVkFormatTexelBufferAlignment(pCreateInfo->format, this) : mvkEnsurePowerOfTwo(pixFmts->getBytesPerBlock(pCreateInfo->format));
_rowByteAlignment = _isLinear || _isLinearForAtomics ? _device->getVkFormatTexelBufferAlignment(pCreateInfo->format) : mvkEnsurePowerOfTwo(pixFmts->getBytesPerBlock(pCreateInfo->format));

VkExtent2D blockTexelSizeOfPlane[3];
uint32_t bytesPerBlockOfPlane[3];
Expand Down Expand Up @@ -970,15 +973,15 @@
NSUInteger bufferLength = 0;
for (uint32_t mipLvl = 0; mipLvl < _mipLevels; mipLvl++) {
VkExtent3D mipExtent = getExtent3D(planeIndex, mipLvl);
bufferLength += getBytesPerLayer(planeIndex, mipLvl) * mipExtent.depth * _arrayLayers;
bufferLength += getBytesPerLayer(planeIndex, mipExtent) * mipExtent.depth * _arrayLayers;
}
MTLSizeAndAlign sizeAndAlign = [_device->getMTLDevice() heapBufferSizeAndAlignWithLength: bufferLength options: MTLResourceStorageModePrivate];
memoryBinding->_byteCount += sizeAndAlign.size;
memoryBinding->_byteCount = sizeAndAlign.size;
memoryBinding->_byteAlignment = std::max(std::max(memoryBinding->_byteAlignment, _rowByteAlignment), (VkDeviceSize)sizeAndAlign.align);
} else {
for (uint32_t mipLvl = 0; mipLvl < _mipLevels; mipLvl++) {
VkExtent3D mipExtent = getExtent3D(planeIndex, mipLvl);
memoryBinding->_byteCount += getBytesPerLayer(planeIndex, mipLvl) * mipExtent.depth * _arrayLayers;
memoryBinding->_byteCount += getBytesPerLayer(planeIndex, mipExtent) * mipExtent.depth * _arrayLayers;
}
memoryBinding->_byteAlignment = std::max(memoryBinding->_byteAlignment, _rowByteAlignment);
}
Expand Down
4 changes: 2 additions & 2 deletions MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1674,7 +1674,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3

shaderConfig.options.mslOptions.msl_version = _device->_pMetalFeatures->mslVersion;
shaderConfig.options.mslOptions.texel_buffer_texture_width = _device->_pMetalFeatures->maxTextureDimension;
shaderConfig.options.mslOptions.r32ui_linear_texture_alignment = (uint32_t)_device->getVkFormatTexelBufferAlignment(VK_FORMAT_R32_UINT, this);
shaderConfig.options.mslOptions.r32ui_linear_texture_alignment = (uint32_t)_device->getVkFormatTexelBufferAlignment(VK_FORMAT_R32_UINT);
shaderConfig.options.mslOptions.texture_buffer_native = _device->_pMetalFeatures->textureBuffers;

bool useMetalArgBuff = isUsingMetalArgumentBuffers();
Expand Down Expand Up @@ -2113,7 +2113,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3
shaderConfig.options.entryPointStage = spv::ExecutionModelGLCompute;
shaderConfig.options.mslOptions.msl_version = _device->_pMetalFeatures->mslVersion;
shaderConfig.options.mslOptions.texel_buffer_texture_width = _device->_pMetalFeatures->maxTextureDimension;
shaderConfig.options.mslOptions.r32ui_linear_texture_alignment = (uint32_t)_device->getVkFormatTexelBufferAlignment(VK_FORMAT_R32_UINT, this);
shaderConfig.options.mslOptions.r32ui_linear_texture_alignment = (uint32_t)_device->getVkFormatTexelBufferAlignment(VK_FORMAT_R32_UINT);
shaderConfig.options.mslOptions.swizzle_texture_samples = _fullImageViewSwizzle && !getDevice()->_pMetalFeatures->nativeTextureSwizzle;
shaderConfig.options.mslOptions.texture_buffer_native = _device->_pMetalFeatures->textureBuffers;
shaderConfig.options.mslOptions.dispatch_base = _allowsDispatchBase;
Expand Down
1 change: 1 addition & 0 deletions MoltenVK/MoltenVK/Layers/MVKExtensions.def
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ MVK_EXTENSION(KHR_incremental_present, KHR_INCREMENTAL_PRESENT,
MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE, 10.11, 8.0, 1.0)
MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE, 10.11, 8.0, 1.0)
MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, DEVICE, 10.11, 8.0, 1.0)
MVK_EXTENSION(KHR_maintenance4, KHR_MAINTENANCE_4, DEVICE, 10.11, 8.0, 1.0)
MVK_EXTENSION(KHR_map_memory2, KHR_MAP_MEMORY_2, DEVICE, 10.11, 8.0, 1.0)
MVK_EXTENSION(KHR_multiview, KHR_MULTIVIEW, DEVICE, 10.11, 8.0, 1.0)
MVK_EXTENSION(KHR_portability_subset, KHR_PORTABILITY_SUBSET, DEVICE, 10.11, 8.0, 1.0)
Expand Down
49 changes: 46 additions & 3 deletions MoltenVK/MoltenVK/Vulkan/vulkan.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2814,9 +2814,44 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkDestroyPrivateDataSlot(
MVKTraceVulkanCallEnd();
}

MVK_PUBLIC_VULKAN_STUB(vkGetDeviceBufferMemoryRequirements, void, VkDevice, const VkDeviceBufferMemoryRequirements*, VkMemoryRequirements2*)
MVK_PUBLIC_VULKAN_STUB(vkGetDeviceImageMemoryRequirements, void, VkDevice, const VkDeviceImageMemoryRequirements*, VkMemoryRequirements2*)
MVK_PUBLIC_VULKAN_STUB(vkGetDeviceImageSparseMemoryRequirements, void, VkDevice, const VkDeviceImageMemoryRequirements*, uint32_t*, VkSparseImageMemoryRequirements2*)
MVK_PUBLIC_VULKAN_SYMBOL void vkGetDeviceBufferMemoryRequirements(
VkDevice device,
const VkDeviceBufferMemoryRequirements* pInfo,
VkMemoryRequirements2* pMemoryRequirements) {

MVKTraceVulkanCallStart();
auto* mvkDev = MVKDevice::getMVKDevice(device);
auto* buffer = new MVKBuffer(mvkDev, pInfo->pCreateInfo);
buffer->getMemoryRequirements(nullptr, pMemoryRequirements);
buffer->destroy();
MVKTraceVulkanCallEnd();
}

MVK_PUBLIC_VULKAN_SYMBOL void vkGetDeviceImageMemoryRequirements(
VkDevice device,
const VkDeviceImageMemoryRequirements* pInfo,
VkMemoryRequirements2* pMemoryRequirements) {

MVKTraceVulkanCallStart();
auto* mvkDev = MVKDevice::getMVKDevice(device);
auto* image = new MVKImage(mvkDev, pInfo->pCreateInfo);
image->getMemoryRequirements(pMemoryRequirements, MVKImage::getPlaneFromVkImageAspectFlags(pInfo->planeAspect));
image->destroy();
MVKTraceVulkanCallEnd();
}

MVK_PUBLIC_VULKAN_SYMBOL void vkGetDeviceImageSparseMemoryRequirements(
VkDevice device,
const VkDeviceImageMemoryRequirements* pInfo,
uint32_t* pSparseMemoryRequirementCount,
VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {

MVKTraceVulkanCallStart();
// Metal does not support sparse images
*pSparseMemoryRequirementCount = 0;
MVKTraceVulkanCallEnd();
}

MVK_PUBLIC_VULKAN_STUB_VKRESULT(vkGetPhysicalDeviceToolProperties, VkPhysicalDevice, uint32_t*, VkPhysicalDeviceToolProperties*)

MVK_PUBLIC_VULKAN_SYMBOL void vkGetPrivateData(
Expand Down Expand Up @@ -3067,6 +3102,14 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkDestroyDeferredOperationKHR(
MVK_PUBLIC_VULKAN_CORE_ALIAS(vkGetDescriptorSetLayoutSupport, KHR);


#pragma mark -
#pragma mark VK_KHR_maintenance4 extension

MVK_PUBLIC_VULKAN_CORE_ALIAS(vkGetDeviceBufferMemoryRequirements, KHR);
MVK_PUBLIC_VULKAN_CORE_ALIAS(vkGetDeviceImageMemoryRequirements, KHR);
MVK_PUBLIC_VULKAN_CORE_ALIAS(vkGetDeviceImageSparseMemoryRequirements, KHR);


#pragma mark -
#pragma mark VK_KHR_map_memory2 extension

Expand Down