diff --git a/include/Nazara/OpenGLRenderer/OpenGLTexture.inl b/include/Nazara/OpenGLRenderer/OpenGLTexture.inl index 69f2b6bb6..04dcb8383 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLTexture.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLTexture.inl @@ -20,13 +20,14 @@ namespace Nz case ImageType::E2D: return GL::TextureTarget::Target2D; case ImageType::E2D_Array: return GL::TextureTarget::Target2D_Array; case ImageType::E3D: return GL::TextureTarget::Target3D; - case ImageType::Cubemap: return GL::TextureTarget::Cubemap; + case ImageType::Cubemap: return GL::TextureTarget::Cubemap; - case ImageType::E1D: - case ImageType::E1D_Array: - default: - throw std::runtime_error("unsupported texture type"); + // OpenGL ES doesn't support 1D textures, use 2D textures with a height of 1 instead + case ImageType::E1D: return GL::TextureTarget::Target2D; + case ImageType::E1D_Array: return GL::TextureTarget::Target2D_Array; } + + throw std::runtime_error("unsupported texture type"); } } diff --git a/include/Nazara/Renderer/Texture.hpp b/include/Nazara/Renderer/Texture.hpp index 7d5cfe5d5..54caf205e 100644 --- a/include/Nazara/Renderer/Texture.hpp +++ b/include/Nazara/Renderer/Texture.hpp @@ -27,6 +27,7 @@ namespace Nz ImageType type; TextureUsageFlags usageFlags = TextureUsage::ShaderSampling | TextureUsage::TransferDestination; UInt8 mipmapLevel = 1; + unsigned int layerCount = 1; unsigned int depth = 1; unsigned int height; unsigned int width; diff --git a/include/Nazara/VulkanRenderer/VulkanTexture.hpp b/include/Nazara/VulkanRenderer/VulkanTexture.hpp index 79d56fee0..f7546aacc 100644 --- a/include/Nazara/VulkanRenderer/VulkanTexture.hpp +++ b/include/Nazara/VulkanRenderer/VulkanTexture.hpp @@ -41,7 +41,7 @@ namespace Nz VulkanTexture& operator=(VulkanTexture&&) = delete; private: - static void InitForFormat(PixelFormat pixelFormat, VkImageCreateInfo& createImage, VkImageViewCreateInfo& createImageView); + static void InitViewForFormat(PixelFormat pixelFormat, VkImageViewCreateInfo& createImageView); VkImage m_image; VmaAllocation m_allocation; diff --git a/src/Nazara/Graphics/Graphics.cpp b/src/Nazara/Graphics/Graphics.cpp index 886913fbe..a57e7bf71 100644 --- a/src/Nazara/Graphics/Graphics.cpp +++ b/src/Nazara/Graphics/Graphics.cpp @@ -340,6 +340,8 @@ namespace Nz if (texInfo.type == ImageType::E3D) continue; + texInfo.layerCount = (texInfo.type == ImageType::Cubemap) ? 6 : 1; + m_defaultTextures.depthTextures[i] = m_renderDevice->InstantiateTexture(texInfo); m_defaultTextures.depthTextures[i]->Update(whitePixels.data()); } @@ -356,6 +358,7 @@ namespace Nz for (std::size_t i = 0; i < ImageTypeCount; ++i) { texInfo.type = static_cast(i); + texInfo.layerCount = (texInfo.type == ImageType::Cubemap) ? 6 : 1; m_defaultTextures.whiteTextures[i] = m_renderDevice->InstantiateTexture(texInfo); m_defaultTextures.whiteTextures[i]->Update(whitePixels.data()); diff --git a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp index abe67463c..9945d56cf 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp @@ -25,20 +25,12 @@ namespace Nz 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: m_texture.TexStorage2D(GL::TextureTarget::Target2D, params.mipmapLevel, format->internalFormat, params.width, params.height); break; 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; case ImageType::E3D: @@ -48,6 +40,15 @@ namespace Nz case ImageType::Cubemap: m_texture.TexStorage2D(GL::TextureTarget::Cubemap, params.mipmapLevel, format->internalFormat, params.width, params.height); 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()) diff --git a/src/Nazara/VulkanRenderer/VulkanTexture.cpp b/src/Nazara/VulkanRenderer/VulkanTexture.cpp index 62718ced4..0a98f7d07 100644 --- a/src/Nazara/VulkanRenderer/VulkanTexture.cpp +++ b/src/Nazara/VulkanRenderer/VulkanTexture.cpp @@ -19,127 +19,120 @@ namespace Nz m_device(device), m_params(params) { + VkImageViewCreateInfo createInfoView = {}; + createInfoView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + InitViewForFormat(params.pixelFormat, createInfoView); + VkImageCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + createInfo.format = createInfoView.format; createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - createInfo.mipLevels = params.mipmapLevel; createInfo.samples = VK_SAMPLE_COUNT_1_BIT; createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 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) { case ImageType::E1D: NazaraAssert(params.width > 0, "Width must be over zero"); - - createInfoView.viewType = VK_IMAGE_VIEW_TYPE_1D; + NazaraAssert(params.height == 1, "Height must be one"); + NazaraAssert(params.depth == 1, "Depth must be one"); + NazaraAssert(params.layerCount == 1, "Array count must be one"); createInfo.imageType = VK_IMAGE_TYPE_1D; + createInfoView.viewType = VK_IMAGE_VIEW_TYPE_1D; createInfo.extent.width = params.width; - createInfo.extent.height = 1; - createInfo.extent.depth = 1; - createInfo.arrayLayers = 1; break; case ImageType::E1D_Array: NazaraAssert(params.width > 0, "Width must be over zero"); - NazaraAssert(params.height > 0, "Height must be over zero"); - - createInfoView.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY; + NazaraAssert(params.height == 1, "Height must be one"); + NazaraAssert(params.depth == 1, "Depth must be one"); + NazaraAssert(params.layerCount > 0, "Array count must be over zero"); createInfo.imageType = VK_IMAGE_TYPE_1D; - createInfo.extent.width = params.width; - createInfo.extent.height = 1; - createInfo.extent.depth = 1; - createInfo.arrayLayers = params.height; + createInfoView.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY; break; case ImageType::E2D: NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero"); - - createInfoView.viewType = VK_IMAGE_VIEW_TYPE_2D; + NazaraAssert(params.depth == 1, "Depth must be one"); + NazaraAssert(params.layerCount == 1, "Array count must be one"); createInfo.imageType = VK_IMAGE_TYPE_2D; - createInfo.extent.width = params.width; - createInfo.extent.height = params.height; - createInfo.extent.depth = 1; - createInfo.arrayLayers = 1; + createInfoView.viewType = VK_IMAGE_VIEW_TYPE_2D; break; case ImageType::E2D_Array: NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero"); - NazaraAssert(params.depth > 0, "Depth must be over zero"); - - createInfoView.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + NazaraAssert(params.depth == 1, "Depth must be one"); + NazaraAssert(params.layerCount > 0, "Array count must be over zero"); createInfo.imageType = VK_IMAGE_TYPE_2D; - createInfo.extent.width = params.width; - createInfo.extent.height = params.height; - createInfo.extent.depth = 1; - createInfo.arrayLayers = params.depth; + createInfoView.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; break; case ImageType::E3D: NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero"); NazaraAssert(params.depth > 0, "Depth must be over zero"); - - createInfoView.viewType = VK_IMAGE_VIEW_TYPE_3D; + NazaraAssert(params.layerCount == 1, "Array count must be one"); createInfo.imageType = VK_IMAGE_TYPE_3D; - createInfo.extent.width = params.width; - createInfo.extent.height = params.height; - createInfo.extent.depth = params.depth; - createInfo.arrayLayers = 1; + createInfoView.viewType = VK_IMAGE_VIEW_TYPE_3D; break; case ImageType::Cubemap: NazaraAssert(params.width > 0, "Width must be over zero"); NazaraAssert(params.height > 0, "Height must be over zero"); - - createInfoView.viewType = VK_IMAGE_VIEW_TYPE_CUBE; - createInfoView.subresourceRange.layerCount = 6; + NazaraAssert(params.depth == 1, "Depth must be one"); + NazaraAssert(params.layerCount % 6 == 0, "Array count must be a multiple of 6"); 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; + createInfoView.viewType = VK_IMAGE_VIEW_TYPE_CUBE; break; default: 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 = {}; - 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); if (result != VK_SUCCESS) 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; - if (!m_imageView.Create(device, createInfoView)) { // FIXME 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, 0, //< mipLevel 0, //< baseArrayLayer - 1 //< layerCount + 1 //< layerCount }; VkImageSubresourceRange subresourceRange = { //< FIXME @@ -348,7 +341,7 @@ namespace Nz return m_device.SetDebugName(VK_OBJECT_TYPE_IMAGE, static_cast(reinterpret_cast(m_image)), name); } - void VulkanTexture::InitForFormat(PixelFormat pixelFormat, VkImageCreateInfo& createImage, VkImageViewCreateInfo& createImageView) + void VulkanTexture::InitViewForFormat(PixelFormat pixelFormat, VkImageViewCreateInfo& createImageView) { createImageView.components = { VK_COMPONENT_SWIZZLE_R, @@ -377,16 +370,14 @@ namespace Nz case PixelFormat::RGBA16F: case PixelFormat::RGBA32F: { - createImage.format = ToVulkan(pixelFormat); - createImageView.format = createImage.format; + createImageView.format = ToVulkan(pixelFormat); break; } // "emulated" formats case PixelFormat::A8: { - createImage.format = VK_FORMAT_R8_UNORM; - createImageView.format = createImage.format; + createImageView.format = VK_FORMAT_R8_UNORM; createImageView.components = { VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, @@ -398,8 +389,7 @@ namespace Nz case PixelFormat::L8: { - createImage.format = VK_FORMAT_R8_UNORM; - createImageView.format = createImage.format; + createImageView.format = VK_FORMAT_R8_UNORM; createImageView.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, @@ -411,8 +401,7 @@ namespace Nz case PixelFormat::LA8: { - createImage.format = VK_FORMAT_R8G8_UNORM; - createImageView.format = createImage.format; + createImageView.format = VK_FORMAT_R8G8_UNORM; createImageView.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, @@ -425,6 +414,14 @@ namespace Nz default: throw std::runtime_error("Unsupported pixel format " + PixelFormatInfo::GetName(pixelFormat)); } + + createImageView.subresourceRange = { + ToVulkan(PixelFormatInfo::GetContent(pixelFormat)), + 0, + 1, + 0, + 1 + }; } }