From 879b2f7aa634aaf1eb6fa31a8c31ccb2f16c1bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 7 Sep 2021 18:42:53 +0200 Subject: [PATCH] Renderer/Texture: Implement Update of a region + inherit AbstractImage --- .../Nazara/OpenGLRenderer/OpenGLTexture.hpp | 3 +- include/Nazara/Renderer/Texture.hpp | 4 +- include/Nazara/Utility/AbstractImage.hpp | 12 +--- include/Nazara/Utility/AbstractImage.inl | 10 ++++ include/Nazara/VulkanRenderer/Utils.inl | 18 +++--- .../Nazara/VulkanRenderer/VulkanTexture.hpp | 3 +- .../VulkanRenderer/Wrapper/CommandBuffer.hpp | 3 + .../VulkanRenderer/Wrapper/CommandBuffer.inl | 30 +++++++++- src/Nazara/OpenGLRenderer/OpenGLTexture.cpp | 9 ++- src/Nazara/Utility/Image.cpp | 43 +------------ src/Nazara/VulkanRenderer/VulkanTexture.cpp | 60 +++++++++++++++++-- 11 files changed, 122 insertions(+), 73 deletions(-) diff --git a/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp b/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp index 0b97585a8..bf12212c6 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp @@ -29,7 +29,8 @@ namespace Nz inline const GL::Texture& GetTexture() const; ImageType GetType() const override; - bool Update(const void* ptr) override; + using Texture::Update; + bool Update(const void* ptr, const Boxui& box, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) override; OpenGLTexture& operator=(const OpenGLTexture&) = delete; OpenGLTexture& operator=(OpenGLTexture&&) = delete; diff --git a/include/Nazara/Renderer/Texture.hpp b/include/Nazara/Renderer/Texture.hpp index f20fe9069..b4026a2b9 100644 --- a/include/Nazara/Renderer/Texture.hpp +++ b/include/Nazara/Renderer/Texture.hpp @@ -46,7 +46,7 @@ namespace Nz using TextureLoader = ResourceLoader; using TextureManager = ResourceManager; - class NAZARA_RENDERER_API Texture : public Resource + class NAZARA_RENDERER_API Texture : public AbstractImage, public Resource, public std::enable_shared_from_this //< FIXME { public: Texture() = default; @@ -59,8 +59,6 @@ namespace Nz virtual Vector3ui GetSize(UInt8 level = 0) const = 0; virtual ImageType GetType() const = 0; - virtual bool Update(const void* ptr) = 0; - 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/Utility/AbstractImage.hpp b/include/Nazara/Utility/AbstractImage.hpp index f5e3f22ce..0471f3754 100644 --- a/include/Nazara/Utility/AbstractImage.hpp +++ b/include/Nazara/Utility/AbstractImage.hpp @@ -27,23 +27,17 @@ namespace Nz virtual ~AbstractImage(); UInt8 GetBytesPerPixel() const; - virtual unsigned int GetDepth(UInt8 level = 0) const = 0; virtual PixelFormat GetFormat() const = 0; - virtual unsigned int GetHeight(UInt8 level = 0) const = 0; virtual UInt8 GetLevelCount() const = 0; - virtual UInt8 GetMaxLevel() const = 0; - virtual std::size_t GetMemoryUsage() const = 0; - virtual std::size_t GetMemoryUsage(UInt8 level) const = 0; virtual Vector3ui GetSize(UInt8 level = 0) const = 0; virtual ImageType GetType() const = 0; - virtual unsigned int GetWidth(UInt8 level = 0) const = 0; bool IsCompressed() const; bool IsCubemap() const; - virtual bool Update(const UInt8* pixels, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) = 0; - virtual bool Update(const UInt8* pixels, const Boxui& box, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) = 0; - virtual bool Update(const UInt8* pixels, const Rectui& rect, unsigned int z = 0, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) = 0; + inline bool Update(const void* pixels, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0); + virtual bool Update(const void* pixels, const Boxui& box, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) = 0; + inline bool Update(const void* pixels, const Rectui& rect, unsigned int z = 0, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0); AbstractImage& operator=(const AbstractImage&) = default; AbstractImage& operator=(AbstractImage&&) noexcept = default; diff --git a/include/Nazara/Utility/AbstractImage.inl b/include/Nazara/Utility/AbstractImage.inl index 219d06bbd..7ff7cf293 100644 --- a/include/Nazara/Utility/AbstractImage.inl +++ b/include/Nazara/Utility/AbstractImage.inl @@ -2,10 +2,20 @@ // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include namespace Nz { + inline bool AbstractImage::Update(const void* pixels, unsigned int srcWidth, unsigned int srcHeight, UInt8 level) + { + return Update(pixels, GetSize(level), srcWidth, srcHeight, level); + } + + inline bool AbstractImage::Update(const void* pixels, const Rectui& rect, unsigned int z, unsigned int srcWidth, unsigned int srcHeight, UInt8 level) + { + return Update(pixels, Boxui(rect.x, rect.y, z, rect.width, rect.height, 1), srcWidth, srcHeight, level); + } } #include diff --git a/include/Nazara/VulkanRenderer/Utils.inl b/include/Nazara/VulkanRenderer/Utils.inl index a5172ce29..fd82c60d2 100644 --- a/include/Nazara/VulkanRenderer/Utils.inl +++ b/include/Nazara/VulkanRenderer/Utils.inl @@ -249,16 +249,16 @@ namespace Nz { switch (pixelFormat) { - case PixelFormat::BGRA8: return VK_FORMAT_B8G8R8A8_UNORM; - case PixelFormat::BGRA8_SRGB: return VK_FORMAT_B8G8R8A8_SRGB; - case PixelFormat::Depth16: return VK_FORMAT_D16_UNORM; - case PixelFormat::Depth16Stencil8: return VK_FORMAT_D16_UNORM_S8_UINT; - case PixelFormat::Depth24Stencil8: return VK_FORMAT_D24_UNORM_S8_UINT; - case PixelFormat::Depth32F: return VK_FORMAT_D32_SFLOAT; + case PixelFormat::BGRA8: return VK_FORMAT_B8G8R8A8_UNORM; + case PixelFormat::BGRA8_SRGB: return VK_FORMAT_B8G8R8A8_SRGB; + case PixelFormat::Depth16: return VK_FORMAT_D16_UNORM; + case PixelFormat::Depth16Stencil8: return VK_FORMAT_D16_UNORM_S8_UINT; + case PixelFormat::Depth24Stencil8: return VK_FORMAT_D24_UNORM_S8_UINT; + case PixelFormat::Depth32F: return VK_FORMAT_D32_SFLOAT; case PixelFormat::Depth32FStencil8: return VK_FORMAT_D32_SFLOAT_S8_UINT; - case PixelFormat::RGBA8: return VK_FORMAT_R8G8B8A8_UNORM; - case PixelFormat::RGBA8_SRGB: return VK_FORMAT_R8G8B8A8_SRGB; - case PixelFormat::RGBA32F: return VK_FORMAT_R32G32B32A32_SFLOAT; + case PixelFormat::RGBA8: return VK_FORMAT_R8G8B8A8_UNORM; + case PixelFormat::RGBA8_SRGB: return VK_FORMAT_R8G8B8A8_SRGB; + case PixelFormat::RGBA32F: return VK_FORMAT_R32G32B32A32_SFLOAT; default: break; } diff --git a/include/Nazara/VulkanRenderer/VulkanTexture.hpp b/include/Nazara/VulkanRenderer/VulkanTexture.hpp index 32bbfa485..dd801e391 100644 --- a/include/Nazara/VulkanRenderer/VulkanTexture.hpp +++ b/include/Nazara/VulkanRenderer/VulkanTexture.hpp @@ -30,7 +30,8 @@ namespace Nz Vector3ui GetSize(UInt8 level = 0) const override; ImageType GetType() const override; - bool Update(const void* ptr) override; + using Texture::Update; + bool Update(const void* ptr, const Boxui& box, unsigned int srcWidth, unsigned int srcHeight, UInt8 level) override; VulkanTexture& operator=(const VulkanTexture&) = delete; VulkanTexture& operator=(VulkanTexture&&) = delete; diff --git a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp index 7f3397641..99c3f3cfc 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp +++ b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp @@ -57,7 +57,10 @@ namespace Nz inline void CopyBuffer(VkBuffer source, VkBuffer target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0); inline void CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, UInt32 width, UInt32 height, UInt32 depth = 1); + inline void CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, const VkImageSubresourceLayers& subresourceLayers, Int32 x, Int32 y, Int32 z, UInt32 width, UInt32 height, UInt32 depth); inline void CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, const VkImageSubresourceLayers& subresourceLayers, UInt32 width, UInt32 height, UInt32 depth = 1); + inline void CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, const VkImageSubresourceLayers& subresourceLayers, const VkBufferImageCopy& region); + inline void CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, const VkImageSubresourceLayers& subresourceLayers, UInt32 regionCount, const VkBufferImageCopy* regions); inline void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0); inline void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, Int32 vertexOffset = 0, UInt32 firstInstance = 0); diff --git a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl index 632902ac5..22e76e6db 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl @@ -236,6 +236,24 @@ namespace Nz return CopyBufferToImage(source, target, targetLayout, subresourceLayers, width, height, depth); } + inline void CommandBuffer::CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, const VkImageSubresourceLayers& subresourceLayers, Int32 x, Int32 y, Int32 z, UInt32 width, UInt32 height, UInt32 depth) + { + VkBufferImageCopy region = { + 0, + 0, + 0, + subresourceLayers, + { // imageOffset + x, y, z + }, + { // imageExtent + width, height, depth + } + }; + + return CopyBufferToImage(source, target, targetLayout, subresourceLayers, region); + } + inline void CommandBuffer::CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, const VkImageSubresourceLayers& subresourceLayers, UInt32 width, UInt32 height, UInt32 depth) { VkBufferImageCopy region = { @@ -251,7 +269,17 @@ namespace Nz } }; - return m_pool->GetDevice()->vkCmdCopyBufferToImage(m_handle, source, target, targetLayout, 1, ®ion); + return CopyBufferToImage(source, target, targetLayout, subresourceLayers, region); + } + + inline void CommandBuffer::CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, const VkImageSubresourceLayers& subresourceLayers, const VkBufferImageCopy& region) + { + return CopyBufferToImage(source, target, targetLayout, subresourceLayers, 1, ®ion); + } + + inline void CommandBuffer::CopyBufferToImage(VkBuffer source, VkImage target, VkImageLayout targetLayout, const VkImageSubresourceLayers& subresourceLayers, UInt32 regionCount, const VkBufferImageCopy* regions) + { + return m_pool->GetDevice()->vkCmdCopyBufferToImage(m_handle, source, target, targetLayout, regionCount, regions); } inline void CommandBuffer::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) diff --git a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp index 91e5e6a2f..ec79bc659 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp @@ -73,7 +73,7 @@ namespace Nz return m_params.type; } - bool OpenGLTexture::Update(const void* ptr) + bool OpenGLTexture::Update(const void* ptr, const Boxui& box, unsigned int srcWidth, unsigned int srcHeight, UInt8 level) { auto format = DescribeTextureFormat(m_params.pixelFormat); assert(format); @@ -90,6 +90,9 @@ namespace Nz else context.glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + context.glPixelStorei(GL_UNPACK_ROW_LENGTH, srcWidth); + context.glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, srcHeight); + switch (m_params.type) { case ImageType::E1D: @@ -99,7 +102,7 @@ namespace Nz break; case ImageType::E2D: - m_texture.TexSubImage2D(GL::TextureTarget::Target2D, 0, 0, 0, m_params.width, m_params.height, format->format, format->type, ptr); + m_texture.TexSubImage2D(GL::TextureTarget::Target2D, level, box.x, box.y, box.width, box.height, format->format, format->type, ptr); break; case ImageType::E2D_Array: @@ -115,7 +118,7 @@ namespace Nz for (GL::TextureTarget face : { GL::TextureTarget::CubemapPositiveX, GL::TextureTarget::CubemapNegativeX, GL::TextureTarget::CubemapPositiveY, GL::TextureTarget::CubemapNegativeY, GL::TextureTarget::CubemapPositiveZ, GL::TextureTarget::CubemapNegativeZ }) { - m_texture.TexSubImage2D(face, 0, 0, 0, m_params.width, m_params.height, format->format, format->type, facePtr); + m_texture.TexSubImage2D(face, level, box.x, box.y, box.width, box.height, format->format, format->type, facePtr); facePtr += faceSize; } break; diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index d81cdb9df..7bfb76fb9 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -1248,41 +1248,7 @@ namespace Nz return true; } - bool Image::Update(const UInt8* pixels, unsigned int srcWidth, unsigned int srcHeight, UInt8 level) - { - #if NAZARA_UTILITY_SAFE - if (m_sharedImage == &emptyImage) - { - NazaraError("Image must be valid"); - return false; - } - - if (!pixels) - { - NazaraError("Invalid pixel source"); - return false; - } - - if (level >= m_sharedImage->levels.size()) - { - NazaraError("Level out of bounds (" + NumberToString(level) + " >= " + NumberToString(m_sharedImage->levels.size()) + ')'); - return false; - } - #endif - - EnsureOwnership(); - - Copy(m_sharedImage->levels[level].get(), pixels, m_sharedImage->format, - GetLevelSize(m_sharedImage->width, level), - GetLevelSize(m_sharedImage->height, level), - GetLevelSize(m_sharedImage->depth, level), - 0, 0, - srcWidth, srcHeight); - - return true; - } - - bool Image::Update(const UInt8* pixels, const Boxui& box, unsigned int srcWidth, unsigned int srcHeight, UInt8 level) + bool Image::Update(const void* pixels, const Boxui& box, unsigned int srcWidth, unsigned int srcHeight, UInt8 level) { #if NAZARA_UTILITY_SAFE if (m_sharedImage == &emptyImage) @@ -1328,7 +1294,7 @@ namespace Nz UInt8 bpp = PixelFormatInfo::GetBytesPerPixel(m_sharedImage->format); UInt8* dstPixels = GetPixelPtr(m_sharedImage->levels[level].get(), bpp, box.x, box.y, box.z, width, height); - Copy(dstPixels, pixels, m_sharedImage->format, + Copy(dstPixels, static_cast(pixels), m_sharedImage->format, box.width, box.height, box.depth, width, height, srcWidth, srcHeight); @@ -1336,11 +1302,6 @@ namespace Nz return true; } - bool Image::Update(const UInt8* pixels, const Rectui& rect, unsigned int z, unsigned int srcWidth, unsigned int srcHeight, UInt8 level) - { - return Update(pixels, Boxui(rect.x, rect.y, z, rect.width, rect.height, 1), srcWidth, srcHeight, level); - } - Image& Image::operator=(const Image& image) { ReleaseImage(); diff --git a/src/Nazara/VulkanRenderer/VulkanTexture.cpp b/src/Nazara/VulkanRenderer/VulkanTexture.cpp index e4911e4b3..ab8a4d2c9 100644 --- a/src/Nazara/VulkanRenderer/VulkanTexture.cpp +++ b/src/Nazara/VulkanRenderer/VulkanTexture.cpp @@ -167,9 +167,9 @@ namespace Nz return m_params.type; } - bool VulkanTexture::Update(const void* ptr) + bool VulkanTexture::Update(const void* ptr, const Boxui& box, unsigned int srcWidth, unsigned int srcHeight, UInt8 level) { - std::size_t textureSize = m_params.width * m_params.height * m_params.depth * PixelFormatInfo::GetBytesPerPixel(m_params.pixelFormat); + std::size_t textureSize = box.width * box.height * box.depth * PixelFormatInfo::GetBytesPerPixel(m_params.pixelFormat); if (m_params.type == ImageType::Cubemap) textureSize *= 6; @@ -198,7 +198,44 @@ namespace Nz vmaDestroyBuffer(m_device.GetMemoryAllocator(), stagingBuffer, stagingAllocation); }); - std::memcpy(allocationInfo.pMappedData, ptr, textureSize); + if (srcWidth == 0) + srcWidth = box.width; + + if (srcHeight == 0) + srcHeight = box.height; + + if (srcWidth == box.width && srcHeight == box.height) + std::memcpy(allocationInfo.pMappedData, ptr, textureSize); + else + { + unsigned int dstWidth = box.width; + unsigned int dstHeight = box.height; + + unsigned int bpp = PixelFormatInfo::GetBytesPerPixel(m_params.pixelFormat); + unsigned int lineStride = box.width * bpp; + unsigned int dstLineStride = dstWidth * bpp; + unsigned int dstFaceStride = dstLineStride * dstHeight; + unsigned int srcLineStride = srcWidth * bpp; + unsigned int srcFaceStride = srcLineStride * srcHeight; + + const UInt8* source = static_cast(ptr); + UInt8* destination = static_cast(allocationInfo.pMappedData); + for (unsigned int i = 0; i < box.depth; ++i) + { + UInt8* dstFacePtr = destination; + const UInt8* srcFacePtr = source; + for (unsigned int y = 0; y < box.height; ++y) + { + std::memcpy(dstFacePtr, srcFacePtr, lineStride); + + dstFacePtr += dstLineStride; + srcFacePtr += srcLineStride; + } + + destination += dstFaceStride; + source += srcFaceStride; + } + } Vk::AutoCommandBuffer copyCommandBuffer = m_device.AllocateCommandBuffer(QueueType::Graphics); if (!copyCommandBuffer->Begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)) @@ -206,7 +243,7 @@ namespace Nz VkImageSubresourceLayers subresourceLayers = { //< FIXME VK_IMAGE_ASPECT_COLOR_BIT, - 0, //< mipLevel + level, //< mipLevel 0, //< baseArrayLayer UInt32((m_params.type == ImageType::Cubemap) ? 6 : 1) //< layerCount }; @@ -219,9 +256,22 @@ namespace Nz subresourceLayers.layerCount //< layerCount }; + VkBufferImageCopy region = { + 0, + 0, + 0, + subresourceLayers, + { // imageOffset + box.x, box.y, box.z + }, + { // imageExtent + box.width, box.height, box.depth + } + }; + copyCommandBuffer->SetImageLayout(m_image, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceRange); - copyCommandBuffer->CopyBufferToImage(stagingBuffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceLayers, m_params.width, m_params.height, m_params.depth); + copyCommandBuffer->CopyBufferToImage(stagingBuffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceLayers, region); copyCommandBuffer->SetImageLayout(m_image, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, subresourceRange);