Skip to content

Commit 58300f6

Browse files
committed
Add support for VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT
1 parent 712fbb8 commit 58300f6

File tree

4 files changed

+55
-20
lines changed

4 files changed

+55
-20
lines changed

Docs/MoltenVK_Configuration_Parameters.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,9 @@ allocate textures and buffers from general device memory.
680680
Vulkan extension `VK_EXT_image_2d_view_of_3d` requires this parameter to be active,
681681
to allow aliasing of texture memory between the 3D image and the 2D view.
682682

683+
`VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT` also requires this parameter to be active,
684+
to allow aliasing of texture memory between the compressed image and the uncompressed view.
685+
683686
To force `MTLHeap` to be used on AMD GPUs, set this parameter to `2`.
684687
To disable the use of `MTLHeap` on any GPU, set this parameter to `0`.
685688

MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,9 +1521,12 @@
15211521
}
15221522
}
15231523

1524-
// Metal does not support creating uncompressed views of compressed formats.
1524+
// Metal does not support creating uncompressed views of compressed formats without aliasing with MTLHeap.
1525+
if (mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT) && !getMVKConfig().useMTLHeap) {
1526+
return VK_ERROR_FORMAT_NOT_SUPPORTED;
1527+
}
15251528
// Metal does not support split-instance images.
1526-
if (mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT | VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT)) {
1529+
if (mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT)) {
15271530
return VK_ERROR_FORMAT_NOT_SUPPORTED;
15281531
}
15291532

MoltenVK/MoltenVK/GPUObjects/MVKImage.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ class MVKImage : public MVKVulkanAPIDeviceObject {
402402
bool _shouldSupportAtomics;
403403
bool _isLinearForAtomics;
404404
bool _is2DViewOn3DImageCompatible = false;
405+
bool _isBlockTexelViewCompatible = false;
405406
};
406407

407408

@@ -597,6 +598,8 @@ class MVKImageView : public MVKVulkanAPIDeviceObject {
597598
/** Return the underlying image. */
598599
MVKImage* getImage() { return _image; }
599600

601+
bool getIsCompressed() { return getPixelFormats()->getFormatType(_vkFormat) == kMVKFormatCompressed; }
602+
600603
#pragma mark Metal
601604

602605
/** Returns the Metal texture underlying this image view. */
@@ -653,6 +656,7 @@ class MVKImageView : public MVKVulkanAPIDeviceObject {
653656
VkImageUsageFlags _usage;
654657
std::mutex _lock;
655658
MTLTextureType _mtlTextureType;
659+
VkFormat _vkFormat;
656660
};
657661

658662

MoltenVK/MoltenVK/GPUObjects/MVKImage.mm

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151
if (_image->_is2DViewOn3DImageCompatible && !dvcMem->ensureMTLHeap()) {
5252
MVKAssert(0, "Creating a 2D view of a 3D texture currently requires a placement heap, which is not available.");
5353
}
54+
if (_image->_isBlockTexelViewCompatible && !dvcMem->ensureMTLHeap()) {
55+
MVKAssert(0, "Creating an uncompressed view of a compressed texture currently requires a placement heap, which is not available.");
56+
}
5457

5558
// Use imported texture if we are binding to a VkDeviceMemory that was created with an import operation
5659
if (dvcMem && (dvcMem->_externalMemoryHandleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT) && dvcMem->_mtlTexture) {
@@ -1138,13 +1141,16 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
11381141

11391142
// Metal before 3.0 doesn't support 3D compressed textures, so we'll
11401143
// decompress the texture ourselves, and we need to be able to write to it.
1141-
// Additionally, the ability to create 2D alias over 3D image is dependent
1142-
// on write capability to synchronize correctly.
1143-
bool makeWritable = (MVK_MACOS && _is3DCompressed) || _is2DViewOn3DImageCompatible;
1144-
if (makeWritable) {
1144+
if (MVK_MACOS && _is3DCompressed) {
11451145
mvkEnableFlags(mtlUsage, MTLTextureUsageShaderWrite);
11461146
}
11471147

1148+
// For 2D views of 3D and block texel views, set pixel format view usage to ensure
1149+
// that Metal does not apply lossless compression so we can alias the underlying memory.
1150+
if (_is2DViewOn3DImageCompatible || _isBlockTexelViewCompatible) {
1151+
mvkEnableFlags(mtlUsage, MTLTextureUsagePixelFormatView);
1152+
}
1153+
11481154
return mtlUsage;
11491155
}
11501156

@@ -1306,6 +1312,7 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
13061312
}
13071313

13081314
_is2DViewOn3DImageCompatible = mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT);
1315+
_isBlockTexelViewCompatible = mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT);
13091316
}
13101317

13111318
VkSampleCountFlagBits MVKImage::validateSamples(const VkImageCreateInfo* pCreateInfo, bool isAttachment) {
@@ -1358,8 +1365,8 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
13581365
if (isAttachment && (getImageType() == VK_IMAGE_TYPE_1D)) {
13591366
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Metal does not support rendering to native 1D attachments. Consider enabling MVK_CONFIG_TEXTURE_1D_AS_2D."));
13601367
}
1361-
if (mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT)) {
1362-
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Metal does not allow uncompressed views of compressed images."));
1368+
if (mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT) && !getMVKConfig().useMTLHeap) {
1369+
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : MTLHeap must be enabled to create uncompressed views of compressed images."));
13631370
}
13641371
if (mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT)) {
13651372
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Metal does not support split-instance memory binding."));
@@ -1860,33 +1867,50 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) {
18601867
id<MTLTexture> MVKImageViewPlane::newMTLTexture() {
18611868
MTLTextureType mtlTextureType = _imageView->_mtlTextureType;
18621869
NSRange sliceRange = NSMakeRange(_imageView->_subresourceRange.baseArrayLayer, _imageView->_subresourceRange.layerCount);
1863-
// Fake support for 2D views of 3D textures.
1870+
// Fake support for 2D views of 3D textures and block texel views
18641871
id<MTLTexture> aliasTex = nil;
18651872
auto* image = _imageView->_image;
18661873
id<MTLTexture> mtlTex = image->getMTLTexture(_planeIndex);
1867-
if (image->getImageType() == VK_IMAGE_TYPE_3D &&
1868-
(mtlTextureType == MTLTextureType2D || mtlTextureType == MTLTextureType2DArray)) {
1869-
if (image->_is2DViewOn3DImageCompatible) {
1874+
const bool is2dViewOf3d = image->getImageType() == VK_IMAGE_TYPE_3D &&
1875+
(mtlTextureType == MTLTextureType2D || mtlTextureType == MTLTextureType2DArray);
1876+
const bool isBlockTexelView = image->getIsCompressed() != _imageView->getIsCompressed();
1877+
if (is2dViewOf3d || isBlockTexelView) {
1878+
const bool alias2dViewOf3d = is2dViewOf3d && image->_is2DViewOn3DImageCompatible;
1879+
const bool aliasBlockTexelView = isBlockTexelView && image->_isBlockTexelViewCompatible;
1880+
if (alias2dViewOf3d || aliasBlockTexelView) {
18701881
const auto heapAllocation = image->getHeapAllocation(_planeIndex);
1871-
MVKAssert(heapAllocation, "Attempting to create a 2D view of a 3D texture without a placement heap");
1882+
MVKAssert(heapAllocation, "Attempting to create a memory-aliased texture without a placement heap");
18721883

1873-
const auto relativeSliceOffset = _imageView->_subresourceRange.baseArrayLayer * (heapAllocation->size / image->_extent.depth);
18741884
MTLTextureDescriptor* mtlTexDesc = image->newMTLTextureDescriptor(_planeIndex); // temp retain
18751885

1876-
mtlTexDesc.depth = 1;
1877-
mtlTexDesc.arrayLength = _imageView->_subresourceRange.layerCount;
1878-
mtlTexDesc.textureType = mtlTextureType;
1886+
size_t relativeSliceOffset = 0;
1887+
if (alias2dViewOf3d) {
1888+
// Update descriptor and slice info with correct attributes and offsets for 2D view.
1889+
mtlTexDesc.depth = 1;
1890+
mtlTexDesc.arrayLength = _imageView->_subresourceRange.layerCount;
1891+
mtlTexDesc.textureType = mtlTextureType;
1892+
sliceRange = NSMakeRange(0, _imageView->_subresourceRange.layerCount);
1893+
relativeSliceOffset = _imageView->_subresourceRange.baseArrayLayer * (heapAllocation->size / image->_extent.depth);
1894+
}
1895+
if (aliasBlockTexelView) {
1896+
// Update pixel format and dimensions to match uncompressed view format.
1897+
// TODO: dEQP-VK.image.texel_view_compatible.graphic.extended.*
1898+
const VkExtent2D fmtBlockSize = getPixelFormats()->getBlockTexelSize(image->getVkFormat());
1899+
mtlTexDesc.pixelFormat = _mtlPixFmt;
1900+
mtlTexDesc.width = (mtlTexDesc.width + fmtBlockSize.width - 1) / fmtBlockSize.width;
1901+
mtlTexDesc.height = (mtlTexDesc.height + fmtBlockSize.height - 1) / fmtBlockSize.height;
1902+
}
18791903

1880-
// Create a temporary texture that is backed by the 3D texture's memory
1904+
// Create a temporary texture that is backed by the original texture's memory
18811905
aliasTex = [heapAllocation->heap
18821906
newTextureWithDescriptor: mtlTexDesc
18831907
offset: heapAllocation->offset + relativeSliceOffset];
18841908

18851909
[mtlTexDesc release]; // temp release
18861910

18871911
mtlTex = aliasTex;
1888-
sliceRange = NSMakeRange(0, _imageView->_subresourceRange.layerCount);
1889-
} else {
1912+
}
1913+
if (is2dViewOf3d && !alias2dViewOf3d) {
18901914
mtlTextureType = MTLTextureType3D;
18911915
sliceRange = NSMakeRange(0, 1);
18921916
}
@@ -2294,6 +2318,7 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) {
22942318

22952319
_mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType,
22962320
_image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT);
2321+
_vkFormat = pCreateInfo->format;
22972322

22982323
// Per spec, for depth/stencil formats, determine the appropriate usage
22992324
// based on whether stencil or depth or both aspects are being used.

0 commit comments

Comments
 (0)