|
51 | 51 | if (_image->_is2DViewOn3DImageCompatible && !dvcMem->ensureMTLHeap()) {
|
52 | 52 | MVKAssert(0, "Creating a 2D view of a 3D texture currently requires a placement heap, which is not available.");
|
53 | 53 | }
|
| 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 | + } |
54 | 57 |
|
55 | 58 | // Use imported texture if we are binding to a VkDeviceMemory that was created with an import operation
|
56 | 59 | if (dvcMem && (dvcMem->_externalMemoryHandleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT) && dvcMem->_mtlTexture) {
|
@@ -1138,13 +1141,16 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
|
1138 | 1141 |
|
1139 | 1142 | // Metal before 3.0 doesn't support 3D compressed textures, so we'll
|
1140 | 1143 | // 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) { |
1145 | 1145 | mvkEnableFlags(mtlUsage, MTLTextureUsageShaderWrite);
|
1146 | 1146 | }
|
1147 | 1147 |
|
| 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 | + |
1148 | 1154 | return mtlUsage;
|
1149 | 1155 | }
|
1150 | 1156 |
|
@@ -1306,6 +1312,7 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
|
1306 | 1312 | }
|
1307 | 1313 |
|
1308 | 1314 | _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); |
1309 | 1316 | }
|
1310 | 1317 |
|
1311 | 1318 | VkSampleCountFlagBits MVKImage::validateSamples(const VkImageCreateInfo* pCreateInfo, bool isAttachment) {
|
@@ -1358,8 +1365,8 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
|
1358 | 1365 | if (isAttachment && (getImageType() == VK_IMAGE_TYPE_1D)) {
|
1359 | 1366 | 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."));
|
1360 | 1367 | }
|
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.")); |
1363 | 1370 | }
|
1364 | 1371 | if (mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT)) {
|
1365 | 1372 | 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) {
|
1860 | 1867 | id<MTLTexture> MVKImageViewPlane::newMTLTexture() {
|
1861 | 1868 | MTLTextureType mtlTextureType = _imageView->_mtlTextureType;
|
1862 | 1869 | 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 |
1864 | 1871 | id<MTLTexture> aliasTex = nil;
|
1865 | 1872 | auto* image = _imageView->_image;
|
1866 | 1873 | 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) { |
1870 | 1881 | 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"); |
1872 | 1883 |
|
1873 |
| - const auto relativeSliceOffset = _imageView->_subresourceRange.baseArrayLayer * (heapAllocation->size / image->_extent.depth); |
1874 | 1884 | MTLTextureDescriptor* mtlTexDesc = image->newMTLTextureDescriptor(_planeIndex); // temp retain
|
1875 | 1885 |
|
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 | + } |
1879 | 1903 |
|
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 |
1881 | 1905 | aliasTex = [heapAllocation->heap
|
1882 | 1906 | newTextureWithDescriptor: mtlTexDesc
|
1883 | 1907 | offset: heapAllocation->offset + relativeSliceOffset];
|
1884 | 1908 |
|
1885 | 1909 | [mtlTexDesc release]; // temp release
|
1886 | 1910 |
|
1887 | 1911 | mtlTex = aliasTex;
|
1888 |
| - sliceRange = NSMakeRange(0, _imageView->_subresourceRange.layerCount); |
1889 |
| - } else { |
| 1912 | + } |
| 1913 | + if (is2dViewOf3d && !alias2dViewOf3d) { |
1890 | 1914 | mtlTextureType = MTLTextureType3D;
|
1891 | 1915 | sliceRange = NSMakeRange(0, 1);
|
1892 | 1916 | }
|
@@ -2294,6 +2318,7 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) {
|
2294 | 2318 |
|
2295 | 2319 | _mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType,
|
2296 | 2320 | _image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT);
|
| 2321 | + _vkFormat = pCreateInfo->format; |
2297 | 2322 |
|
2298 | 2323 | // Per spec, for depth/stencil formats, determine the appropriate usage
|
2299 | 2324 | // based on whether stencil or depth or both aspects are being used.
|
|
0 commit comments