diff --git a/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp b/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp index bf12212c6..a21f0c038 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLTexture.hpp @@ -23,6 +23,8 @@ namespace Nz OpenGLTexture(OpenGLTexture&&) = delete; ~OpenGLTexture() = default; + bool Copy(const Texture& source, const Boxui& srcBox, const Vector3ui& dstPos) override; + PixelFormat GetFormat() const override; UInt8 GetLevelCount() const override; Vector3ui GetSize(UInt8 level = 0) const override; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp b/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp index c9851592f..fedf69667 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp @@ -167,6 +167,8 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const G cb(glVertexAttribPointer, PFNGLVERTEXATTRIBPOINTERPROC) \ cb(glViewport, PFNGLVIEWPORTPROC) \ \ + extCb(glCopyImageSubData, PFNGLCOPYIMAGESUBDATAPROC) \ + \ extCb(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \ \ extCb(glPolygonMode, PFNGLPOLYGONMODEPROC) \ diff --git a/include/Nazara/Renderer/Texture.hpp b/include/Nazara/Renderer/Texture.hpp index b4026a2b9..a7920d781 100644 --- a/include/Nazara/Renderer/Texture.hpp +++ b/include/Nazara/Renderer/Texture.hpp @@ -54,6 +54,8 @@ namespace Nz Texture(Texture&&) = delete; virtual ~Texture(); + virtual bool Copy(const Texture& source, const Boxui& srcBox, const Vector3ui& dstPos = Vector3ui::Zero()) = 0; + virtual PixelFormat GetFormat() const = 0; virtual UInt8 GetLevelCount() const = 0; virtual Vector3ui GetSize(UInt8 level = 0) const = 0; diff --git a/include/Nazara/VulkanRenderer/VulkanTexture.hpp b/include/Nazara/VulkanRenderer/VulkanTexture.hpp index dd801e391..864f45295 100644 --- a/include/Nazara/VulkanRenderer/VulkanTexture.hpp +++ b/include/Nazara/VulkanRenderer/VulkanTexture.hpp @@ -23,6 +23,8 @@ namespace Nz VulkanTexture(VulkanTexture&&) = delete; ~VulkanTexture(); + bool Copy(const Texture& source, const Boxui& srcBox, const Vector3ui& dstPos) override; + PixelFormat GetFormat() const override; inline VkImage GetImage() const; inline VkImageView GetImageView() const; diff --git a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp index 99c3f3cfc..0bda704dc 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp +++ b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.hpp @@ -61,6 +61,8 @@ namespace Nz 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 CopyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, const VkImageCopy& region); + inline void CopyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, UInt32 regionCount, const VkImageCopy* 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 22e76e6db..edd97068c 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/CommandBuffer.inl @@ -282,6 +282,16 @@ namespace Nz return m_pool->GetDevice()->vkCmdCopyBufferToImage(m_handle, source, target, targetLayout, regionCount, regions); } + inline void CommandBuffer::CopyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, const VkImageCopy& region) + { + return CopyImage(srcImage, srcImageLayout, dstImage, dstImageLayout, 1U, ®ion); + } + + inline void CommandBuffer::CopyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, UInt32 regionCount, const VkImageCopy* regions) + { + return m_pool->GetDevice()->vkCmdCopyImage(m_handle, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, regions); + } + inline void CommandBuffer::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) { return m_pool->GetDevice()->vkCmdDraw(m_handle, vertexCount, instanceCount, firstVertex, firstInstance); diff --git a/src/Nazara/Graphics/GuillotineTextureAtlas.cpp b/src/Nazara/Graphics/GuillotineTextureAtlas.cpp index 5d6c35d1a..4da4db68e 100644 --- a/src/Nazara/Graphics/GuillotineTextureAtlas.cpp +++ b/src/Nazara/Graphics/GuillotineTextureAtlas.cpp @@ -48,23 +48,14 @@ namespace Nz if (oldImage) { - return nullptr; - /*const Texture& oldTexture = static_cast(*oldImage); + const Texture& oldTexture = static_cast(*oldImage); + Vector3ui oldSize = oldTexture.GetSize(); - // Copy of old data - ///TODO: Copy from texture to texture - Image image; - if (!oldTexture->Download(&image)) - { - NazaraError("Failed to download old texture"); - return nullptr; - } - - if (!newTexture->Update(&image, Rectui(0, 0, image.GetWidth(), image.GetHeight()))) + if (!newTexture->Copy(oldTexture, Rectui(0, 0, oldSize.x, oldSize.y))) { NazaraError("Failed to update texture"); return nullptr; - }*/ + } } return newTexture; diff --git a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp index ec79bc659..e08410ade 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp @@ -53,6 +53,32 @@ namespace Nz m_texture.SetParameteri(GL_TEXTURE_SWIZZLE_A, format->swizzleA); } + bool OpenGLTexture::Copy(const Texture& source, const Boxui& srcBox, const Vector3ui& dstPos) + { + const OpenGLTexture& glTexture = static_cast(source); + + const GL::Context& context = m_texture.EnsureDeviceContext(); + + // Use glCopyImageSubData if available + if (context.glCopyImageSubData) + { + GLuint srcImage = glTexture.GetTexture().GetObjectId(); + GLenum srcTarget = ToOpenGL(ToTextureTarget(glTexture.GetType())); + + GLuint dstImage = m_texture.GetObjectId(); + GLenum dstTarget = ToOpenGL(ToTextureTarget(m_params.type)); + + context.glCopyImageSubData(srcImage, srcTarget, 0, GLint(srcBox.x), GLint(srcBox.y), GLint(srcBox.z), dstImage, dstTarget, 0, GLint(dstPos.x), GLint(dstPos.y), GLint(dstPos.z), GLsizei(srcBox.width), GLsizei(srcBox.height), GLsizei(srcBox.depth)); + return true; + } + else + { + //TODO: Blit using framebuffers + } + + return false; + } + PixelFormat OpenGLTexture::GetFormat() const { return m_params.pixelFormat; diff --git a/src/Nazara/VulkanRenderer/VulkanTexture.cpp b/src/Nazara/VulkanRenderer/VulkanTexture.cpp index ab8a4d2c9..89703aa72 100644 --- a/src/Nazara/VulkanRenderer/VulkanTexture.cpp +++ b/src/Nazara/VulkanRenderer/VulkanTexture.cpp @@ -147,6 +147,57 @@ namespace Nz vmaDestroyImage(m_device.GetMemoryAllocator(), m_image, m_allocation); } + bool VulkanTexture::Copy(const Texture& source, const Boxui& srcBox, const Vector3ui& dstPos) + { + const VulkanTexture& sourceTexture = static_cast(source); + + Vk::AutoCommandBuffer copyCommandBuffer = m_device.AllocateCommandBuffer(QueueType::Graphics); + if (!copyCommandBuffer->Begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)) + return false; + + VkImageSubresourceLayers subresourceLayers = { //< FIXME + VK_IMAGE_ASPECT_COLOR_BIT, + 0, //< mipLevel + 0, //< baseArrayLayer + 1 //< layerCount + }; + + VkImageSubresourceRange subresourceRange = { //< FIXME + VK_IMAGE_ASPECT_COLOR_BIT, + 0, //< baseMipLevel + 1, //< levelCount + subresourceLayers.baseArrayLayer, //< baseArrayLayer + subresourceLayers.layerCount //< layerCount + }; + + VkImageCopy region = { + subresourceLayers, + VkOffset3D { static_cast(srcBox.x), static_cast(srcBox.y), static_cast(srcBox.z) }, + subresourceLayers, + VkOffset3D { static_cast(dstPos.x), static_cast(dstPos.y), static_cast(dstPos.z) }, + VkExtent3D { static_cast(srcBox.width), static_cast(srcBox.height), static_cast(srcBox.depth) } + }; + + copyCommandBuffer->SetImageLayout(sourceTexture.GetImage(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, subresourceRange); + 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->CopyImage(sourceTexture.GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, region); + + copyCommandBuffer->SetImageLayout(sourceTexture.GetImage(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, subresourceRange); + 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); + + if (!copyCommandBuffer->End()) + return false; + + Vk::QueueHandle transferQueue = m_device.GetQueue(m_device.GetDefaultFamilyIndex(QueueType::Graphics), 0); + if (!transferQueue.Submit(copyCommandBuffer)) + return false; + + transferQueue.WaitIdle(); + + return true; + } + PixelFormat VulkanTexture::GetFormat() const { return m_params.pixelFormat;