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:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user