From a0215b7eb6d2eb5ead0edc711dc6393ae870c062 Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Fri, 14 Mar 2025 15:51:25 +0100 Subject: [PATCH 1/4] Fix texture copy when using multiple canvas --- Plugins/NativeEngine/Source/NativeEngine.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Plugins/NativeEngine/Source/NativeEngine.cpp b/Plugins/NativeEngine/Source/NativeEngine.cpp index 329176b8d..e19beb177 100644 --- a/Plugins/NativeEngine/Source/NativeEngine.cpp +++ b/Plugins/NativeEngine/Source/NativeEngine.cpp @@ -1435,7 +1435,9 @@ namespace Babylon arcana::make_task(m_update.Scheduler(), *m_cancellationSource, [this, textureDestination, textureSource, cancellationSource = m_cancellationSource]() { return arcana::make_task(m_runtimeScheduler, *m_cancellationSource, [this, textureDestination, textureSource, updateToken = m_update.GetUpdateToken(), cancellationSource = m_cancellationSource]() { bgfx::Encoder* encoder = m_update.GetUpdateToken().GetEncoder(); - GetBoundFrameBuffer(*encoder).Blit(*encoder, textureDestination->Handle(), 0, 0, textureSource->Handle()); + auto& boundFramebuffer = GetBoundFrameBuffer(*encoder); + boundFramebuffer.Bind(*encoder); + boundFramebuffer.Blit(*encoder, textureDestination->Handle(), 0, 0, textureSource->Handle()); }).then(arcana::inline_scheduler, *m_cancellationSource, [this, cancellationSource{m_cancellationSource}](const arcana::expected& result) { if (!cancellationSource->cancelled() && result.has_error()) { From 96b0c816c9928231eb956b0cc36de5713490d35c Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Wed, 19 Mar 2025 11:01:09 +0100 Subject: [PATCH 2/4] Blit is part of the device context instead of FrameBuffer --- .../InternalInclude/Babylon/Graphics/DeviceContext.h | 1 + .../InternalInclude/Babylon/Graphics/FrameBuffer.h | 1 - Core/Graphics/Source/DeviceContext.cpp | 7 +++++++ Core/Graphics/Source/FrameBuffer.cpp | 7 ------- Plugins/NativeEngine/Source/NativeEngine.cpp | 7 +++---- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h b/Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h index f0a9aeae2..cf468a979 100644 --- a/Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h +++ b/Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h @@ -121,6 +121,7 @@ namespace Babylon::Graphics TextureInfo GetTextureInfo(bgfx::TextureHandle handle); static bx::AllocatorI& GetDefaultAllocator() { return m_allocator; } + void Blit(bgfx::Encoder& encoder, bgfx::TextureHandle dst, uint16_t dstX, uint16_t dstY, bgfx::TextureHandle src, uint16_t srcX = 0, uint16_t srcY = 0, uint16_t width = UINT16_MAX, uint16_t height = UINT16_MAX); private: friend UpdateToken; diff --git a/Core/Graphics/InternalInclude/Babylon/Graphics/FrameBuffer.h b/Core/Graphics/InternalInclude/Babylon/Graphics/FrameBuffer.h index 6f9f4cda4..5e46a9a6c 100644 --- a/Core/Graphics/InternalInclude/Babylon/Graphics/FrameBuffer.h +++ b/Core/Graphics/InternalInclude/Babylon/Graphics/FrameBuffer.h @@ -41,7 +41,6 @@ namespace Babylon::Graphics void SetScissor(bgfx::Encoder& encoder, float x, float y, float width, float height); void Submit(bgfx::Encoder& encoder, bgfx::ProgramHandle programHandle, uint8_t flags); void SetStencil(bgfx::Encoder& encoder, uint32_t stencilState); - void Blit(bgfx::Encoder& encoder, bgfx::TextureHandle dst, uint16_t dstX, uint16_t dstY, bgfx::TextureHandle src, uint16_t srcX = 0, uint16_t srcY = 0, uint16_t width = UINT16_MAX, uint16_t height = UINT16_MAX); bool HasDepth() const { return m_hasDepth; } bool HasStencil() const { return m_hasStencil; } diff --git a/Core/Graphics/Source/DeviceContext.cpp b/Core/Graphics/Source/DeviceContext.cpp index 93512e0fd..9a6021380 100644 --- a/Core/Graphics/Source/DeviceContext.cpp +++ b/Core/Graphics/Source/DeviceContext.cpp @@ -129,4 +129,11 @@ namespace Babylon::Graphics { return m_graphicsImpl.GetId(); } + + void DeviceContext::Blit(bgfx::Encoder& encoder, bgfx::TextureHandle dst, uint16_t dstX, uint16_t dstY, bgfx::TextureHandle src, uint16_t srcX, uint16_t srcY, uint16_t width, uint16_t height) + { + // Increment viewId so blit happens after the last drawcall of the last viewId + auto viewId = AcquireNewViewId(encoder); + encoder.blit(viewId, dst, dstX, dstY, src, srcX, srcY, width, height); + } } diff --git a/Core/Graphics/Source/FrameBuffer.cpp b/Core/Graphics/Source/FrameBuffer.cpp index c2d150f65..168b88afc 100644 --- a/Core/Graphics/Source/FrameBuffer.cpp +++ b/Core/Graphics/Source/FrameBuffer.cpp @@ -132,13 +132,6 @@ namespace Babylon::Graphics encoder.submit(m_viewId.value(), programHandle, 0, flags); } - void FrameBuffer::Blit(bgfx::Encoder& encoder, bgfx::TextureHandle dst, uint16_t dstX, uint16_t dstY, bgfx::TextureHandle src, uint16_t srcX, uint16_t srcY, uint16_t width, uint16_t height) - { - // In order for Blit to work properly we need to force the creation of a new ViewID. - SetBgfxViewPortAndScissor(encoder, m_desiredViewPort, m_desiredScissor); - encoder.blit(m_viewId.value(), dst, dstX, dstY, src, srcX, srcY, width, height); - } - void FrameBuffer::SetStencil(bgfx::Encoder& encoder, uint32_t stencilState) { encoder.setStencil(m_hasStencil ? stencilState : 0); diff --git a/Plugins/NativeEngine/Source/NativeEngine.cpp b/Plugins/NativeEngine/Source/NativeEngine.cpp index e19beb177..3d4c5c13a 100644 --- a/Plugins/NativeEngine/Source/NativeEngine.cpp +++ b/Plugins/NativeEngine/Source/NativeEngine.cpp @@ -1431,13 +1431,12 @@ namespace Babylon { const auto textureDestination = info[0].As>().Get(); const auto textureSource = info[1].As>().Get(); - + + // Append a task instead of calling blit immediately or blit happens before drawcalls. arcana::make_task(m_update.Scheduler(), *m_cancellationSource, [this, textureDestination, textureSource, cancellationSource = m_cancellationSource]() { return arcana::make_task(m_runtimeScheduler, *m_cancellationSource, [this, textureDestination, textureSource, updateToken = m_update.GetUpdateToken(), cancellationSource = m_cancellationSource]() { bgfx::Encoder* encoder = m_update.GetUpdateToken().GetEncoder(); - auto& boundFramebuffer = GetBoundFrameBuffer(*encoder); - boundFramebuffer.Bind(*encoder); - boundFramebuffer.Blit(*encoder, textureDestination->Handle(), 0, 0, textureSource->Handle()); + m_deviceContext.Blit(*encoder, textureDestination->Handle(), 0, 0, textureSource->Handle()); }).then(arcana::inline_scheduler, *m_cancellationSource, [this, cancellationSource{m_cancellationSource}](const arcana::expected& result) { if (!cancellationSource->cancelled() && result.has_error()) { From dd3952e383adc95efb2ee53677e3f95bf7cbea2e Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Wed, 19 Mar 2025 11:51:34 +0100 Subject: [PATCH 3/4] do not wast viewId if not necessary --- .../Babylon/Graphics/DeviceContext.h | 5 +++++ Core/Graphics/Source/DeviceContext.cpp | 14 +++++++++++--- Core/Graphics/Source/FrameBuffer.cpp | 1 + 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h b/Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h index cf468a979..cd326cb21 100644 --- a/Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h +++ b/Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h @@ -121,6 +121,8 @@ namespace Babylon::Graphics TextureInfo GetTextureInfo(bgfx::TextureHandle handle); static bx::AllocatorI& GetDefaultAllocator() { return m_allocator; } + // call following method when a submit call is associated with the current acquired viewId + void SetViewAsUsed(); void Blit(bgfx::Encoder& encoder, bgfx::TextureHandle dst, uint16_t dstX, uint16_t dstY, bgfx::TextureHandle src, uint16_t srcX = 0, uint16_t srcY = 0, uint16_t width = UINT16_MAX, uint16_t height = UINT16_MAX); private: friend UpdateToken; @@ -131,5 +133,8 @@ namespace Babylon::Graphics std::mutex m_textureHandleToInfoMutex{}; static inline bx::DefaultAllocator m_allocator{}; + + bool m_currentViewIsUsed{false}; + bgfx::ViewId m_lastAcquiredViewId{bgfx::kInvalidHandle}; }; } diff --git a/Core/Graphics/Source/DeviceContext.cpp b/Core/Graphics/Source/DeviceContext.cpp index 9a6021380..f2a00dfa9 100644 --- a/Core/Graphics/Source/DeviceContext.cpp +++ b/Core/Graphics/Source/DeviceContext.cpp @@ -103,7 +103,9 @@ namespace Babylon::Graphics bgfx::ViewId DeviceContext::AcquireNewViewId(bgfx::Encoder& encoder) { - return m_graphicsImpl.AcquireNewViewId(encoder); + m_currentViewIsUsed = false; + m_lastAcquiredViewId = m_graphicsImpl.AcquireNewViewId(encoder); + return m_lastAcquiredViewId; } void DeviceContext::AddTexture(bgfx::TextureHandle handle, uint16_t width, uint16_t height, bool hasMips, uint16_t numLayers, bgfx::TextureFormat::Enum format) @@ -132,8 +134,14 @@ namespace Babylon::Graphics void DeviceContext::Blit(bgfx::Encoder& encoder, bgfx::TextureHandle dst, uint16_t dstX, uint16_t dstY, bgfx::TextureHandle src, uint16_t srcX, uint16_t srcY, uint16_t width, uint16_t height) { - // Increment viewId so blit happens after the last drawcall of the last viewId - auto viewId = AcquireNewViewId(encoder); + // Increment viewId so blit happens after the last drawcall of the last viewId if drawcall(s) have been submitted to the view. + // Otherwise, reuse last acquired viewId to not waste an Id. + auto viewId = m_currentViewIsUsed ? AcquireNewViewId(encoder) : m_lastAcquiredViewId; encoder.blit(viewId, dst, dstX, dstY, src, srcX, srcY, width, height); } + + void DeviceContext::SetViewAsUsed() + { + m_currentViewIsUsed = true; + } } diff --git a/Core/Graphics/Source/FrameBuffer.cpp b/Core/Graphics/Source/FrameBuffer.cpp index 168b88afc..835304d02 100644 --- a/Core/Graphics/Source/FrameBuffer.cpp +++ b/Core/Graphics/Source/FrameBuffer.cpp @@ -130,6 +130,7 @@ namespace Babylon::Graphics { SetBgfxViewPortAndScissor(encoder, m_desiredViewPort, m_desiredScissor); encoder.submit(m_viewId.value(), programHandle, 0, flags); + m_deviceContext.SetViewAsUsed(); } void FrameBuffer::SetStencil(bgfx::Encoder& encoder, uint32_t stencilState) From 5d307c2663dfb9e3fb57fd52077971df93a7018e Mon Sep 17 00:00:00 2001 From: Cedric Guillemet <1312968+CedricGuillemet@users.noreply.github.com> Date: Thu, 20 Mar 2025 09:51:18 +0100 Subject: [PATCH 4/4] InvalidateView --- Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h | 2 +- Core/Graphics/Source/DeviceContext.cpp | 2 +- Core/Graphics/Source/FrameBuffer.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h b/Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h index cd326cb21..7e3ac9393 100644 --- a/Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h +++ b/Core/Graphics/InternalInclude/Babylon/Graphics/DeviceContext.h @@ -122,7 +122,7 @@ namespace Babylon::Graphics static bx::AllocatorI& GetDefaultAllocator() { return m_allocator; } // call following method when a submit call is associated with the current acquired viewId - void SetViewAsUsed(); + void InvalidateView(); void Blit(bgfx::Encoder& encoder, bgfx::TextureHandle dst, uint16_t dstX, uint16_t dstY, bgfx::TextureHandle src, uint16_t srcX = 0, uint16_t srcY = 0, uint16_t width = UINT16_MAX, uint16_t height = UINT16_MAX); private: friend UpdateToken; diff --git a/Core/Graphics/Source/DeviceContext.cpp b/Core/Graphics/Source/DeviceContext.cpp index f2a00dfa9..f25e092c8 100644 --- a/Core/Graphics/Source/DeviceContext.cpp +++ b/Core/Graphics/Source/DeviceContext.cpp @@ -140,7 +140,7 @@ namespace Babylon::Graphics encoder.blit(viewId, dst, dstX, dstY, src, srcX, srcY, width, height); } - void DeviceContext::SetViewAsUsed() + void DeviceContext::InvalidateView() { m_currentViewIsUsed = true; } diff --git a/Core/Graphics/Source/FrameBuffer.cpp b/Core/Graphics/Source/FrameBuffer.cpp index 835304d02..ee0ced2c9 100644 --- a/Core/Graphics/Source/FrameBuffer.cpp +++ b/Core/Graphics/Source/FrameBuffer.cpp @@ -112,6 +112,7 @@ namespace Babylon::Graphics m_bgfxScissor = {}; encoder.touch(m_viewId.value()); + m_deviceContext.InvalidateView(); } void FrameBuffer::SetViewPort(bgfx::Encoder& encoder, float x, float y, float width, float height) @@ -130,7 +131,7 @@ namespace Babylon::Graphics { SetBgfxViewPortAndScissor(encoder, m_desiredViewPort, m_desiredScissor); encoder.submit(m_viewId.value(), programHandle, 0, flags); - m_deviceContext.SetViewAsUsed(); + m_deviceContext.InvalidateView(); } void FrameBuffer::SetStencil(bgfx::Encoder& encoder, uint32_t stencilState)