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 partial VK_EXT_image_2d_view_of_3d support #2332

Open
wants to merge 3 commits 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
12 changes: 12 additions & 0 deletions Docs/MoltenVK_Configuration_Parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -684,3 +684,15 @@ Determines the style used to implement _Vulkan_ semaphore (`VkSemaphore`) functi

In the special case of `VK_SEMAPHORE_TYPE_TIMELINE` semaphores, **MoltenVK** will always use
`MTLSharedEvent` if it is available on the platform, regardless of the value of this parameter.

---------------------------------------
#### MVK_CONFIG_ENABLE_2DVIEWOF3D
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason to have the app have to opt-in to this extension?

If not, I've run CTS on everything, and it all seems to be working fine, and doesn't seem to be interfering with other behaviour. I think I would be satisfied to remove MVK_CONFIG_ENABLE_2DVIEWOF3D and MVKConfiguration::enable2DViewOf3D, and then where you test for enable2DViewOf3D internally, use useMTLHeap instead.


##### Type: Boolean
##### Default: `0`

If enabled, **MoltenVK** will advertise the `VK_EXT_image_2d_view_of_3d` extension. The **MoltenVK** implementation of this extension uses
`MTLHeap`s to create 2D textures from memory allocated for 3D textures, which makes some assumptions about how a 3D texture's memory is laid
out by the metal driver.

Note that the use of this feature depends on `MVK_CONFIG_USE_MTLHEAP`.
1 change: 1 addition & 0 deletions MoltenVK/MoltenVK/API/mvk_private_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ typedef struct {
VkBool32 useMetalPrivateAPI; /**< MVK_CONFIG_USE_METAL_PRIVATE_API */
const char* shaderDumpDir; /**< MVK_CONFIG_SHADER_DUMP_DIR */
VkBool32 shaderLogEstimatedGLSL; /**< MVK_CONFIG_SHADER_LOG_ESTIMATED_GLSL */
VkBool32 enable2DViewOf3D; /**< MVK_CONFIG_VK_ENABLE_2DVIEWOF3D */
} MVKConfiguration;

// Legacy support for renamed struct elements.
Expand Down
13 changes: 12 additions & 1 deletion MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@
portabilityFeatures->imageViewFormatReinterpretation = true;
portabilityFeatures->imageViewFormatSwizzle = (_metalFeatures.nativeTextureSwizzle ||
getMVKConfig().fullImageViewSwizzle);
portabilityFeatures->imageView2DOn3DImage = false;
portabilityFeatures->imageView2DOn3DImage = getMVKConfig().enable2DViewOf3D;
portabilityFeatures->multisampleArrayImage = _metalFeatures.multisampleArrayTextures;
portabilityFeatures->mutableComparisonSamplers = _metalFeatures.depthSampleCompare;
portabilityFeatures->pointPolygons = false;
Expand Down Expand Up @@ -581,6 +581,17 @@
auto* shaderIntFuncsFeatures = (VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL*)next;
shaderIntFuncsFeatures->shaderIntegerFunctions2 = true;
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT: {
if (getMVKConfig().enable2DViewOf3D) {
auto* extFeatures = (VkPhysicalDeviceImage2DViewOf3DFeaturesEXT*)next;
extFeatures->image2DViewOf3D = true;

// TODO (ncesario-lunarg) Related CTS tests (e.g., dEQP-VK.pipeline.monolithic.image_2d_view_3d_image.compute.sampler.mip0_layer0)
// are failing with this enabled.
extFeatures->sampler2DViewOf3D = false;
}
break;
}
default:
break;
Expand Down
1 change: 1 addition & 0 deletions MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ MVK_DEVICE_FEATURE_EXTN(ShaderAtomicFloat, SHADER_ATOMIC_FLOAT,
MVK_DEVICE_FEATURE_EXTN(SwapchainMaintenance1, SWAPCHAIN_MAINTENANCE_1, EXT, 1)
MVK_DEVICE_FEATURE_EXTN(TexelBufferAlignment, TEXEL_BUFFER_ALIGNMENT, EXT, 1)
MVK_DEVICE_FEATURE_EXTN(VertexAttributeDivisor, VERTEX_ATTRIBUTE_DIVISOR, EXT, 2)
MVK_DEVICE_FEATURE_EXTN(Image2DViewOf3D, IMAGE_2D_VIEW_OF_3D, EXT, 2)
MVK_DEVICE_FEATURE_EXTN(ShaderIntegerFunctions2, SHADER_INTEGER_FUNCTIONS_2, INTEL, 1)

#pragma pop_macro("INTEL")
Expand Down
10 changes: 10 additions & 0 deletions MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ typedef struct MVKMappedMemoryRange {
VkDeviceSize size = 0;
} MVKMappedMemoryRange;

struct HeapAllocation {
id<MTLHeap> heap = nil; // Reference to the heap containing this allocation
size_t offset = 0; // Offset into the heap
size_t size = 0; // Total size of this allocation
size_t align = 0; // Allocation alignment requirement

bool isValid() const {
return (heap != nil) && (size != 0);
}
};

/** Represents a Vulkan device-space memory allocation. */
class MVKDeviceMemory : public MVKVulkanAPIDeviceObject {
Expand Down
14 changes: 5 additions & 9 deletions MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
Original file line number Diff line number Diff line change
Expand Up @@ -188,15 +188,11 @@
// Can't create MTLHeaps of zero size.
if (_allocationSize == 0) { return true; }

#if MVK_MACOS
// MTLHeaps on macOS must use private storage for now.
if (_mtlStorageMode != MTLStorageModePrivate) { return true; }
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of being removed, does this need to be modified to include a test for non-Apple-Silicon devices?

Copy link
Author

Choose a reason for hiding this comment

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

See comment below.

#endif
#if MVK_IOS
// MTLHeaps on iOS must use private or shared storage for now.
if ( !(_mtlStorageMode == MTLStorageModePrivate ||
_mtlStorageMode == MTLStorageModeShared) ) { return true; }
#endif
if (getPhysicalDevice()->getMTLDeviceCapabilities().isAppleGPU) {
// MTLHeaps on Apple silicon must use private or shared storage for now.
if ( !(_mtlStorageMode == MTLStorageModePrivate ||
_mtlStorageMode == MTLStorageModeShared) ) { return true; }
}

MTLHeapDescriptor* heapDesc = [MTLHeapDescriptor new];
heapDesc.type = MTLHeapTypePlacement;
Expand Down
6 changes: 6 additions & 0 deletions MoltenVK/MoltenVK/GPUObjects/MVKImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class MVKImagePlane : public MVKBaseObject {
id<MTLTexture> _mtlTexture;
std::unordered_map<NSUInteger, id<MTLTexture>> _mtlTextureViews;
MVKSmallVector<MVKImageSubresource, 1> _subresources;

HeapAllocation _heapAllocation;
};


Expand Down Expand Up @@ -233,6 +235,7 @@ class MVKImage : public MVKVulkanAPIDeviceObject {
/** Populates the specified transfer image descriptor data structure. */
void getTransferDescriptorData(MVKImageDescriptorData& imgData);

MTLTextureDescriptor* getTextureDescriptor(uint32_t planeIndex);

#pragma mark Resource memory

Expand Down Expand Up @@ -334,6 +337,8 @@ class MVKImage : public MVKVulkanAPIDeviceObject {
/** Returns the Metal CPU cache mode used by this image. */
MTLCPUCacheMode getMTLCPUCacheMode();

HeapAllocation* getHeapAllocation(uint32_t planeIndex);


#pragma mark Construction

Expand Down Expand Up @@ -395,6 +400,7 @@ class MVKImage : public MVKVulkanAPIDeviceObject {
bool _hasMutableFormat;
bool _shouldSupportAtomics;
bool _isLinearForAtomics;
bool _is2DViewOn3DImageCompatible = false;
};


Expand Down
62 changes: 46 additions & 16 deletions MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
MVKImageMemoryBinding* memoryBinding = getMemoryBinding();
MVKDeviceMemory* dvcMem = memoryBinding->_deviceMemory;

if (_image->_is2DViewOn3DImageCompatible && !dvcMem->ensureMTLHeap()) {
MVKAssert(0, "Creating a 2D view of a 3D texture currently requires a placement heap, which is not available.");
}

if (_image->_ioSurface) {
_mtlTexture = [_image->getMTLDevice()
newTextureWithDescriptor: mtlTexDesc
Expand All @@ -60,6 +64,11 @@
bytesPerRow: _subresources[0].layout.rowPitch];
} else if (dvcMem && dvcMem->getMTLHeap() && !_image->getIsDepthStencil()) {
// Metal support for depth/stencil from heaps is flaky
_heapAllocation.heap = dvcMem->getMTLHeap();
_heapAllocation.offset = memoryBinding->getDeviceMemoryOffset() + _subresources[0].layout.offset;
const auto texSizeAlign = [dvcMem->getMTLDevice() heapTextureSizeAndAlignWithDescriptor:mtlTexDesc];
_heapAllocation.size = texSizeAlign.size;
_heapAllocation.align = texSizeAlign.align;
_mtlTexture = [dvcMem->getMTLHeap()
newTextureWithDescriptor: mtlTexDesc
offset: memoryBinding->getDeviceMemoryOffset() + _subresources[0].layout.offset];
Expand Down Expand Up @@ -823,6 +832,10 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
imgData.usage = getCombinedUsage();
}

MTLTextureDescriptor* MVKImage::getTextureDescriptor(uint32_t planeIndex) {
return _planes[planeIndex]->newMTLTextureDescriptor();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

getTextureDescriptor() should be renamed to newMTLTextureDescriptor, to clarify that the returned object is retained, and needs to be released by the caller.

Since this function is only used once, it might be better to remove this getTextureDescriptor(), and replace its use with just _planes[planeIndex]->newMTLTextureDescriptor().


// Returns whether an MVKImageView can have the specified format.
// If the list of pre-declared view formats is not empty,
// and the format is not on that list, the view format is not valid.
Expand Down Expand Up @@ -1069,6 +1082,11 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
return _memoryBindings[0]->_deviceMemory ? _memoryBindings[0]->_deviceMemory->getMTLCPUCacheMode() : MTLCPUCacheModeDefaultCache;
}

HeapAllocation* MVKImage::getHeapAllocation(uint32_t planeIndex) {
auto& heapAllocation = _planes[planeIndex]->_heapAllocation;
return (heapAllocation.isValid()) ? &heapAllocation : nullptr;
}

MTLTextureUsage MVKImage::getMTLTextureUsage(MTLPixelFormat mtlPixFmt) {

// In the special case of a dedicated aliasable image, we must presume the texture can be used for anything.
Expand Down Expand Up @@ -1254,6 +1272,8 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) {
if (pExportInfo && pExportInfo->exportObjectType == VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT && !_ioSurface) {
setConfigurationResult(useIOSurface(nil));
}

_is2DViewOn3DImageCompatible = mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT);
}

VkSampleCountFlagBits MVKImage::validateSamples(const VkImageCreateInfo* pCreateInfo, bool isAttachment) {
Expand Down Expand Up @@ -1801,12 +1821,34 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) {
MTLTextureType mtlTextureType = _imageView->_mtlTextureType;
NSRange sliceRange = NSMakeRange(_imageView->_subresourceRange.baseArrayLayer, _imageView->_subresourceRange.layerCount);
// Fake support for 2D views of 3D textures.
if (_imageView->_image->getImageType() == VK_IMAGE_TYPE_3D &&
auto* image = _imageView->_image;
id<MTLTexture> mtlTex = image->getMTLTexture(_planeIndex);
if (image->getImageType() == VK_IMAGE_TYPE_3D &&
(mtlTextureType == MTLTextureType2D || mtlTextureType == MTLTextureType2DArray)) {
mtlTextureType = MTLTextureType3D;
sliceRange = NSMakeRange(0, 1);
if (!image->_is2DViewOn3DImageCompatible) {
mtlTextureType = MTLTextureType3D;
sliceRange = NSMakeRange(0, 1);
} else {
if (!_mtlTexture) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This test is unnecessary, since newMTLTexture() is only called if _mtlTexture is nil.

const auto heapAllocation = image->getHeapAllocation(_planeIndex);
MVKAssert(heapAllocation, "Attempting to create a 2D view of a 3D texture without a placement heap");
// TODO (ncesario-lunarg) untested where _imageView->subresourceRange.layerCount > 1, but VK_EXT_image_2d_view_of_3d
// allows for 2D_ARRAY views of 3D textures.
const auto relativeSliceOffset = _imageView->_subresourceRange.baseArrayLayer * (heapAllocation->size / image->_extent.depth);
MTLTextureDescriptor* mtlTexDesc = image->getTextureDescriptor(_planeIndex);
Copy link
Contributor

Choose a reason for hiding this comment

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

mtlTexDesc will leak if it isn't released after it is used. See other uses of newMTLTextureDescriptor() for guidance on that.


mtlTexDesc.depth = _imageView->_subresourceRange.layerCount;
mtlTexDesc.textureType = mtlTextureType;

// Create a temporary texture that is backed by the 3D texture's memory
_mtlTexture = [heapAllocation->heap
newTextureWithDescriptor: mtlTexDesc
offset: heapAllocation->offset + relativeSliceOffset];
Copy link
Contributor

Choose a reason for hiding this comment

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

Two issues here.

  1. This unexpectedly plugs a value into _mtlTexture, which will be overridden by the value returned by this function.

  2. The new MTLTexture created here is retained, and will leak if it is not released at some point.

I suggest:

  • Declare a id<MTLTexture> aliasTex = nil; at the top of this function.
  • Assign aliasTex here from the call to newTextureWithDescriptor(), and set mtlTex = aliasTex;.
  • Replace the two return [mtlTex newTextureView... below with texView = [mtlTex newTextureView....
  • End the function with:
[aliasTex release];
return texView;

It's important to release aliasTex after texView has been created, and aliasTex will be retained within texView, and will be released and deallocated when texView is released and deallocated.

}
mtlTex = _mtlTexture;
sliceRange = NSMakeRange(0, _imageView->_subresourceRange.layerCount);
}
}
id<MTLTexture> mtlTex = _imageView->_image->getMTLTexture(_planeIndex);
if (_useNativeSwizzle) {
return [mtlTex newTextureViewWithPixelFormat: _mtlPixFmt
textureType: mtlTextureType
Expand Down Expand Up @@ -2235,18 +2277,6 @@ static void signalAndUntrack(const MVKSwapchainSignaler& signaler) {
}
}

VkImageType imgType = _image->getImageType();
VkImageViewType viewType = pCreateInfo->viewType;

// VK_KHR_maintenance1 supports taking 2D image views of 3D slices for sampling.
// No dice in Metal. But we are able to fake out a 3D render attachment by making the Metal view
// itself a 3D texture (when we create it), and setting the rendering depthPlane appropriately.
if ((viewType == VK_IMAGE_VIEW_TYPE_2D || viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) && (imgType == VK_IMAGE_TYPE_3D)) {
if (!mvkIsOnlyAnyFlagEnabled(_usage, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImageView(): 2D views on 3D images can only be used as color attachments."));
}
}

// If a 2D array view on a 2D image with layerCount 1, and the only usages are
// attachment usages, then force the use of a 2D non-arrayed view. This is important for
// input attachments, or they won't match the types declared in the fragment shader.
Expand Down
5 changes: 5 additions & 0 deletions MoltenVK/MoltenVK/Layers/MVKExtensions.def
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ MVK_EXTENSION(EXT_swapchain_maintenance1, EXT_SWAPCHAIN_MAINTENANCE_
MVK_EXTENSION(EXT_texel_buffer_alignment, EXT_TEXEL_BUFFER_ALIGNMENT, DEVICE, 10.13, 11.0, 1.0)
MVK_EXTENSION(EXT_texture_compression_astc_hdr, EXT_TEXTURE_COMPRESSION_ASTC_HDR, DEVICE, 11.0, 13.0, 1.0)
MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR, DEVICE, 10.11, 8.0, 1.0)

#ifdef MVK_CONFIG_ENABLE_2DVIEWOF3D
MVK_EXTENSION(EXT_image_2d_view_of_3d, EXT_IMAGE_2D_VIEW_OF_3D, DEVICE, 10.15, 13.0, 1.0)
Copy link

Choose a reason for hiding this comment

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

Do you think we can modify mvkIsSupportedOnPlatform check and not advertise support on this when the config flag is not enabled?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, I'll wrap that in an #ifdef.

Copy link
Contributor

Choose a reason for hiding this comment

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

Wrapping in #ifdef here only works for environment variables, and not VK_EXT_layer_settings.

To properly support allowing this extension to be enabled via settings, use something like:

pWritableExtns->vk_EXT_image_2d_view_of_3d.enabled = getMVKConfig().enable2DViewOf3D;

in MVKPhysicalDevice::initExtensions().

However, see my question above about whether we need to have this configurable at all.

#endif

MVK_EXTENSION(AMD_draw_indirect_count, AMD_DRAW_INDIRECT_COUNT, DEVICE, MVK_NA, MVK_NA, MVK_NA)
MVK_EXTENSION(AMD_gpu_shader_half_float, AMD_GPU_SHADER_HALF_FLOAT, DEVICE, 10.11, 8.0, 1.0)
MVK_EXTENSION(AMD_negative_viewport_height, AMD_NEGATIVE_VIEWPORT_HEIGHT, DEVICE, 10.11, 8.0, 1.0)
Expand Down
1 change: 1 addition & 0 deletions MoltenVK/MoltenVK/Utility/MVKConfigMembers.def
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ MVK_CONFIG_MEMBER(timestampPeriodLowPassAlpha, float,
MVK_CONFIG_MEMBER(useMetalPrivateAPI, VkBool32, USE_METAL_PRIVATE_API)
MVK_CONFIG_MEMBER_STRING(shaderDumpDir, char*, SHADER_DUMP_DIR)
MVK_CONFIG_MEMBER(shaderLogEstimatedGLSL, VkBool32, SHADER_LOG_ESTIMATED_GLSL)
MVK_CONFIG_MEMBER(enable2DViewOf3D, VkBool32, ENABLE_2DVIEWOF3D)

#undef MVK_CONFIG_MEMBER
#undef MVK_CONFIG_MEMBER_STRING
Expand Down
5 changes: 2 additions & 3 deletions MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@
// Return the expected size of MVKConfiguration, based on contents of MVKConfigMembers.def.
static constexpr uint32_t getExpectedMVKConfigurationSize() {
#define MVK_CONFIG_MEMBER(member, mbrType, name) cfgSize += sizeof(mbrType);
uint32_t cfgSize = 0;
size_t cfgSize = 0;
#include "MVKConfigMembers.def"
cfgSize += kMVKConfigurationInternalPaddingByteCount;
Copy link
Author

Choose a reason for hiding this comment

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

@billhollings This seemed to be calculating the incorrect size, but perhaps that meant I added the config member incorrectly? I changed this function to align the expected size to the alignment of MVKConfiguration; please let me know if something is "off" here.

Copy link

Choose a reason for hiding this comment

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

iiuc, this is to make the padding requirement of the structure clearer and it expects modification to kMVKConfigurationInternalPaddingByteCount with the new additions, as the real size of the structure seems to be important for backwards compatibility. I believe with this new version, adding a new item only to the .def file when there is a padding in the structure (or in some cases adding an item to the both sides with different sizes) won't generate an error. Both paths are prone to errors and probably it should use a better protocol, but it might be easier to follow the changes with with an explicit padding value.

Otherwise, I don't see any other functionality of kMVKConfigurationInternalPaddingByteCount variable, and if this is going to be submitted, maybe that value can be removed as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

Have a look at the description of kMVKConfigurationInternalPaddingByteCount. It's sole purpose is to adjust the calculation of:

static_assert(getExpectedMVKConfigurationSize() == sizeof(MVKConfiguration), "MVKConfigMembers.def does not match the members of MVKConfiguration.");

And the purpose of that static_assert() is to ensure that the members of MVKConfiguration are all accounted for in MVKConfigMembers.def (ie- a dev mod isn't made to MVKConfiguration without adding the corrsponding entry in MVKConfigMembers.def), which would be tough to debug.

The reason kMVKConfigurationInternalPaddingByteCount is needed is to account for alignment padding that the compiler adds to sizeof(MVKConfiguration).

The solution to the issue you have dealt with here is to adjust the value of kMVKConfigurationInternalPaddingByteCount accordingly. In this specific case, the value should be set to 0, instead of removing the padding calculation. The next time an entry is added to MVKConfiguration, it will need to be set to a different value, and the padding calculation needs to be available.

return cfgSize;
return (uint32_t)((cfgSize + (alignof(MVKConfiguration) - 1)) & ~(alignof(MVKConfiguration) - 1));
}

// Return the expected number of string members in MVKConfiguration, based on contents of MVKConfigMembers.def.
Expand Down
4 changes: 4 additions & 0 deletions MoltenVK/MoltenVK/Utility/MVKEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -370,3 +370,7 @@ void mvkSetConfig(MVKConfiguration& dstMVKConfig, const MVKConfiguration& srcMVK
# define MVK_CONFIG_SHADER_LOG_ESTIMATED_GLSL 0
#endif

/** Advertise VK_EXT_image_2d_view_of_3d */
#ifndef MVK_CONFIG_ENABLE_2DVIEWOF3D
# define MVK_CONFIG_ENABLE_2DVIEWOF3D 0
#endif
Loading