Renderer/CommandBuffer: Add support for texture blit/copy

This commit is contained in:
Jérôme Leclercq 2021-12-03 22:15:34 +01:00
parent 53747abf6e
commit 17df8fafa4
12 changed files with 178 additions and 5 deletions

View File

@ -41,9 +41,11 @@ namespace Nz
inline void BindPipeline(const OpenGLRenderPipeline* pipeline);
inline void BindShaderBinding(const OpenGLRenderPipelineLayout& pipelineLayout, UInt32 set, const OpenGLShaderBinding* binding);
inline void BindVertexBuffer(UInt32 binding, GLuint vertexBuffer, UInt64 offset = 0);
inline void BlitTexture(const GL::Texture& source, const Boxui& sourceBox, const GL::Texture& target, const Boxui& targetBox, SamplerFilter filter = SamplerFilter::Nearest);
inline void CopyBuffer(GLuint source, GLuint target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0);
inline void CopyBuffer(const UploadPool::Allocation& allocation, GLuint target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0);
inline void CopyTexture(const GL::Texture& source, const Boxui& sourceBox, const GL::Texture& target, const Vector3ui& targetPoint);
inline void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0);
inline void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstIndex = 0, UInt32 firstInstance = 0);
@ -75,6 +77,15 @@ namespace Nz
Color color;
};
struct BlitTextureData
{
const GL::Texture* source;
const GL::Texture* target;
Boxui sourceBox;
Boxui targetBox;
SamplerFilter filter;
};
struct CopyBufferData
{
GLuint source;
@ -84,6 +95,14 @@ namespace Nz
UInt64 targetOffset;
};
struct CopyTextureData
{
const GL::Texture* source;
const GL::Texture* target;
Boxui sourceBox;
Vector3ui targetPoint;
};
struct CopyBufferFromMemoryData
{
const void* memory;
@ -141,8 +160,10 @@ namespace Nz
using CommandData = std::variant<
BeginDebugRegionData,
BlitTextureData,
CopyBufferData,
CopyBufferFromMemoryData,
CopyTextureData,
DrawData,
DrawIndexedData,
EndDebugRegionData,

View File

@ -62,6 +62,19 @@ namespace Nz
vertexBufferData.vertexBuffer = vertexBuffer;
}
inline void OpenGLCommandBuffer::BlitTexture(const GL::Texture& source, const Boxui& sourceBox, const GL::Texture& target, const Boxui& targetBox, SamplerFilter filter)
{
BlitTextureData blitTexture = {
&source,
&target,
sourceBox,
targetBox,
filter
};
m_commands.emplace_back(std::move(blitTexture));
}
inline void OpenGLCommandBuffer::CopyBuffer(GLuint source, GLuint target, UInt64 size, UInt64 sourceOffset, UInt64 targetOffset)
{
CopyBufferData copyBuffer = {
@ -87,6 +100,18 @@ namespace Nz
m_commands.emplace_back(std::move(copyBuffer));
}
inline void OpenGLCommandBuffer::CopyTexture(const GL::Texture& source, const Boxui& sourceBox, const GL::Texture& target, const Vector3ui& targetPoint)
{
CopyTextureData copyTexture = {
&source,
&target,
sourceBox,
targetPoint
};
m_commands.emplace_back(std::move(copyTexture));
}
inline void OpenGLCommandBuffer::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance)
{
if (!m_currentStates.pipeline)

View File

@ -32,8 +32,11 @@ namespace Nz
void BindShaderBinding(const RenderPipelineLayout& pipelineLayout, UInt32 set, const ShaderBinding& binding) override;
void BindVertexBuffer(UInt32 binding, const AbstractBuffer& vertexBuffer, UInt64 offset = 0) override;
void BlitTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Boxui& toBox, TextureLayout toLayout, SamplerFilter filter) override;
void CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0) override;
void CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0) override;
void CopyTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Vector3ui& toPos, TextureLayout toLayout) override;
void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0) override;
void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstIndex = 0, UInt32 firstInstance = 0) override;

View File

@ -125,7 +125,7 @@ namespace Nz::GL
void BindUniformBuffer(UInt32 uboUnit, GLuint buffer, GLintptr offset, GLsizeiptr size) const;
void BindVertexArray(GLuint vertexArray, bool force = false) const;
bool BlitTexture(const Texture& source, const Texture& destination, const Boxui& srcBox, const Vector3ui& dstPos, SamplerFilter filter) const;
bool BlitTexture(const Texture& source, const Texture& destination, const Boxui& srcBox, const Boxui& dstBox, SamplerFilter filter) const;
bool ClearErrorStack() const;

View File

@ -9,11 +9,13 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Color.hpp>
#include <Nazara/Math/Box.hpp>
#include <Nazara/Math/Rect.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/Enums.hpp>
#include <Nazara/Renderer/RenderBufferView.hpp>
#include <Nazara/Renderer/UploadPool.hpp>
#include <Nazara/Utility/Enums.hpp>
#include <string_view>
namespace Nz
@ -46,10 +48,13 @@ namespace Nz
virtual void BindShaderBinding(const RenderPipelineLayout& pipelineLayout, UInt32 set, const ShaderBinding& binding) = 0;
virtual void BindVertexBuffer(UInt32 binding, const AbstractBuffer& vertexBuffer, UInt64 offset = 0) = 0;
virtual void BlitTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Boxui& toBox, TextureLayout toLayout, SamplerFilter filter) = 0;
inline void CopyBuffer(const RenderBufferView& source, const RenderBufferView& target);
virtual void CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 fromOffset = 0, UInt64 toOffset = 0) = 0;
inline void CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target);
virtual void CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target, UInt64 size, UInt64 fromOffset = 0, UInt64 toOffset = 0) = 0;
virtual void CopyTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Vector3ui& toPos, TextureLayout toLayout) = 0;
virtual void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0) = 0;
virtual void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstIndex = 0, UInt32 firstInstance = 0) = 0;

View File

@ -33,8 +33,11 @@ namespace Nz
void BindShaderBinding(const RenderPipelineLayout& pipelineLayout, UInt32 set, const ShaderBinding& binding) override;
void BindVertexBuffer(UInt32 binding, const AbstractBuffer& vertexBuffer, UInt64 offset = 0) override;
void BlitTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Boxui& toBox, TextureLayout toLayout, SamplerFilter filter) override;
void CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0) override;
void CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0) override;
void CopyTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Vector3ui& toPos, TextureLayout toLayout) override;
void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0) override;
void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstIndex = 0, UInt32 firstInstance = 0) override;

View File

@ -46,6 +46,9 @@ namespace Nz
inline void BindVertexBuffer(UInt32 binding, const VkBuffer buffer, const VkDeviceSize offset);
inline void BindVertexBuffers(UInt32 firstBinding, UInt32 bindingCount, const VkBuffer* buffer, const VkDeviceSize* offset);
inline void BlitImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, const VkImageBlit& region, VkFilter filter);
inline void BlitImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, UInt32 regionCount, const VkImageBlit* regions, VkFilter filter);
inline void ClearAttachment(const VkClearAttachment& attachment, const VkClearRect& rect);
inline void ClearAttachments(UInt32 attachmentCount, const VkClearAttachment* attachments, UInt32 rectCount, const VkClearRect* rects);

View File

@ -184,6 +184,16 @@ namespace Nz
return m_pool->GetDevice()->vkCmdBindVertexBuffers(m_handle, firstBinding, bindingCount, buffer, offset);
}
inline void CommandBuffer::BlitImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, const VkImageBlit& region, VkFilter filter)
{
return BlitImage(srcImage, srcImageLayout, dstImage, dstImageLayout, 1U, &region, filter);
}
inline void CommandBuffer::BlitImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, UInt32 regionCount, const VkImageBlit* regions, VkFilter filter)
{
return m_pool->GetDevice()->vkCmdBlitImage(m_handle, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, regions, filter);
}
inline void CommandBuffer::ClearAttachment(const VkClearAttachment& attachment, const VkClearRect& rect)
{
return ClearAttachments(1U, &attachment, 1U, &rect);

View File

@ -78,6 +78,10 @@ namespace Nz
if (context->glPushDebugGroup)
context->glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, GLsizei(command.regionName.size()), command.regionName.data());
}
else if constexpr (std::is_same_v<T, BlitTextureData>)
{
context->BlitTexture(*command.source, *command.target, command.sourceBox, command.targetBox, command.filter);
}
else if constexpr (std::is_same_v<T, CopyBufferData>)
{
context->BindBuffer(GL::BufferTarget::CopyRead, command.source);
@ -89,6 +93,10 @@ namespace Nz
context->BindBuffer(GL::BufferTarget::CopyWrite, command.target);
context->glBufferSubData(GL_COPY_WRITE_BUFFER, command.targetOffset, command.size, command.memory);
}
else if constexpr (std::is_same_v<T, CopyTextureData>)
{
context->CopyTexture(*command.source, *command.target, command.sourceBox, command.targetPoint);
}
else if constexpr (std::is_same_v<T, DrawData>)
{
ApplyStates(*context, command.states);

View File

@ -9,6 +9,7 @@
#include <Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp>
#include <Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp>
#include <Nazara/OpenGLRenderer/OpenGLTexture.hpp>
#include <Nazara/OpenGLRenderer/OpenGLUploadPool.hpp>
#include <Nazara/OpenGLRenderer/Debug.hpp>
@ -60,6 +61,14 @@ namespace Nz
m_commandBuffer.BindVertexBuffer(binding, glBuffer.GetBuffer().GetObjectId(), offset);
}
void OpenGLCommandBufferBuilder::BlitTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout /*fromLayout*/, const Texture& toTexture, const Boxui& toBox, TextureLayout /*toLayout*/, SamplerFilter filter)
{
const OpenGLTexture& sourceTexture = static_cast<const OpenGLTexture&>(fromTexture);
const OpenGLTexture& targetTexture = static_cast<const OpenGLTexture&>(toTexture);
m_commandBuffer.BlitTexture(sourceTexture.GetTexture(), fromBox, targetTexture.GetTexture(), toBox, filter);
}
void OpenGLCommandBufferBuilder::CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset, UInt64 targetOffset)
{
OpenGLBuffer& sourceBuffer = *static_cast<OpenGLBuffer*>(source.GetBuffer());
@ -75,6 +84,14 @@ namespace Nz
m_commandBuffer.CopyBuffer(allocation, targetBuffer.GetBuffer().GetObjectId(), size, sourceOffset, target.GetOffset() + targetOffset);
}
void OpenGLCommandBufferBuilder::CopyTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Vector3ui& toPos, TextureLayout toLayout)
{
const OpenGLTexture& sourceTexture = static_cast<const OpenGLTexture&>(fromTexture);
const OpenGLTexture& targetTexture = static_cast<const OpenGLTexture&>(toTexture);
m_commandBuffer.CopyTexture(sourceTexture.GetTexture(), fromBox, targetTexture.GetTexture(), toPos);
}
void OpenGLCommandBufferBuilder::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance)
{
m_commandBuffer.Draw(vertexCount, instanceCount, firstVertex, firstInstance);

View File

@ -249,7 +249,7 @@ namespace Nz::GL
}
}
bool Context::BlitTexture(const Texture& source, const Texture& destination, const Boxui& srcBox, const Vector3ui& dstPos, SamplerFilter filter) const
bool Context::BlitTexture(const Texture& source, const Texture& destination, const Boxui& srcBox, const Boxui& dstBox, SamplerFilter filter) const
{
if (!m_blitFramebuffers && !InitializeBlitFramebuffers())
return false;
@ -277,7 +277,7 @@ namespace Nz::GL
return false;
}
glBlitFramebuffer(srcBox.x, srcBox.y, srcBox.x + srcBox.width, srcBox.y + srcBox.height, dstPos.x, dstPos.y, dstPos.x + srcBox.width, dstPos.y + srcBox.height, GL_COLOR_BUFFER_BIT, ToOpenGL(filter));
glBlitFramebuffer(srcBox.x, srcBox.y, srcBox.x + srcBox.width, srcBox.y + srcBox.height, dstBox.x, dstBox.y, dstBox.x + dstBox.width, dstBox.y + srcBox.height, GL_COLOR_BUFFER_BIT, ToOpenGL(filter));
return true;
}
@ -296,7 +296,7 @@ namespace Nz::GL
bool Context::CopyTexture(const Texture& source, const Texture& destination, const Boxui& srcBox, const Vector3ui& dstPos) const
{
// Use glCopyImageSubData if available
if (glCopyImageSubData && false)
if (glCopyImageSubData)
{
GLuint srcImage = source.GetObjectId();
GLenum srcTarget = ToOpenGL(source.GetTarget());
@ -310,7 +310,7 @@ namespace Nz::GL
else
{
// If glCopyImageSubData is not available, fallback to framebuffer blit
return BlitTexture(source, destination, srcBox, dstPos, SamplerFilter::Nearest);
return BlitTexture(source, destination, srcBox, Boxui(dstPos.x, dstPos.y, dstPos.z, srcBox.width, srcBox.height, srcBox.depth), SamplerFilter::Nearest);
}
}

View File

@ -110,6 +110,50 @@ namespace Nz
m_commandBuffer.BindVertexBuffer(binding, vkBuffer.GetBuffer(), offset);
}
void VulkanCommandBufferBuilder::BlitTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Boxui& toBox, TextureLayout toLayout, SamplerFilter filter)
{
const VulkanTexture& vkFromTexture = static_cast<const VulkanTexture&>(fromTexture);
const VulkanTexture& vkToTexture = static_cast<const VulkanTexture&>(toTexture);
VkImageSubresourceLayers todo = {
VK_IMAGE_ASPECT_COLOR_BIT,
1,
0,
1
};
VkImageBlit region = {
todo,
{
{
SafeCast<Int32>(fromBox.x),
SafeCast<Int32>(fromBox.y),
SafeCast<Int32>(fromBox.z)
},
{
SafeCast<Int32>(fromBox.x + fromBox.width),
SafeCast<Int32>(fromBox.y + fromBox.height),
SafeCast<Int32>(fromBox.z + fromBox.depth)
}
},
todo,
{
{
SafeCast<Int32>(toBox.x),
SafeCast<Int32>(toBox.y),
SafeCast<Int32>(toBox.z)
},
{
SafeCast<Int32>(toBox.x + toBox.width),
SafeCast<Int32>(toBox.y + toBox.height),
SafeCast<Int32>(toBox.z + toBox.depth)
}
},
};
m_commandBuffer.BlitImage(vkFromTexture.GetImage(), ToVulkan(fromLayout), vkToTexture.GetImage(), ToVulkan(toLayout), region, ToVulkan(filter));
}
void VulkanCommandBufferBuilder::CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset, UInt64 targetOffset)
{
VulkanBuffer& sourceBuffer = *static_cast<VulkanBuffer*>(source.GetBuffer());
@ -126,6 +170,40 @@ namespace Nz
m_commandBuffer.CopyBuffer(vkAllocation.buffer, targetBuffer.GetBuffer(), size, vkAllocation.offset + sourceOffset, target.GetOffset() + targetOffset);
}
void VulkanCommandBufferBuilder::CopyTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Vector3ui& toPos, TextureLayout toLayout)
{
const VulkanTexture& vkFromTexture = static_cast<const VulkanTexture&>(fromTexture);
const VulkanTexture& vkToTexture = static_cast<const VulkanTexture&>(toTexture);
VkImageSubresourceLayers todo = {
VK_IMAGE_ASPECT_COLOR_BIT,
1,
0,
1
};
VkImageCopy region = {
todo,
{
SafeCast<Int32>(fromBox.x),
SafeCast<Int32>(fromBox.y),
SafeCast<Int32>(fromBox.z)
},
{
SafeCast<Int32>(toPos.x),
SafeCast<Int32>(toPos.y),
SafeCast<Int32>(toPos.z),
},
{
SafeCast<Int32>(fromBox.width),
SafeCast<Int32>(fromBox.height),
SafeCast<Int32>(fromBox.depth)
}
};
m_commandBuffer.CopyImage(vkFromTexture.GetImage(), ToVulkan(fromLayout), vkToTexture.GetImage(), ToVulkan(toLayout), region);
}
void VulkanCommandBufferBuilder::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance)
{
m_commandBuffer.Draw(vertexCount, instanceCount, firstVertex, firstInstance);