Renderer/TextureInfo: Separate layerCount from size

This commit is contained in:
SirLynix 2022-11-30 08:51:31 +01:00 committed by Jérôme Leclercq
parent 1768f20365
commit 902dee6121
6 changed files with 82 additions and 79 deletions

View File

@ -20,13 +20,14 @@ namespace Nz
case ImageType::E2D: return GL::TextureTarget::Target2D; case ImageType::E2D: return GL::TextureTarget::Target2D;
case ImageType::E2D_Array: return GL::TextureTarget::Target2D_Array; case ImageType::E2D_Array: return GL::TextureTarget::Target2D_Array;
case ImageType::E3D: return GL::TextureTarget::Target3D; case ImageType::E3D: return GL::TextureTarget::Target3D;
case ImageType::Cubemap: return GL::TextureTarget::Cubemap; case ImageType::Cubemap: return GL::TextureTarget::Cubemap;
case ImageType::E1D: // OpenGL ES doesn't support 1D textures, use 2D textures with a height of 1 instead
case ImageType::E1D_Array: case ImageType::E1D: return GL::TextureTarget::Target2D;
default: case ImageType::E1D_Array: return GL::TextureTarget::Target2D_Array;
throw std::runtime_error("unsupported texture type");
} }
throw std::runtime_error("unsupported texture type");
} }
} }

View File

@ -27,6 +27,7 @@ namespace Nz
ImageType type; ImageType type;
TextureUsageFlags usageFlags = TextureUsage::ShaderSampling | TextureUsage::TransferDestination; TextureUsageFlags usageFlags = TextureUsage::ShaderSampling | TextureUsage::TransferDestination;
UInt8 mipmapLevel = 1; UInt8 mipmapLevel = 1;
unsigned int layerCount = 1;
unsigned int depth = 1; unsigned int depth = 1;
unsigned int height; unsigned int height;
unsigned int width; unsigned int width;

View File

@ -41,7 +41,7 @@ namespace Nz
VulkanTexture& operator=(VulkanTexture&&) = delete; VulkanTexture& operator=(VulkanTexture&&) = delete;
private: private:
static void InitForFormat(PixelFormat pixelFormat, VkImageCreateInfo& createImage, VkImageViewCreateInfo& createImageView); static void InitViewForFormat(PixelFormat pixelFormat, VkImageViewCreateInfo& createImageView);
VkImage m_image; VkImage m_image;
VmaAllocation m_allocation; VmaAllocation m_allocation;

View File

@ -340,6 +340,8 @@ namespace Nz
if (texInfo.type == ImageType::E3D) if (texInfo.type == ImageType::E3D)
continue; continue;
texInfo.layerCount = (texInfo.type == ImageType::Cubemap) ? 6 : 1;
m_defaultTextures.depthTextures[i] = m_renderDevice->InstantiateTexture(texInfo); m_defaultTextures.depthTextures[i] = m_renderDevice->InstantiateTexture(texInfo);
m_defaultTextures.depthTextures[i]->Update(whitePixels.data()); m_defaultTextures.depthTextures[i]->Update(whitePixels.data());
} }
@ -356,6 +358,7 @@ namespace Nz
for (std::size_t i = 0; i < ImageTypeCount; ++i) for (std::size_t i = 0; i < ImageTypeCount; ++i)
{ {
texInfo.type = static_cast<ImageType>(i); texInfo.type = static_cast<ImageType>(i);
texInfo.layerCount = (texInfo.type == ImageType::Cubemap) ? 6 : 1;
m_defaultTextures.whiteTextures[i] = m_renderDevice->InstantiateTexture(texInfo); m_defaultTextures.whiteTextures[i] = m_renderDevice->InstantiateTexture(texInfo);
m_defaultTextures.whiteTextures[i]->Update(whitePixels.data()); m_defaultTextures.whiteTextures[i]->Update(whitePixels.data());

View File

@ -25,20 +25,12 @@ namespace Nz
switch (params.type) switch (params.type)
{ {
case ImageType::E1D:
m_texture.TexStorage2D(GL::TextureTarget::Target2D, params.mipmapLevel, format->internalFormat, params.width, 1);
break;
case ImageType::E1D_Array:
m_texture.TexStorage2D(GL::TextureTarget::Target2D, params.mipmapLevel, format->internalFormat, params.width, params.height);
break;
case ImageType::E2D: case ImageType::E2D:
m_texture.TexStorage2D(GL::TextureTarget::Target2D, params.mipmapLevel, format->internalFormat, params.width, params.height); m_texture.TexStorage2D(GL::TextureTarget::Target2D, params.mipmapLevel, format->internalFormat, params.width, params.height);
break; break;
case ImageType::E2D_Array: case ImageType::E2D_Array:
m_texture.TexStorage3D(GL::TextureTarget::Target2D_Array, params.mipmapLevel, format->internalFormat, params.width, params.height, params.depth); m_texture.TexStorage3D(GL::TextureTarget::Target2D_Array, params.mipmapLevel, format->internalFormat, params.width, params.height, params.layerCount);
break; break;
case ImageType::E3D: case ImageType::E3D:
@ -48,6 +40,15 @@ namespace Nz
case ImageType::Cubemap: case ImageType::Cubemap:
m_texture.TexStorage2D(GL::TextureTarget::Cubemap, params.mipmapLevel, format->internalFormat, params.width, params.height); m_texture.TexStorage2D(GL::TextureTarget::Cubemap, params.mipmapLevel, format->internalFormat, params.width, params.height);
break; break;
// OpenGL ES doesn't support 1D textures, use 2D textures with a height of 1 instead
case ImageType::E1D:
m_texture.TexStorage2D(GL::TextureTarget::Target2D, params.mipmapLevel, format->internalFormat, params.width, 1);
break;
case ImageType::E1D_Array:
m_texture.TexStorage2D(GL::TextureTarget::Target2D, params.mipmapLevel, format->internalFormat, params.width, params.layerCount);
break;
} }
if (!context.DidLastCallSucceed()) if (!context.DidLastCallSucceed())

View File

@ -19,127 +19,120 @@ namespace Nz
m_device(device), m_device(device),
m_params(params) m_params(params)
{ {
VkImageViewCreateInfo createInfoView = {};
createInfoView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
InitViewForFormat(params.pixelFormat, createInfoView);
VkImageCreateInfo createInfo = {}; VkImageCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
createInfo.format = createInfoView.format;
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
createInfo.mipLevels = params.mipmapLevel;
createInfo.samples = VK_SAMPLE_COUNT_1_BIT; createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
createInfo.usage = ToVulkan(params.usageFlags); createInfo.usage = ToVulkan(params.usageFlags);
VkImageViewCreateInfo createInfoView = {};
createInfoView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
createInfoView.subresourceRange = {
ToVulkan(PixelFormatInfo::GetContent(params.pixelFormat)),
0,
1,
0,
1
};
InitForFormat(params.pixelFormat, createInfo, createInfoView);
switch (params.type) switch (params.type)
{ {
case ImageType::E1D: case ImageType::E1D:
NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.width > 0, "Width must be over zero");
NazaraAssert(params.height == 1, "Height must be one");
createInfoView.viewType = VK_IMAGE_VIEW_TYPE_1D; NazaraAssert(params.depth == 1, "Depth must be one");
NazaraAssert(params.layerCount == 1, "Array count must be one");
createInfo.imageType = VK_IMAGE_TYPE_1D; createInfo.imageType = VK_IMAGE_TYPE_1D;
createInfoView.viewType = VK_IMAGE_VIEW_TYPE_1D;
createInfo.extent.width = params.width; createInfo.extent.width = params.width;
createInfo.extent.height = 1;
createInfo.extent.depth = 1;
createInfo.arrayLayers = 1;
break; break;
case ImageType::E1D_Array: case ImageType::E1D_Array:
NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.width > 0, "Width must be over zero");
NazaraAssert(params.height > 0, "Height must be over zero"); NazaraAssert(params.height == 1, "Height must be one");
NazaraAssert(params.depth == 1, "Depth must be one");
createInfoView.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY; NazaraAssert(params.layerCount > 0, "Array count must be over zero");
createInfo.imageType = VK_IMAGE_TYPE_1D; createInfo.imageType = VK_IMAGE_TYPE_1D;
createInfo.extent.width = params.width; createInfoView.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
createInfo.extent.height = 1;
createInfo.extent.depth = 1;
createInfo.arrayLayers = params.height;
break; break;
case ImageType::E2D: case ImageType::E2D:
NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.width > 0, "Width must be over zero");
NazaraAssert(params.height > 0, "Height must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero");
NazaraAssert(params.depth == 1, "Depth must be one");
createInfoView.viewType = VK_IMAGE_VIEW_TYPE_2D; NazaraAssert(params.layerCount == 1, "Array count must be one");
createInfo.imageType = VK_IMAGE_TYPE_2D; createInfo.imageType = VK_IMAGE_TYPE_2D;
createInfo.extent.width = params.width; createInfoView.viewType = VK_IMAGE_VIEW_TYPE_2D;
createInfo.extent.height = params.height;
createInfo.extent.depth = 1;
createInfo.arrayLayers = 1;
break; break;
case ImageType::E2D_Array: case ImageType::E2D_Array:
NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.width > 0, "Width must be over zero");
NazaraAssert(params.height > 0, "Height must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero");
NazaraAssert(params.depth > 0, "Depth must be over zero"); NazaraAssert(params.depth == 1, "Depth must be one");
NazaraAssert(params.layerCount > 0, "Array count must be over zero");
createInfoView.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
createInfo.imageType = VK_IMAGE_TYPE_2D; createInfo.imageType = VK_IMAGE_TYPE_2D;
createInfo.extent.width = params.width; createInfoView.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
createInfo.extent.height = params.height;
createInfo.extent.depth = 1;
createInfo.arrayLayers = params.depth;
break; break;
case ImageType::E3D: case ImageType::E3D:
NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.width > 0, "Width must be over zero");
NazaraAssert(params.height > 0, "Height must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero");
NazaraAssert(params.depth > 0, "Depth must be over zero"); NazaraAssert(params.depth > 0, "Depth must be over zero");
NazaraAssert(params.layerCount == 1, "Array count must be one");
createInfoView.viewType = VK_IMAGE_VIEW_TYPE_3D;
createInfo.imageType = VK_IMAGE_TYPE_3D; createInfo.imageType = VK_IMAGE_TYPE_3D;
createInfo.extent.width = params.width; createInfoView.viewType = VK_IMAGE_VIEW_TYPE_3D;
createInfo.extent.height = params.height;
createInfo.extent.depth = params.depth;
createInfo.arrayLayers = 1;
break; break;
case ImageType::Cubemap: case ImageType::Cubemap:
NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.width > 0, "Width must be over zero");
NazaraAssert(params.height > 0, "Height must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero");
NazaraAssert(params.depth == 1, "Depth must be one");
createInfoView.viewType = VK_IMAGE_VIEW_TYPE_CUBE; NazaraAssert(params.layerCount % 6 == 0, "Array count must be a multiple of 6");
createInfoView.subresourceRange.layerCount = 6;
createInfo.imageType = VK_IMAGE_TYPE_2D; createInfo.imageType = VK_IMAGE_TYPE_2D;
createInfo.extent.width = params.width;
createInfo.extent.height = params.height;
createInfo.extent.depth = 1;
createInfo.arrayLayers = 6;
createInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; createInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
createInfoView.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
break; break;
default: default:
break; break;
} }
createInfo.extent.width = params.width;
createInfo.extent.height = params.height;
createInfo.extent.depth = params.depth;
createInfo.arrayLayers = params.layerCount;
createInfo.mipLevels = params.mipmapLevel;
VmaAllocationCreateInfo allocInfo = {}; VmaAllocationCreateInfo allocInfo = {};
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
VkResult result = vmaCreateImage(m_device.GetMemoryAllocator(), &createInfo, &allocInfo, &m_image, &m_allocation, nullptr); VkResult result = vmaCreateImage(m_device.GetMemoryAllocator(), &createInfo, &allocInfo, &m_image, &m_allocation, nullptr);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
throw std::runtime_error("Failed to allocate image: " + TranslateVulkanError(result)); throw std::runtime_error("Failed to allocate image: " + TranslateVulkanError(result));
CallOnExit releaseImage([&]{ vmaDestroyImage(m_device.GetMemoryAllocator(), m_image, m_allocation); });
createInfoView.subresourceRange = {
ToVulkan(PixelFormatInfo::GetContent(params.pixelFormat)),
0, //< baseMipLevel
createInfo.mipLevels, //< levelCount
0, //< baseArrayLayer
createInfo.arrayLayers //< layerCount, will be set if the type is an array/cubemap
};
createInfoView.image = m_image;
if (!m_imageView.Create(m_device, createInfoView))
throw std::runtime_error("Failed to create default image view: " + TranslateVulkanError(m_imageView.GetLastErrorCode()));
releaseImage.Reset();
createInfoView.image = m_image; createInfoView.image = m_image;
if (!m_imageView.Create(device, createInfoView))
{ {
// FIXME // FIXME
vmaDestroyImage(m_device.GetMemoryAllocator(), m_image, m_allocation); vmaDestroyImage(m_device.GetMemoryAllocator(), m_image, m_allocation);
throw std::runtime_error("Failed to create image view: " + TranslateVulkanError(m_imageView.GetLastErrorCode()));
} }
} }
@ -160,7 +153,7 @@ namespace Nz
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
0, //< mipLevel 0, //< mipLevel
0, //< baseArrayLayer 0, //< baseArrayLayer
1 //< layerCount 1 //< layerCount
}; };
VkImageSubresourceRange subresourceRange = { //< FIXME VkImageSubresourceRange subresourceRange = { //< FIXME
@ -348,7 +341,7 @@ namespace Nz
return m_device.SetDebugName(VK_OBJECT_TYPE_IMAGE, static_cast<UInt64>(reinterpret_cast<std::uintptr_t>(m_image)), name); return m_device.SetDebugName(VK_OBJECT_TYPE_IMAGE, static_cast<UInt64>(reinterpret_cast<std::uintptr_t>(m_image)), name);
} }
void VulkanTexture::InitForFormat(PixelFormat pixelFormat, VkImageCreateInfo& createImage, VkImageViewCreateInfo& createImageView) void VulkanTexture::InitViewForFormat(PixelFormat pixelFormat, VkImageViewCreateInfo& createImageView)
{ {
createImageView.components = { createImageView.components = {
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
@ -377,16 +370,14 @@ namespace Nz
case PixelFormat::RGBA16F: case PixelFormat::RGBA16F:
case PixelFormat::RGBA32F: case PixelFormat::RGBA32F:
{ {
createImage.format = ToVulkan(pixelFormat); createImageView.format = ToVulkan(pixelFormat);
createImageView.format = createImage.format;
break; break;
} }
// "emulated" formats // "emulated" formats
case PixelFormat::A8: case PixelFormat::A8:
{ {
createImage.format = VK_FORMAT_R8_UNORM; createImageView.format = VK_FORMAT_R8_UNORM;
createImageView.format = createImage.format;
createImageView.components = { createImageView.components = {
VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE,
VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE,
@ -398,8 +389,7 @@ namespace Nz
case PixelFormat::L8: case PixelFormat::L8:
{ {
createImage.format = VK_FORMAT_R8_UNORM; createImageView.format = VK_FORMAT_R8_UNORM;
createImageView.format = createImage.format;
createImageView.components = { createImageView.components = {
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
@ -411,8 +401,7 @@ namespace Nz
case PixelFormat::LA8: case PixelFormat::LA8:
{ {
createImage.format = VK_FORMAT_R8G8_UNORM; createImageView.format = VK_FORMAT_R8G8_UNORM;
createImageView.format = createImage.format;
createImageView.components = { createImageView.components = {
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
@ -425,6 +414,14 @@ namespace Nz
default: default:
throw std::runtime_error("Unsupported pixel format " + PixelFormatInfo::GetName(pixelFormat)); throw std::runtime_error("Unsupported pixel format " + PixelFormatInfo::GetName(pixelFormat));
} }
createImageView.subresourceRange = {
ToVulkan(PixelFormatInfo::GetContent(pixelFormat)),
0,
1,
0,
1
};
} }
} }