Fix metal mip writes within compute pass (#1673)

* Fix mip writes via compute passes by creates subresource views

- Create metal subresource views so that we can write into correct mips for compute passes
- Remove code to set the correct slice/level for gfx passes as the view will be correct now
- Handle cubemap/cubemaparray/3d texture types as the drivers do not allow subresource views.
This commit is contained in:
moudgils
2021-06-30 10:44:59 -07:00
committed by GitHub
parent 6392788212
commit 9c3ebeba04
3 changed files with 52 additions and 29 deletions
@@ -34,20 +34,41 @@ namespace AZ
id<MTLTexture> mtlTexture = image.GetMemoryView().GetGpuAddress<id<MTLTexture>>();
MTLPixelFormat textureFormat = ConvertPixelFormat(image.GetDescriptor().m_format);
MTLPixelFormat textureViewFormat = ConvertPixelFormat(viewDescriptor.m_overrideFormat);
id<MTLTexture> textureView = nil;
if(viewDescriptor.m_overrideFormat != RHI::Format::Unknown)
bool isViewFormatDifferent = false;
//Check if we the viewformat differs from the base texture format
if(textureViewFormat != MTLPixelFormatInvalid)
{
MTLPixelFormat textureViewFormat = ConvertPixelFormat(viewDescriptor.m_overrideFormat);
//Create a unique texture if needed
if(textureFormat != textureViewFormat)
isViewFormatDifferent = textureViewFormat!=textureFormat;
}
//Since we divide the array length of a cubemap by NumCubeMapSlices when creating the base texture
//we have to do reverse of that here
uint32_t textureLength = mtlTexture.arrayLength;
if(imgDesc.m_isCubemap)
{
textureLength = textureLength * RHI::ImageDescriptor::NumCubeMapSlices;
}
//Create a new view if the format, mip range or slice range has changed
if( isViewFormatDifferent ||
levelRange.length != mtlTexture.mipmapLevelCount ||
sliceRange.length != textureLength)
{
//Protection against creating a view with an invalid format
//If view format is invalid use the base texture's format
if(textureViewFormat == MTLPixelFormatInvalid)
{
textureView = [mtlTexture newTextureViewWithPixelFormat : textureViewFormat
textureType : mtlTexture.textureType
levels : levelRange
slices : sliceRange];
AZ_Assert(false,"View format is invalid");
textureViewFormat = textureFormat;
}
textureView = [mtlTexture newTextureViewWithPixelFormat : textureViewFormat
textureType : mtlTexture.textureType
levels : levelRange
slices : sliceRange];
}
if(!textureView)
@@ -112,20 +133,21 @@ namespace AZ
{
const Image& image = static_cast<const Image&>(resourceBase);
const RHI::ImageDescriptor& imageDesc = image.GetDescriptor();
const RHI::ImageViewDescriptor& descriptor = GetDescriptor();
const RHI::ImageViewDescriptor& viewDescriptor = GetDescriptor();
RHI::ImageSubresourceRange& range = m_imageSubresourceRange;
range.m_mipSliceMin = descriptor.m_mipSliceMin;
range.m_mipSliceMax = AZStd::min(descriptor.m_mipSliceMax, static_cast<uint16_t>(imageDesc.m_mipLevels - 1));
if (imageDesc.m_dimension == RHI::ImageDimension::Image3D)
range.m_mipSliceMin = viewDescriptor.m_mipSliceMin;
range.m_mipSliceMax = AZStd::min(viewDescriptor.m_mipSliceMax, static_cast<uint16_t>(imageDesc.m_mipLevels - 1));
range.m_arraySliceMin = viewDescriptor.m_arraySliceMin;
range.m_arraySliceMax = AZStd::min(viewDescriptor.m_arraySliceMax, static_cast<uint16_t>(imageDesc.m_arraySize - 1));
//The length value of the sliceRange parameter must be a multiple of 6 if the texture
//is of type MTLTextureTypeCube or MTLTextureTypeCubeArray. Hence we cant really make
//a subresource view for these types.
if(imageDesc.m_isCubemap)
{
range.m_arraySliceMin = 0;
range.m_arraySliceMax = 0;
}
else
{
range.m_arraySliceMin = descriptor.m_arraySliceMin;
range.m_arraySliceMax = AZStd::min(descriptor.m_arraySliceMax, static_cast<uint16_t>(imageDesc.m_arraySize - 1));
range.m_arraySliceMax = static_cast<uint16_t>(imageDesc.m_arraySize - 1);
}
}
@@ -53,7 +53,6 @@ namespace AZ
//Internally it may create a new MTLTexture object that reinterprets the original MTLTexture object from Image
MemoryView m_memoryView;
RHI::ImageViewDescriptor m_descriptor;
MTLPixelFormat m_format;
RHI::ImageSubresourceRange m_imageSubresourceRange;
};
+10 -8
View File
@@ -180,15 +180,19 @@ namespace AZ
if(!m_isWritingToSwapChainScope)
{
if(renderTargetTexture.textureType == MTLTextureType3D)
{
m_renderPassDescriptor.colorAttachments[colorAttachmentIndex].depthPlane = imgViewDescriptor.m_depthSliceMin;
}
else
//Cubemap/cubemaparray and 3d textures have restrictions placed on them by the
//drivers when creating a new texture view. Hence we cant get a view with subresource range
//of the original texture. As a result in order to write into specific slice or depth plane
//we specify it here. It also means that we cant write into these texturee types via a compute shader
const RHI::ImageViewDescriptor& imgViewDescriptor = imageView->GetDescriptor();
if(renderTargetTexture.textureType == MTLTextureTypeCube || renderTargetTexture.textureType == MTLTextureTypeCubeArray)
{
m_renderPassDescriptor.colorAttachments[colorAttachmentIndex].slice = imgViewDescriptor.m_arraySliceMin;
}
m_renderPassDescriptor.colorAttachments[colorAttachmentIndex].level = imgViewDescriptor.m_mipSliceMin;
else if(renderTargetTexture.textureType == MTLTextureType3D)
{
m_renderPassDescriptor.colorAttachments[colorAttachmentIndex].depthPlane = imgViewDescriptor.m_depthSliceMin;
}
}
MTLRenderPassColorAttachmentDescriptor* colorAttachment = m_renderPassDescriptor.colorAttachments[colorAttachmentIndex];
@@ -222,8 +226,6 @@ namespace AZ
m_renderPassDescriptor.stencilAttachment.texture = imageViewMtlTexture;
}
m_renderPassDescriptor.depthAttachment.slice = imgViewDescriptor.m_arraySliceMin;
MTLRenderPassDepthAttachmentDescriptor* depthAttachment = m_renderPassDescriptor.depthAttachment;
MTLRenderPassStencilAttachmentDescriptor* stencilAttachment = m_renderPassDescriptor.stencilAttachment;
depthAttachment.loadAction = mtlLoadAction;