-
Notifications
You must be signed in to change notification settings - Fork 433
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
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for getting this started!
In addition to the inline change requests, I recognize this is just to solve one immediate extension issue, but if we can do what we can to simplify a future move to using MTLHeaps
, we should try as best we can.
@@ -188,10 +188,6 @@ | |||
// 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; } |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment below.
#if MVK_MACOS | ||
// MTLHeaps on macOS must use private storage for now. | ||
if (_mtlStorageMode != MTLStorageModePrivate) { return true; } | ||
#endif | ||
#if MVK_IOS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should both this section and the one above, be replaced with a single test for MVKMTLDeviceCapabilities.isAppleGPU
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH I'm not sure based on the docs, but I'll add that to be on the safe side. It looked like the usage of heaps in MoltenVK was mainly dependent on placement heaps, but my knowledge is still pretty sparse on the details here.
@@ -48,6 +48,16 @@ typedef struct { | |||
class MVKImagePlane : public MVKBaseObject { | |||
|
|||
public: | |||
struct HeapAllocation { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this declaration be moved to MVKDeviceMemory
or MVKResource
, since heaps can be used by buffers too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, I'll move it there.
- @aitor-lunarg as this is something that may have a more straightforward approach with WIP: Proposal to base VkDeviceMemory on MTLHeap always #2309.
@@ -1066,6 +1079,11 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) { | |||
return _memoryBindings[0]->_deviceMemory ? _memoryBindings[0]->_deviceMemory->getMTLCPUCacheMode() : MTLCPUCacheModeDefaultCache; | |||
} | |||
|
|||
MVKImagePlane::HeapAllocation* MVKImage::getHeapAllocation(uint32_t planeIndex) { | |||
auto& heapAllocation = _planes[planeIndex]->_heapAllocation; | |||
return (heapAllocation) ? &heapAllocation : nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It surprised me that this was compiling, until I noticed the operator bool()
on the struct above.
While clever, we don't use this design pattern anywhere else, so I'm concerned others will balk the same way I did.
Maybe rename operator bool()
to bool isValid()
, for clarity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to isValid()
.
@@ -1251,6 +1269,8 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) { | |||
if (pExportInfo && pExportInfo->exportObjectType == VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT && !_ioSurface) { | |||
setConfigurationResult(useIOSurface(nil)); | |||
} | |||
|
|||
_is2DViewCompatible = pCreateInfo->flags & VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use mvkIsAnyFlagEnabled()
for consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -395,6 +410,7 @@ class MVKImage : public MVKVulkanAPIDeviceObject { | |||
bool _hasMutableFormat; | |||
bool _shouldSupportAtomics; | |||
bool _isLinearForAtomics; | |||
bool _is2DViewCompatible = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this will apply only to 2D on 3D, and not for all 2D views?
Maybe rename to _is2DViewOn3DImageCompatible
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, makes sense. Done.
size_t size = 0; // Total size of this allocation | ||
size_t align = 0; // Allocation alignment requirement | ||
|
||
operator bool() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment below where this is used. Probably best to rename this to something like bool isValid()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Done
|
||
// For now, this is only used for VK_EXT_image_2d_view_of_3d. Specifically, when the backing image of this view is 3D and the view is 2D, | ||
// this texture will be allocated using a placement heap "on top of" the 3D textures backing memory. | ||
id<MTLTexture> _mtlShadowTexture; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since _mtlTexture
end up holding a reference to the same object, does this need to be a separate iVar than _mtlTexture
?
If it is needed for some reason, move it up just below the _mtlTexture
declaration. We try to organize iVars to minimize gaps in the underlying class structure (ie- keep all 8-byte iVars together).
It also feels dangerous that the MTLTexture
is not retained in both _mtlTexture
and _mtlShadowTexture
, and released from both in the destructor. If in the future, we might possibly have different objects in the two iVars, then we'll end up with a hard to discover memory leak.
Finally, maybe it's me, but when I see _mtlShadowTexture
, I keep thinking "shadow map texture". Maybe rename it to _mtlAliasTexture
or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, there is no need for the extra MTLTexture in MVKImageViewPlane; I will remove it. I added this from a debug session and never reverted it (and also forgot to clean it up in the destructor when I was using it :/).
Thanks for the review @billhollings! I've made the changes you've suggested locally, but I'm hitting a crash on |
d01e7ec
to
ba83997
Compare
Does this PR impact the |
ba83997
to
ce6e1fc
Compare
@squidbus yes it does, and I had mistakenly not enabled that, but it should be enabled now. |
Given a 3D texture that is backed by a placement heap in MoltenVK, the approach taken here is to create a 2D texture that is backed by memory pointing into a 3D texture's memory. While ideal compared to alternative implementation solutions for this extension, this approach is sensitive to how Apple lays out the memory for 3D textures. The solution here uses heapTextureSizeAndAlignWithDescriptor to determine the overall size of a given 3D texture and index into the beginning of each "slice" of the 3D texture. So far this is good enough for storage images in CTS.
ce6e1fc
to
3329d40
Compare
#include "MVKConfigMembers.def" | ||
cfgSize += kMVKConfigurationInternalPaddingByteCount; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
3329d40
to
962c94f
Compare
@@ -144,6 +144,7 @@ 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) | |||
MVK_EXTENSION(EXT_image_2d_view_of_3d, EXT_IMAGE_2D_VIEW_OF_3D, DEVICE, 10.15, 13.0, 1.0) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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.
Since the implementation makes some assumptions as to how 3D texture memory is laid out by the metal driver, only advertise VK_EXT_image_2d_view_of_3d if MVK_CONFIG_ENABLE_2DVIEWOF3D is enabled. MVK_CONFIG_ENABLE_2DVIEWOF3D is off by default.
Sets VkPhysicalDeviceImage2DViewOf3DFeaturesEXT::sampler2DViewOf3D to false, as CTS tests involving 2D views of sampled 3D textures are not currently working.
962c94f
to
2a62041
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for getting this ready for release!
I've made a few change requests to catch a few potential memory leaks and simplify the configuration option.
@@ -144,6 +144,7 @@ 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) | |||
MVK_EXTENSION(EXT_image_2d_view_of_3d, EXT_IMAGE_2D_VIEW_OF_3D, DEVICE, 10.15, 13.0, 1.0) |
There was a problem hiding this comment.
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.
@@ -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 |
There was a problem hiding this comment.
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.
#include "MVKConfigMembers.def" | ||
cfgSize += kMVKConfigurationInternalPaddingByteCount; |
There was a problem hiding this comment.
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.
@@ -823,6 +832,10 @@ static MTLRegion getMTLRegion(const ImgRgn& imgRgn) { | |||
imgData.usage = getCombinedUsage(); | |||
} | |||
|
|||
MTLTextureDescriptor* MVKImage::getTextureDescriptor(uint32_t planeIndex) { | |||
return _planes[planeIndex]->newMTLTextureDescriptor(); | |||
} |
There was a problem hiding this comment.
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()
.
// 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); |
There was a problem hiding this comment.
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.
mtlTextureType = MTLTextureType3D; | ||
sliceRange = NSMakeRange(0, 1); | ||
} else { | ||
if (!_mtlTexture) { |
There was a problem hiding this comment.
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
.
// Create a temporary texture that is backed by the 3D texture's memory | ||
_mtlTexture = [heapAllocation->heap | ||
newTextureWithDescriptor: mtlTexDesc | ||
offset: heapAllocation->offset + relativeSliceOffset]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two issues here.
-
This unexpectedly plugs a value into
_mtlTexture
, which will be overridden by the value returned by this function. -
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 tonewTextureWithDescriptor()
, and setmtlTex = aliasTex;
. - Replace the two
return [mtlTex newTextureView...
below withtexView = [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.
Given a 3D texture that is backed by a placement heap in MoltenVK, the
approach taken here is to create a 2D texture that is backed by memory
pointing into a 3D texture's memory.
While ideal compared to alternative implementation solutions for this
extension, this approach is sensitive to how Apple lays out the memory
for 3D textures. The solution here uses
heapTextureSizeAndAlignWithDescriptor to determine the overall size of a
given 3D texture and index into the beginning of each "slice" of the 3D
texture. So far this is good enough for storage images in CTS.
FYI @kocdemir.