You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Atom/RHI/Code/Source/RHI.Reflect/ImageSubresource.cpp

389 lines
15 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/RHI.Reflect/ImageSubresource.h>
#include <Atom/RHI.Reflect/ImageDescriptor.h>
#include <Atom/RHI.Reflect/ImageViewDescriptor.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
namespace RHI
{
ImageSubresource::ImageSubresource(uint16_t mipSlice, uint16_t arraySlice)
: m_mipSlice{mipSlice}
, m_arraySlice{arraySlice}
{}
ImageSubresource::ImageSubresource(uint16_t mipSlice, uint16_t arraySlice, ImageAspect aspect)
: m_mipSlice{ mipSlice }
, m_arraySlice{ arraySlice }
, m_aspect{ aspect }
{}
void ImageSubresource::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ImageSubresource>()
->Version(0)
->Field("m_mipSlice", &ImageSubresource::m_mipSlice)
->Field("m_arraySlice", &ImageSubresource::m_arraySlice)
->Field("m_aspect", &ImageSubresource::m_aspect)
;
}
}
ImageSubresourceRange::ImageSubresourceRange(
uint16_t mipSliceMin,
uint16_t mipSliceMax,
uint16_t arraySliceMin,
uint16_t arraySliceMax)
: m_mipSliceMin{mipSliceMin}
, m_mipSliceMax{mipSliceMax}
, m_arraySliceMin{arraySliceMin}
, m_arraySliceMax{arraySliceMax}
{}
ImageSubresourceRange::ImageSubresourceRange(const ImageDescriptor& descriptor)
: m_mipSliceMin{ 0 }
, m_mipSliceMax{ aznumeric_caster(descriptor.m_mipLevels - 1) }
, m_arraySliceMin{ 0 }
, m_arraySliceMax{ aznumeric_caster(descriptor.m_arraySize - 1) }
, m_aspectFlags{ GetImageAspectFlags(descriptor.m_format) }
{
}
ImageSubresourceRange::ImageSubresourceRange(const ImageViewDescriptor& descriptor)
: m_mipSliceMin{ descriptor.m_mipSliceMin }
, m_mipSliceMax{ descriptor.m_mipSliceMax }
, m_arraySliceMin{ descriptor.m_arraySliceMin }
, m_arraySliceMax{ descriptor.m_arraySliceMax }
, m_aspectFlags{ descriptor.m_aspectFlags }
{
}
bool ImageSubresourceRange::operator==(const ImageSubresourceRange& other) const
{
return
m_mipSliceMin == other.m_mipSliceMin &&
m_mipSliceMax == other.m_mipSliceMax &&
m_arraySliceMin == other.m_arraySliceMin &&
m_arraySliceMax == other.m_arraySliceMax &&
m_aspectFlags == other.m_aspectFlags;
}
void ImageSubresourceRange::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ImageSubresourceRange>()
->Version(0)
->Field("m_mipSliceMin", &ImageSubresourceRange::m_mipSliceMin)
->Field("m_mipSliceMax", &ImageSubresourceRange::m_mipSliceMax)
->Field("m_arraySliceMin", &ImageSubresourceRange::m_arraySliceMin)
->Field("m_arraySliceMax", &ImageSubresourceRange::m_arraySliceMax)
->Field("m_aspectFlags", &ImageSubresourceRange::m_aspectFlags)
;
}
}
void ImageSubresourceLayout::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ImageSubresourceLayout>()
->Version(1)
->Field("m_size", &ImageSubresourceLayout::m_size)
->Field("m_rowCount", &ImageSubresourceLayout::m_rowCount)
->Field("m_bytesPerRow", &ImageSubresourceLayout::m_bytesPerRow)
->Field("m_bytesPerImage", &ImageSubresourceLayout::m_bytesPerImage)
->Field("m_blockElementWidth", &ImageSubresourceLayout::m_blockElementWidth)
->Field("m_blockElementHeight", &ImageSubresourceLayout::m_blockElementHeight)
;
}
}
ImageSubresourceLayout::ImageSubresourceLayout(
Size size,
uint32_t rowCount,
uint32_t bytesPerRow,
uint32_t bytesPerImage,
uint32_t blockElementWidth,
uint32_t blockElementHeight)
: m_size{size}
, m_rowCount{rowCount}
, m_bytesPerRow{bytesPerRow}
, m_bytesPerImage{bytesPerImage}
, m_blockElementWidth{blockElementWidth}
, m_blockElementHeight{blockElementHeight}
{}
ImageSubresourceLayoutPlaced::ImageSubresourceLayoutPlaced(const ImageSubresourceLayout& subresourceLayout, uint32_t offset)
: ImageSubresourceLayout(subresourceLayout)
, m_offset{offset}
{}
void ImageSubresourceLayoutPlaced::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ImageSubresourceLayoutPlaced, ImageSubresourceLayout>()
->Version(0)
->Field("m_offset", &ImageSubresourceLayoutPlaced::m_offset)
;
}
}
ImageSubresourceLayout GetImageSubresourceLayout(Size imageSize, Format imageFormat)
{
ImageSubresourceLayout subresourceLayout;
bool isBlockCompressed = false;
bool isPacked = false;
bool isPlanar = false;
uint32_t bytesPerElement = 0; //For block compressions this is bytesPerBlock
uint32_t numBlocks = 0;
switch (imageFormat)
{
case Format::R32G32B32A32_FLOAT:
case Format::R32G32B32A32_UINT:
case Format::R32G32B32A32_SINT:
case Format::R32G32B32_FLOAT:
case Format::R32G32B32_UINT:
case Format::R32G32B32_SINT:
case Format::R16G16B16A16_FLOAT:
case Format::R16G16B16A16_UNORM:
case Format::R16G16B16A16_UINT:
case Format::R16G16B16A16_SNORM:
case Format::R16G16B16A16_SINT:
case Format::R32G32_FLOAT:
case Format::R32G32_UINT:
case Format::R32G32_SINT:
case Format::D32_FLOAT_S8X24_UINT:
case Format::R10G10B10A2_UNORM:
case Format::R10G10B10A2_UINT:
case Format::R11G11B10_FLOAT:
case Format::R8G8B8A8_UNORM:
case Format::R8G8B8A8_UNORM_SRGB:
case Format::R8G8B8A8_UINT:
case Format::R8G8B8A8_SNORM:
case Format::R8G8B8A8_SINT:
case Format::R16G16_FLOAT:
case Format::R16G16_UNORM:
case Format::R16G16_UINT:
case Format::R16G16_SNORM:
case Format::R16G16_SINT:
case Format::D32_FLOAT:
case Format::R32_FLOAT:
case Format::R32_UINT:
case Format::R32_SINT:
case Format::D24_UNORM_S8_UINT:
case Format::B8G8R8A8_UNORM:
case Format::B8G8R8X8_UNORM:
case Format::B8G8R8A8_UNORM_SRGB:
case Format::B8G8R8X8_UNORM_SRGB:
case Format::R8G8_UNORM:
case Format::R8G8_UINT:
case Format::R8G8_SNORM:
case Format::R8G8_SINT:
case Format::R16_FLOAT:
case Format::D16_UNORM:
case Format::R16_UNORM:
case Format::R16_UINT:
case Format::R16_SNORM:
case Format::R16_SINT:
case Format::R8_UNORM:
case Format::R8_UINT:
case Format::R8_SNORM:
case Format::R8_SINT:
case Format::A8_UNORM:
case Format::R1_UNORM:
case Format::R9G9B9E5_SHAREDEXP:
break;
case RHI::Format::BC1_UNORM:
case RHI::Format::BC1_UNORM_SRGB:
case RHI::Format::BC4_UNORM:
case RHI::Format::BC4_SNORM:
isBlockCompressed = true;
bytesPerElement = 8;
numBlocks = 4;
break;
case RHI::Format::BC2_UNORM:
case RHI::Format::BC2_UNORM_SRGB:
case RHI::Format::BC3_UNORM:
case RHI::Format::BC3_UNORM_SRGB:
case RHI::Format::BC5_UNORM:
case RHI::Format::BC5_SNORM:
case RHI::Format::BC6H_UF16:
case RHI::Format::BC6H_SF16:
case RHI::Format::BC7_UNORM:
case RHI::Format::BC7_UNORM_SRGB:
case RHI::Format::ASTC_4x4_UNORM:
case RHI::Format::ASTC_4x4_UNORM_SRGB:
isBlockCompressed = true;
bytesPerElement = 16;
numBlocks = 4;
break;
case RHI::Format::ASTC_6x6_UNORM:
case RHI::Format::ASTC_6x6_UNORM_SRGB:
isBlockCompressed = true;
bytesPerElement = 16;
numBlocks = 6;
break;
case RHI::Format::ASTC_8x8_UNORM:
case RHI::Format::ASTC_8x8_UNORM_SRGB:
isBlockCompressed = true;
bytesPerElement = 16;
numBlocks = 8;
break;
case RHI::Format::ASTC_10x10_UNORM:
case RHI::Format::ASTC_10x10_UNORM_SRGB:
isBlockCompressed = true;
bytesPerElement = 16;
numBlocks = 10;
break;
case RHI::Format::ASTC_12x12_UNORM:
case RHI::Format::ASTC_12x12_UNORM_SRGB:
isBlockCompressed = true;
bytesPerElement = 16;
numBlocks = 12;
break;
case RHI::Format::R8G8_B8G8_UNORM:
case RHI::Format::G8R8_G8B8_UNORM:
case RHI::Format::YUY2:
isPacked = true;
bytesPerElement = 4;
break;
case RHI::Format::Y210:
case RHI::Format::Y216:
isPacked = true;
bytesPerElement = 8;
break;
case RHI::Format::NV12:
break;
case RHI::Format::P010:
case RHI::Format::P016:
isPlanar = true;
bytesPerElement = 4;
break;
case RHI::Format::ETC2_UNORM:
case RHI::Format::ETC2_UNORM_SRGB:
case RHI::Format::ETC2A1_UNORM:
case RHI::Format::ETC2A1_UNORM_SRGB:
isBlockCompressed = true;
bytesPerElement = 8;
numBlocks = 4;
break;
case RHI::Format::ETC2A_UNORM:
case RHI::Format::ETC2A_UNORM_SRGB:
isBlockCompressed = true;
bytesPerElement = 16;
numBlocks = 4;
break;
case RHI::Format::EAC_R11_UNORM:
case RHI::Format::EAC_R11_SNORM:
isBlockCompressed = true;
bytesPerElement = 8;
numBlocks = 4;
break;
case RHI::Format::EAC_RG11_UNORM:
case RHI::Format::EAC_RG11_SNORM:
isBlockCompressed = true;
bytesPerElement = 16;
numBlocks = 4;
break;
default:
AZ_Assert(false, "Unimplemented esoteric format %i.", static_cast<int>(imageFormat));
}
if (isBlockCompressed)
{
uint32_t numBlocksWide = 0;
if (imageSize.m_width > 0)
{
numBlocksWide = AZStd::max<uint32_t>(1, (imageSize.m_width + (numBlocks - 1)) / numBlocks);
}
uint32_t numBlocksHigh = 0;
if (imageSize.m_height > 0)
{
numBlocksHigh = AZStd::max<uint32_t>(1, (imageSize.m_height + (numBlocks - 1)) / numBlocks);
}
subresourceLayout.m_bytesPerRow = numBlocksWide * bytesPerElement;
subresourceLayout.m_rowCount = numBlocksHigh;
subresourceLayout.m_size.m_width = imageSize.m_width;
subresourceLayout.m_size.m_height = imageSize.m_height;
subresourceLayout.m_blockElementWidth = numBlocks;
subresourceLayout.m_blockElementHeight = numBlocks;
}
else if (isPacked)
{
subresourceLayout.m_bytesPerRow = ((imageSize.m_width + 1) >> 1) * bytesPerElement;
subresourceLayout.m_rowCount = imageSize.m_height;
subresourceLayout.m_size.m_width = imageSize.m_width;
subresourceLayout.m_size.m_height = imageSize.m_height;
}
else if (imageFormat == RHI::Format::NV11)
{
subresourceLayout.m_bytesPerRow = ((imageSize.m_width + 3) >> 2) * 4;
subresourceLayout.m_rowCount = imageSize.m_height * 2;
subresourceLayout.m_size.m_width = AlignUp(imageSize.m_width, 2);
subresourceLayout.m_size.m_height = AlignUp(imageSize.m_height, 2);
}
else if (isPlanar)
{
subresourceLayout.m_bytesPerRow = ((imageSize.m_width + 1) >> 1) * bytesPerElement;
subresourceLayout.m_rowCount = imageSize.m_height + ((imageSize.m_height + 1) >> 1);
subresourceLayout.m_size.m_width = AlignUp(imageSize.m_width, 2);
subresourceLayout.m_size.m_height = AlignUp(imageSize.m_height, 2);
}
else
{
subresourceLayout.m_bytesPerRow = imageSize.m_width * RHI::GetFormatSize(imageFormat);
subresourceLayout.m_rowCount = imageSize.m_height;
subresourceLayout.m_size.m_width = imageSize.m_width;
subresourceLayout.m_size.m_height = imageSize.m_height;
}
subresourceLayout.m_bytesPerImage = subresourceLayout.m_bytesPerRow * subresourceLayout.m_rowCount;
subresourceLayout.m_size.m_depth = imageSize.m_depth;
return subresourceLayout;
}
ImageSubresourceLayout GetImageSubresourceLayout(const ImageDescriptor& imageDescriptor, const ImageSubresource& subresource)
{
return GetImageSubresourceLayout(imageDescriptor.m_size.GetReducedMip(subresource.m_mipSlice), imageDescriptor.m_format);
}
uint32_t GetImageSubresourceIndex(uint32_t mipSlice, uint32_t arraySlice, uint32_t mipLevels)
{
return mipSlice + arraySlice * mipLevels;
}
uint32_t GetImageSubresourceIndex(ImageSubresource subresource, uint32_t mipLevels)
{
return GetImageSubresourceIndex(subresource.m_mipSlice, subresource.m_arraySlice, mipLevels);
}
}
}