diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ImageView.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ImageView.cpp index 916d1ba793..14d042a2d3 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ImageView.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ImageView.cpp @@ -34,20 +34,41 @@ namespace AZ id mtlTexture = image.GetMemoryView().GetGpuAddress>(); MTLPixelFormat textureFormat = ConvertPixelFormat(image.GetDescriptor().m_format); - + MTLPixelFormat textureViewFormat = ConvertPixelFormat(viewDescriptor.m_overrideFormat); + id 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(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(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(imageDesc.m_mipLevels - 1)); + range.m_arraySliceMin = viewDescriptor.m_arraySliceMin; + range.m_arraySliceMax = AZStd::min(viewDescriptor.m_arraySliceMax, static_cast(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(imageDesc.m_arraySize - 1)); + range.m_arraySliceMax = static_cast(imageDesc.m_arraySize - 1); } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ImageView.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ImageView.h index 0609086ddb..e3fe8909c7 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ImageView.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ImageView.h @@ -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; }; diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/Scope.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/Scope.cpp index d176078563..691ecdc295 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/Scope.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/Scope.cpp @@ -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;