From 42f8cdb15101178596503c247aea9a0f8f83ca1e Mon Sep 17 00:00:00 2001 From: SirLynix Date: Wed, 30 Nov 2022 18:45:07 +0100 Subject: [PATCH] Add initial support for texture views --- .../Nazara/OpenGLRenderer/OpenGLTexture.hpp | 12 +- .../Nazara/OpenGLRenderer/OpenGLTexture.inl | 5 + .../Nazara/OpenGLRenderer/Wrapper/Context.hpp | 3 +- .../OpenGLRenderer/Wrapper/CoreFunctions.hpp | 5 + .../Nazara/OpenGLRenderer/Wrapper/Texture.hpp | 1 + .../Nazara/OpenGLRenderer/Wrapper/Texture.inl | 6 + include/Nazara/Renderer/Texture.hpp | 15 +- include/Nazara/Renderer/Texture.inl | 13 ++ .../Nazara/VulkanRenderer/VulkanTexture.hpp | 8 +- src/Nazara/Graphics/Graphics.cpp | 4 +- src/Nazara/OpenGLRenderer/OpenGLTexture.cpp | 91 +++++++++--- src/Nazara/OpenGLRenderer/Wrapper/Context.cpp | 16 ++ src/Nazara/VulkanRenderer/VulkanTexture.cpp | 138 +++++++++++------- 13 files changed, 239 insertions(+), 78 deletions(-) diff --git a/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp b/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp index 1a5396771..1606a8059 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp @@ -12,25 +12,31 @@ #include #include #include +#include namespace Nz { class NAZARA_OPENGLRENDERER_API OpenGLTexture : public Texture { public: - OpenGLTexture(OpenGLDevice& device, const TextureInfo& params); + OpenGLTexture(OpenGLDevice& device, const TextureInfo& textureInfo); + OpenGLTexture(std::shared_ptr parentTexture, const TextureViewInfo& viewInfo); OpenGLTexture(const OpenGLTexture&) = delete; OpenGLTexture(OpenGLTexture&&) = delete; ~OpenGLTexture() = default; bool Copy(const Texture& source, const Boxui& srcBox, const Vector3ui& dstPos) override; + std::shared_ptr CreateView(const TextureViewInfo& viewInfo) override; PixelFormat GetFormat() const override; UInt8 GetLevelCount() const override; + OpenGLTexture* GetParentTexture() const override; Vector3ui GetSize(UInt8 level = 0) const override; inline const GL::Texture& GetTexture() const; ImageType GetType() const override; + inline bool RequireTextureViewEmulation() const; + using Texture::Update; bool Update(const void* ptr, const Boxui& box, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) override; @@ -42,8 +48,10 @@ namespace Nz static inline GL::TextureTarget ToTextureTarget(ImageType imageType); private: + std::optional m_viewInfo; + std::shared_ptr m_parentTexture; GL::Texture m_texture; - TextureInfo m_params; + TextureInfo m_textureInfo; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLTexture.inl b/include/Nazara/OpenGLRenderer/OpenGLTexture.inl index 04dcb8383..74dea9b94 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLTexture.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLTexture.inl @@ -13,6 +13,11 @@ namespace Nz return m_texture; } + inline bool OpenGLTexture::RequireTextureViewEmulation() const + { + return m_viewInfo.has_value() && !m_texture.IsValid(); + } + inline GL::TextureTarget OpenGLTexture::ToTextureTarget(ImageType imageType) { switch (imageType) diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp index fca467789..4c6ae918e 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp @@ -60,8 +60,9 @@ namespace Nz::GL StorageBuffers, TextureCompressionS3tc, TextureFilterAnisotropic, + TextureView, - Max = TextureFilterAnisotropic + Max = TextureView }; enum class ExtensionStatus diff --git a/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp b/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp index 9e9c920db..294166530 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp @@ -26,6 +26,9 @@ typedef void (GL_APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode); // Depth clamp (OpenGL 3.2) #define GL_DEPTH_CLAMP 0x864F +// Texture views (OpenGL 4.3) +typedef void (GL_APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); + // Clip control (OpenGL 4.5) #define GL_LOWER_LEFT 0x8CA1 #define GL_UPPER_LEFT 0x8CA2 @@ -200,6 +203,8 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERPROC) (GLuint shader, const GLch extCb(glObjectLabel, PFNGLOBJECTLABELPROC) \ extCb(glPopDebugGroup, PFNGLPOPDEBUGGROUPPROC) \ extCb(glPushDebugGroup, PFNGLPUSHDEBUGGROUPPROC) \ + /* OpenGL 4.3 - GL_ARB_texture_view */ \ + extCb(glTextureView, PFNGLTEXTUREVIEWPROC) \ /* OpenGL 4.5 - GL_ARB_clip_control/GL_EXT_clip_control */ \ extCb(glClipControl, PFNGLCLIPCONTROLPROC) \ /* OpenGL 4.6 - GL_ARB_spirv_extensions */\ diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp index ccebcd2bb..f53cd8bb0 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp @@ -39,6 +39,7 @@ namespace Nz::GL inline void TexStorage3D(TextureTarget target, GLint levels, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth); inline void TexSubImage2D(TextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data); inline void TexSubImage3D(TextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data); + inline void TextureView(GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); Texture& operator=(const Texture&) = delete; Texture& operator=(Texture&&) noexcept = default; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl b/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl index e2888624f..1658ff55a 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl @@ -111,6 +111,12 @@ namespace Nz::GL //< TODO: Handle errors } + inline void Texture::TextureView(GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) + { + const Context& context = EnsureDeviceContext(); + context.glTextureView(m_objectId, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers); + } + inline GLuint Texture::CreateHelper(OpenGLDevice& /*device*/, const Context& context) { GLuint texture = 0; diff --git a/include/Nazara/Renderer/Texture.hpp b/include/Nazara/Renderer/Texture.hpp index 54caf205e..d301ab9a5 100644 --- a/include/Nazara/Renderer/Texture.hpp +++ b/include/Nazara/Renderer/Texture.hpp @@ -26,13 +26,23 @@ namespace Nz PixelFormat pixelFormat; ImageType type; TextureUsageFlags usageFlags = TextureUsage::ShaderSampling | TextureUsage::TransferDestination; - UInt8 mipmapLevel = 1; + UInt8 levelCount = 1; unsigned int layerCount = 1; unsigned int depth = 1; unsigned int height; unsigned int width; }; + struct TextureViewInfo + { + ImageType viewType; + PixelFormat reinterpretFormat; + UInt8 baseMipLevel = 0; + UInt8 levelCount = 1; + unsigned int baseArrayLayer = 0; + unsigned int layerCount = 1; + }; + struct NAZARA_RENDERER_API TextureParams : ImageParams { std::shared_ptr renderDevice; @@ -56,9 +66,11 @@ namespace Nz virtual ~Texture(); virtual bool Copy(const Texture& source, const Boxui& srcBox, const Vector3ui& dstPos = Vector3ui::Zero()) = 0; + virtual std::shared_ptr CreateView(const TextureViewInfo& viewInfo) = 0; virtual PixelFormat GetFormat() const = 0; virtual UInt8 GetLevelCount() const = 0; + virtual Texture* GetParentTexture() const = 0; virtual Vector3ui GetSize(UInt8 level = 0) const = 0; virtual ImageType GetType() const = 0; @@ -67,6 +79,7 @@ namespace Nz Texture& operator=(const Texture&) = delete; Texture& operator=(Texture&&) = delete; + static inline TextureInfo ApplyView(TextureInfo textureInfo, const TextureViewInfo& viewInfo); static inline unsigned int GetLevelSize(unsigned int size, unsigned int level); static std::shared_ptr CreateFromImage(const Image& image, const TextureParams& params); diff --git a/include/Nazara/Renderer/Texture.inl b/include/Nazara/Renderer/Texture.inl index 2f2ae286f..7d2c68a17 100644 --- a/include/Nazara/Renderer/Texture.inl +++ b/include/Nazara/Renderer/Texture.inl @@ -7,6 +7,19 @@ namespace Nz { + inline TextureInfo Texture::ApplyView(TextureInfo textureInfo, const TextureViewInfo& viewInfo) + { + textureInfo.type = viewInfo.viewType; + textureInfo.pixelFormat = viewInfo.reinterpretFormat; + textureInfo.width = GetLevelSize(textureInfo.width, viewInfo.baseMipLevel); + textureInfo.height = GetLevelSize(textureInfo.height, viewInfo.baseMipLevel); + textureInfo.depth = GetLevelSize(textureInfo.depth, viewInfo.baseMipLevel); + textureInfo.levelCount = (textureInfo.levelCount > viewInfo.baseMipLevel) ? (textureInfo.levelCount - viewInfo.baseMipLevel) : 1; + textureInfo.layerCount = (textureInfo.layerCount > viewInfo.baseArrayLayer) ? (textureInfo.layerCount - viewInfo.baseArrayLayer) : 1; + + return textureInfo; + } + inline unsigned int Texture::GetLevelSize(unsigned int size, unsigned int level) { if (size == 0) // Possible dans le cas d'une image invalide diff --git a/include/Nazara/VulkanRenderer/VulkanTexture.hpp b/include/Nazara/VulkanRenderer/VulkanTexture.hpp index f7546aacc..d74b52e82 100644 --- a/include/Nazara/VulkanRenderer/VulkanTexture.hpp +++ b/include/Nazara/VulkanRenderer/VulkanTexture.hpp @@ -18,17 +18,20 @@ namespace Nz class NAZARA_VULKANRENDERER_API VulkanTexture : public Texture { public: - VulkanTexture(Vk::Device& device, const TextureInfo& params); + VulkanTexture(Vk::Device& device, const TextureInfo& textureInfo); + VulkanTexture(std::shared_ptr parentTexture, const TextureViewInfo& viewInfo); VulkanTexture(const VulkanTexture&) = delete; VulkanTexture(VulkanTexture&&) = delete; ~VulkanTexture(); bool Copy(const Texture& source, const Boxui& srcBox, const Vector3ui& dstPos) override; + std::shared_ptr CreateView(const TextureViewInfo& viewInfo) override; PixelFormat GetFormat() const override; inline VkImage GetImage() const; inline VkImageView GetImageView() const; UInt8 GetLevelCount() const override; + VulkanTexture* GetParentTexture() const override; Vector3ui GetSize(UInt8 level = 0) const override; ImageType GetType() const override; @@ -43,11 +46,12 @@ namespace Nz private: static void InitViewForFormat(PixelFormat pixelFormat, VkImageViewCreateInfo& createImageView); + std::shared_ptr m_parentTexture; VkImage m_image; VmaAllocation m_allocation; Vk::Device& m_device; Vk::ImageView m_imageView; - TextureInfo m_params; + TextureInfo m_textureInfo; }; } diff --git a/src/Nazara/Graphics/Graphics.cpp b/src/Nazara/Graphics/Graphics.cpp index a57e7bf71..8a906a852 100644 --- a/src/Nazara/Graphics/Graphics.cpp +++ b/src/Nazara/Graphics/Graphics.cpp @@ -329,7 +329,7 @@ namespace Nz throw std::runtime_error("couldn't find a sampling-compatible depth pixel format"); TextureInfo texInfo; - texInfo.width = texInfo.height = texInfo.depth = texInfo.mipmapLevel = 1; + texInfo.width = texInfo.height = texInfo.depth = texInfo.levelCount = 1; texInfo.pixelFormat = depthFormat; std::array whitePixels = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -350,7 +350,7 @@ namespace Nz // White texture 2D { TextureInfo texInfo; - texInfo.width = texInfo.height = texInfo.depth = texInfo.mipmapLevel = 1; + texInfo.width = texInfo.height = texInfo.depth = texInfo.levelCount = 1; texInfo.pixelFormat = PixelFormat::L8; std::array whitePixels = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; diff --git a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp index 9945d56cf..4a48cc6e4 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp @@ -10,57 +10,87 @@ namespace Nz { - OpenGLTexture::OpenGLTexture(OpenGLDevice& device, const TextureInfo& params) : - m_params(params) + OpenGLTexture::OpenGLTexture(OpenGLDevice& device, const TextureInfo& textureInfo) : + m_textureInfo(textureInfo) { if (!m_texture.Create(device)) throw std::runtime_error("failed to create texture object"); - auto format = DescribeTextureFormat(params.pixelFormat); + auto format = DescribeTextureFormat(textureInfo.pixelFormat); if (!format) throw std::runtime_error("unsupported texture format"); const GL::Context& context = m_texture.EnsureDeviceContext(); context.ClearErrorStack(); - switch (params.type) + switch (textureInfo.type) { case ImageType::E2D: - m_texture.TexStorage2D(GL::TextureTarget::Target2D, params.mipmapLevel, format->internalFormat, params.width, params.height); + m_texture.TexStorage2D(GL::TextureTarget::Target2D, textureInfo.levelCount, format->internalFormat, textureInfo.width, textureInfo.height); break; case ImageType::E2D_Array: - m_texture.TexStorage3D(GL::TextureTarget::Target2D_Array, params.mipmapLevel, format->internalFormat, params.width, params.height, params.layerCount); + m_texture.TexStorage3D(GL::TextureTarget::Target2D_Array, textureInfo.levelCount, format->internalFormat, textureInfo.width, textureInfo.height, textureInfo.layerCount); break; case ImageType::E3D: - m_texture.TexStorage3D(GL::TextureTarget::Target3D, params.mipmapLevel, format->internalFormat, params.width, params.height, params.depth); + m_texture.TexStorage3D(GL::TextureTarget::Target3D, textureInfo.levelCount, format->internalFormat, textureInfo.width, textureInfo.height, textureInfo.depth); break; case ImageType::Cubemap: - m_texture.TexStorage2D(GL::TextureTarget::Cubemap, params.mipmapLevel, format->internalFormat, params.width, params.height); + m_texture.TexStorage2D(GL::TextureTarget::Cubemap, textureInfo.levelCount, format->internalFormat, textureInfo.width, textureInfo.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); + m_texture.TexStorage2D(GL::TextureTarget::Target2D, textureInfo.levelCount, format->internalFormat, textureInfo.width, 1); break; case ImageType::E1D_Array: - m_texture.TexStorage2D(GL::TextureTarget::Target2D, params.mipmapLevel, format->internalFormat, params.width, params.layerCount); + m_texture.TexStorage2D(GL::TextureTarget::Target2D, textureInfo.levelCount, format->internalFormat, textureInfo.width, textureInfo.layerCount); break; } if (!context.DidLastCallSucceed()) throw std::runtime_error("failed to create texture"); - m_texture.SetParameteri(GL_TEXTURE_MAX_LEVEL, m_params.mipmapLevel); + m_texture.SetParameteri(GL_TEXTURE_MAX_LEVEL, m_textureInfo.levelCount); m_texture.SetParameteri(GL_TEXTURE_SWIZZLE_R, format->swizzleR); m_texture.SetParameteri(GL_TEXTURE_SWIZZLE_G, format->swizzleG); m_texture.SetParameteri(GL_TEXTURE_SWIZZLE_B, format->swizzleB); m_texture.SetParameteri(GL_TEXTURE_SWIZZLE_A, format->swizzleA); } + OpenGLTexture::OpenGLTexture(std::shared_ptr parentTexture, const TextureViewInfo& viewInfo) : + m_parentTexture(std::move(parentTexture)) + { + const GL::Context& context = m_parentTexture->m_texture.EnsureDeviceContext(); + + NazaraAssert(viewInfo.layerCount <= m_parentTexture->m_textureInfo.layerCount - viewInfo.baseArrayLayer, "layer count exceeds number of layers"); + NazaraAssert(viewInfo.levelCount <= m_parentTexture->m_textureInfo.levelCount - viewInfo.baseMipLevel, "level count exceeds number of levels"); + + m_viewInfo = viewInfo; + + // Try to use texture views if supported (core in GL 4.3 or extension) + if (context.IsExtensionSupported(GL::Extension::TextureView)) + { + if (m_texture.Create(*m_parentTexture->m_texture.GetDevice())) + { + auto format = DescribeTextureFormat(viewInfo.reinterpretFormat); + GLenum target = ToOpenGL(ToTextureTarget(viewInfo.viewType)); + + context.ClearErrorStack(); + + m_texture.TextureView(target, m_parentTexture->m_texture.GetObjectId(), format->internalFormat, viewInfo.baseMipLevel, viewInfo.levelCount, viewInfo.baseArrayLayer, viewInfo.layerCount); + + if (!context.DidLastCallSucceed()) + m_texture.Destroy(); + } + } + + // If texture views are not supported, they will be emulated when using them as attachments + } + bool OpenGLTexture::Copy(const Texture& source, const Boxui& srcBox, const Vector3ui& dstPos) { const OpenGLTexture& glTexture = static_cast(source); @@ -69,34 +99,57 @@ namespace Nz return context.CopyTexture(glTexture.GetTexture(), m_texture, srcBox, dstPos); } + std::shared_ptr OpenGLTexture::CreateView(const TextureViewInfo& viewInfo) + { + if (m_parentTexture) + { + assert(m_viewInfo); + NazaraAssert(viewInfo.layerCount <= m_viewInfo->layerCount - viewInfo.baseArrayLayer, "layer count exceeds number of layers"); + NazaraAssert(viewInfo.levelCount <= m_viewInfo->levelCount - viewInfo.baseMipLevel, "level count exceeds number of levels"); + + TextureViewInfo ajustedView = viewInfo; + ajustedView.baseArrayLayer += m_viewInfo->baseArrayLayer; + ajustedView.baseMipLevel += m_viewInfo->baseMipLevel; + + return m_parentTexture->CreateView(ajustedView); + } + + return std::make_shared(std::static_pointer_cast(shared_from_this()), viewInfo); + } + PixelFormat OpenGLTexture::GetFormat() const { - return m_params.pixelFormat; + return m_textureInfo.pixelFormat; } UInt8 OpenGLTexture::GetLevelCount() const { - return m_params.mipmapLevel; + return m_textureInfo.levelCount; + } + + OpenGLTexture* OpenGLTexture::GetParentTexture() const + { + return m_parentTexture.get(); } Vector3ui OpenGLTexture::GetSize(UInt8 level) const { - return Vector3ui(GetLevelSize(m_params.width, level), GetLevelSize(m_params.height, level), GetLevelSize(m_params.depth, level)); + return Vector3ui(GetLevelSize(m_textureInfo.width, level), GetLevelSize(m_textureInfo.height, level), GetLevelSize(m_textureInfo.depth, level)); } ImageType OpenGLTexture::GetType() const { - return m_params.type; + return m_textureInfo.type; } bool OpenGLTexture::Update(const void* ptr, const Boxui& box, unsigned int srcWidth, unsigned int srcHeight, UInt8 level) { - auto format = DescribeTextureFormat(m_params.pixelFormat); + auto format = DescribeTextureFormat(m_textureInfo.pixelFormat); assert(format); const GL::Context& context = m_texture.EnsureDeviceContext(); - UInt8 bpp = PixelFormatInfo::GetBytesPerPixel(m_params.pixelFormat); + UInt8 bpp = PixelFormatInfo::GetBytesPerPixel(m_textureInfo.pixelFormat); if (bpp % 8 == 0) context.glPixelStorei(GL_UNPACK_ALIGNMENT, 8); else if (bpp % 4 == 0) @@ -109,7 +162,7 @@ namespace Nz context.glPixelStorei(GL_UNPACK_ROW_LENGTH, srcWidth); context.glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, srcHeight); - switch (m_params.type) + switch (m_textureInfo.type) { case ImageType::E1D: break; @@ -129,7 +182,7 @@ namespace Nz case ImageType::Cubemap: { - std::size_t faceSize = PixelFormatInfo::ComputeSize(m_params.pixelFormat, m_params.width, m_params.height, 1); + std::size_t faceSize = PixelFormatInfo::ComputeSize(m_textureInfo.pixelFormat, m_textureInfo.width, m_textureInfo.height, 1); const UInt8* facePtr = static_cast(ptr); for (GL::TextureTarget face : { GL::TextureTarget::CubemapPositiveX, GL::TextureTarget::CubemapNegativeX, GL::TextureTarget::CubemapPositiveY, GL::TextureTarget::CubemapNegativeY, GL::TextureTarget::CubemapPositiveZ, GL::TextureTarget::CubemapNegativeZ }) diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp index ac5290dff..06318ef46 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp @@ -446,6 +446,16 @@ namespace Nz::GL else if (m_supportedExtensions.count("GL_EXT_texture_filter_anisotropic")) m_extensionStatus[UnderlyingCast(Extension::TextureFilterAnisotropic)] = ExtensionStatus::EXT; + // Texture view + if (m_params.type == ContextType::OpenGL && glVersion >= 430) + m_extensionStatus[UnderlyingCast(Extension::TextureView)] = ExtensionStatus::Core; + else if (m_supportedExtensions.count("GL_ARB_texture_view")) + m_extensionStatus[UnderlyingCast(Extension::TextureView)] = ExtensionStatus::ARB; + else if (m_supportedExtensions.count("GL_OES_texture_view")) + m_extensionStatus[UnderlyingCast(Extension::TextureView)] = ExtensionStatus::KHR; //< not sure about the OES => KHR mapping + else if (m_supportedExtensions.count("GL_EXT_texture_view")) + m_extensionStatus[UnderlyingCast(Extension::TextureView)] = ExtensionStatus::EXT; //< not sure about the OES => KHR mapping + #define NAZARA_OPENGLRENDERER_FUNC(name, sig) #define NAZARA_OPENGLRENDERER_EXT_FUNC(name, sig) loader.Load(name, #name, false); NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC, NAZARA_OPENGLRENDERER_EXT_FUNC) @@ -959,6 +969,12 @@ namespace Nz::GL constexpr std::size_t functionIndex = UnderlyingCast(FunctionIndex::glSpecializeShader); return loader.Load(glSpecializeShader, "glSpecializeShaderARB", false); //< from GL_ARB_spirv_extensions } + else if (function == "glTextureView") + { + constexpr std::size_t functionIndex = UnderlyingCast(FunctionIndex::glTextureView); + return loader.Load(glTextureView, "glTextureViewOES", false) || + loader.Load(glTextureView, "glTextureViewEXT", false); //< from GL_EXT_texture_view + } return false; } diff --git a/src/Nazara/VulkanRenderer/VulkanTexture.cpp b/src/Nazara/VulkanRenderer/VulkanTexture.cpp index 0a98f7d07..940ba5cde 100644 --- a/src/Nazara/VulkanRenderer/VulkanTexture.cpp +++ b/src/Nazara/VulkanRenderer/VulkanTexture.cpp @@ -13,15 +13,15 @@ namespace Nz { - VulkanTexture::VulkanTexture(Vk::Device& device, const TextureInfo& params) : + VulkanTexture::VulkanTexture(Vk::Device& device, const TextureInfo& textureInfo) : m_image(VK_NULL_HANDLE), m_allocation(nullptr), m_device(device), - m_params(params) + m_textureInfo(textureInfo) { VkImageViewCreateInfo createInfoView = {}; createInfoView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - InitViewForFormat(params.pixelFormat, createInfoView); + InitViewForFormat(textureInfo.pixelFormat, createInfoView); VkImageCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -29,66 +29,66 @@ namespace Nz createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; createInfo.samples = VK_SAMPLE_COUNT_1_BIT; createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - createInfo.usage = ToVulkan(params.usageFlags); + createInfo.usage = ToVulkan(textureInfo.usageFlags); - switch (params.type) + switch (textureInfo.type) { case ImageType::E1D: - NazaraAssert(params.width > 0, "Width must be over zero"); - 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"); + NazaraAssert(textureInfo.width > 0, "Width must be over zero"); + NazaraAssert(textureInfo.height == 1, "Height must be one"); + NazaraAssert(textureInfo.depth == 1, "Depth must be one"); + NazaraAssert(textureInfo.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.width = textureInfo.width; break; case ImageType::E1D_Array: - NazaraAssert(params.width > 0, "Width must be over zero"); - 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"); + NazaraAssert(textureInfo.width > 0, "Width must be over zero"); + NazaraAssert(textureInfo.height == 1, "Height must be one"); + NazaraAssert(textureInfo.depth == 1, "Depth must be one"); + NazaraAssert(textureInfo.layerCount > 0, "Array count must be over zero"); createInfo.imageType = VK_IMAGE_TYPE_1D; 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"); - NazaraAssert(params.depth == 1, "Depth must be one"); - NazaraAssert(params.layerCount == 1, "Array count must be one"); + NazaraAssert(textureInfo.width > 0, "Width must be over zero"); + NazaraAssert(textureInfo.height > 0, "Height must be over zero"); + NazaraAssert(textureInfo.depth == 1, "Depth must be one"); + NazaraAssert(textureInfo.layerCount == 1, "Array count must be one"); createInfo.imageType = VK_IMAGE_TYPE_2D; 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 == 1, "Depth must be one"); - NazaraAssert(params.layerCount > 0, "Array count must be over zero"); + NazaraAssert(textureInfo.width > 0, "Width must be over zero"); + NazaraAssert(textureInfo.height > 0, "Height must be over zero"); + NazaraAssert(textureInfo.depth == 1, "Depth must be one"); + NazaraAssert(textureInfo.layerCount > 0, "Array count must be over zero"); createInfo.imageType = VK_IMAGE_TYPE_2D; 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"); - NazaraAssert(params.layerCount == 1, "Array count must be one"); + NazaraAssert(textureInfo.width > 0, "Width must be over zero"); + NazaraAssert(textureInfo.height > 0, "Height must be over zero"); + NazaraAssert(textureInfo.depth > 0, "Depth must be over zero"); + NazaraAssert(textureInfo.layerCount == 1, "Array count must be one"); createInfo.imageType = VK_IMAGE_TYPE_3D; 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"); - NazaraAssert(params.depth == 1, "Depth must be one"); - NazaraAssert(params.layerCount % 6 == 0, "Array count must be a multiple of 6"); + NazaraAssert(textureInfo.width > 0, "Width must be over zero"); + NazaraAssert(textureInfo.height > 0, "Height must be over zero"); + NazaraAssert(textureInfo.depth == 1, "Depth must be one"); + NazaraAssert(textureInfo.layerCount % 6 == 0, "Array count must be a multiple of 6"); createInfo.imageType = VK_IMAGE_TYPE_2D; createInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; @@ -99,11 +99,11 @@ namespace Nz break; } - createInfo.extent.width = params.width; - createInfo.extent.height = params.height; - createInfo.extent.depth = params.depth; - createInfo.arrayLayers = params.layerCount; - createInfo.mipLevels = params.mipmapLevel; + createInfo.extent.width = textureInfo.width; + createInfo.extent.height = textureInfo.height; + createInfo.extent.depth = textureInfo.depth; + createInfo.arrayLayers = textureInfo.layerCount; + createInfo.mipLevels = textureInfo.levelCount; VmaAllocationCreateInfo allocInfo = {}; allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; @@ -115,7 +115,7 @@ namespace Nz CallOnExit releaseImage([&]{ vmaDestroyImage(m_device.GetMemoryAllocator(), m_image, m_allocation); }); createInfoView.subresourceRange = { - ToVulkan(PixelFormatInfo::GetContent(params.pixelFormat)), + ToVulkan(PixelFormatInfo::GetContent(textureInfo.pixelFormat)), 0, //< baseMipLevel createInfo.mipLevels, //< levelCount 0, //< baseArrayLayer @@ -128,17 +128,40 @@ namespace Nz throw std::runtime_error("Failed to create default image view: " + TranslateVulkanError(m_imageView.GetLastErrorCode())); releaseImage.Reset(); - createInfoView.image = m_image; + } - { - // FIXME - vmaDestroyImage(m_device.GetMemoryAllocator(), m_image, m_allocation); - } + VulkanTexture::VulkanTexture(std::shared_ptr parentTexture, const TextureViewInfo& viewInfo) : + m_parentTexture(std::move(parentTexture)), + m_image(m_parentTexture->m_image), + m_allocation(nullptr), + m_device(m_parentTexture->m_device) + { + m_textureInfo = ApplyView(m_parentTexture->m_textureInfo, viewInfo); + + NazaraAssert(viewInfo.layerCount <= m_parentTexture->m_textureInfo.layerCount - viewInfo.baseArrayLayer, "layer count exceeds number of layers"); + NazaraAssert(viewInfo.levelCount <= m_parentTexture->m_textureInfo.levelCount - viewInfo.baseMipLevel, "level count exceeds number of levels"); + + VkImageViewCreateInfo createInfoView = {}; + createInfoView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfoView.image = m_image; + createInfoView.subresourceRange = { + ToVulkan(PixelFormatInfo::GetContent(m_textureInfo.pixelFormat)), + 0, //< baseMipLevel + m_textureInfo.levelCount, //< levelCount + 0, //< baseArrayLayer + m_textureInfo.layerCount //< layerCount, will be set if the type is an array/cubemap + }; + + InitViewForFormat(viewInfo.reinterpretFormat, createInfoView); + + if (!m_imageView.Create(m_device, createInfoView)) + throw std::runtime_error("Failed to create image view: " + TranslateVulkanError(m_imageView.GetLastErrorCode())); } VulkanTexture::~VulkanTexture() { - vmaDestroyImage(m_device.GetMemoryAllocator(), m_image, m_allocation); + if (m_allocation) + vmaDestroyImage(m_device.GetMemoryAllocator(), m_image, m_allocation); } bool VulkanTexture::Copy(const Texture& source, const Boxui& srcBox, const Vector3ui& dstPos) @@ -192,30 +215,43 @@ namespace Nz return true; } + std::shared_ptr VulkanTexture::CreateView(const TextureViewInfo& viewInfo) + { + if (m_parentTexture) + return m_parentTexture->CreateView(viewInfo); + + return std::make_shared(std::static_pointer_cast(shared_from_this()), viewInfo); + } + PixelFormat VulkanTexture::GetFormat() const { - return m_params.pixelFormat; + return m_textureInfo.pixelFormat; } UInt8 VulkanTexture::GetLevelCount() const { - return m_params.mipmapLevel; + return m_textureInfo.levelCount; + } + + VulkanTexture* VulkanTexture::GetParentTexture() const + { + return m_parentTexture.get(); } Vector3ui VulkanTexture::GetSize(UInt8 level) const { - return Vector3ui(GetLevelSize(m_params.width, level), GetLevelSize(m_params.height, level), GetLevelSize(m_params.depth, level)); + return Vector3ui(GetLevelSize(m_textureInfo.width, level), GetLevelSize(m_textureInfo.height, level), GetLevelSize(m_textureInfo.depth, level)); } ImageType VulkanTexture::GetType() const { - return m_params.type; + return m_textureInfo.type; } bool VulkanTexture::Update(const void* ptr, const Boxui& box, unsigned int srcWidth, unsigned int srcHeight, UInt8 level) { - std::size_t textureSize = box.width * box.height * box.depth * PixelFormatInfo::GetBytesPerPixel(m_params.pixelFormat); - if (m_params.type == ImageType::Cubemap) + std::size_t textureSize = box.width * box.height * box.depth * PixelFormatInfo::GetBytesPerPixel(m_textureInfo.pixelFormat); + if (m_textureInfo.type == ImageType::Cubemap) textureSize *= 6; VkBufferCreateInfo createInfo = {}; @@ -256,7 +292,7 @@ namespace Nz unsigned int dstWidth = box.width; unsigned int dstHeight = box.height; - unsigned int bpp = PixelFormatInfo::GetBytesPerPixel(m_params.pixelFormat); + unsigned int bpp = PixelFormatInfo::GetBytesPerPixel(m_textureInfo.pixelFormat); unsigned int lineStride = box.width * bpp; unsigned int dstLineStride = dstWidth * bpp; unsigned int dstFaceStride = dstLineStride * dstHeight; @@ -287,14 +323,14 @@ namespace Nz return false; VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT; - if (PixelFormatInfo::GetContent(m_params.pixelFormat) == PixelFormatContent::Depth) + if (PixelFormatInfo::GetContent(m_textureInfo.pixelFormat) == PixelFormatContent::Depth) aspect = VK_IMAGE_ASPECT_DEPTH_BIT; VkImageSubresourceLayers subresourceLayers = { //< FIXME aspect, level, //< mipLevel 0, //< baseArrayLayer - UInt32((m_params.type == ImageType::Cubemap) ? 6 : 1) //< layerCount + UInt32((m_textureInfo.type == ImageType::Cubemap) ? 6 : 1) //< layerCount }; VkImageSubresourceRange subresourceRange = { //< FIXME