Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions Apps/Playground/Scripts/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2274,14 +2274,12 @@
},
{
"title": "Load GUI snippet with unicode",
"playgroundId": "#YS93KY#0",
"renderCount": 50,
"playgroundId": "#YS93KY#1",
"referenceImage": "loadGuiSnippetWithUnicode.png"
},
{
"title": "Parse GUI json with unicode",
"playgroundId": "#ERVGT5#0",
"renderCount": 50,
"playgroundId": "#ERVGT5#1",
"referenceImage": "parseGuiJsonWithUnicode.png"
},
{
Expand Down
6 changes: 6 additions & 0 deletions Core/Graphics/InternalInclude/Babylon/Graphics/Texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ namespace Babylon::Graphics
uint16_t ViewNumLayers() const;
void ViewNumLayers(uint16_t);

// View id reserved (by the Canvas polyfill) for the canvas->texture blit that fills
// this texture. UINT16_MAX means "unset"; consumers fall back to a freshly peeked view.
bgfx::ViewId BlitViewId() const { return m_blitViewId; }
void BlitViewId(bgfx::ViewId viewId) { m_blitViewId = viewId; }

private:
bgfx::TextureHandle m_handle{bgfx::kInvalidHandle};
bool m_ownsHandle{false};
Expand All @@ -56,6 +61,7 @@ namespace Babylon::Graphics
uint32_t m_samplerFlags{BGFX_SAMPLER_NONE};
uint16_t m_viewFirstLayer{0};
uint16_t m_viewNumLayers{0};
bgfx::ViewId m_blitViewId{UINT16_MAX};
uintptr_t m_deviceID;
DeviceContext& m_deviceContext;
};
Expand Down
16 changes: 12 additions & 4 deletions Plugins/NativeEngine/Source/NativeEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1409,10 +1409,18 @@ namespace Babylon
const auto textureSource = data.ReadPointer<Graphics::Texture>();
const auto textureDestination = data.ReadPointer<Graphics::Texture>();

// Use a view id greater than every view used so far so the blit runs after
// all canvas Flushes that may have produced the source content (bgfx
// processes blits in numeric view-id order). See #1683.
const bgfx::ViewId blitView = m_deviceContext.PeekNextViewId();
// The canvas->texture blit must run AFTER the canvas Flush that produced the source
// (bgfx processes blits in numeric view-id order) yet BEFORE the scene/backbuffer view
// that samples the destination, otherwise the consumer (e.g. a fullscreen GUI ADT layer)
// samples the previous frame's content — a one-frame latency. Context::Flush reserves a
// view id immediately after the canvas draws (before the scene render is recorded) and
// hands it to the source texture; use it here. Non-canvas sources have no reserved id, so
// fall back to PeekNextViewId() (a view greater than every view used so far). See #1683.
bgfx::ViewId blitView = textureSource->BlitViewId();
if (blitView == UINT16_MAX)
{
blitView = m_deviceContext.PeekNextViewId();
}
encoder->blit(blitView, textureDestination->Handle(), 0, 0, textureSource->Handle());
}

Expand Down
3 changes: 3 additions & 0 deletions Polyfills/Canvas/Source/Canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ namespace Babylon::Polyfills::Internal
}

m_texture->Attach(bgfx::getTexture(m_frameBuffer->Handle()), false, m_width, m_height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT);
// Hand the blit view id reserved during the preceding Context::Flush to the texture so
// NativeEngine::CopyTexture blits on a view ordered before the consuming layer.
m_texture->BlitViewId(m_blitViewId);
return Napi::Pointer<Graphics::Texture>::Create(info.Env(), m_texture.get());
}

Expand Down
5 changes: 5 additions & 0 deletions Polyfills/Canvas/Source/Canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ namespace Babylon::Polyfills::Internal
Babylon::Graphics::FrameBuffer& GetFrameBuffer() { return *m_frameBuffer; }
FrameBufferPool m_frameBufferPool;

// View id reserved by Context::Flush (right after this canvas' draws) for the
// canvas->texture blit issued from NativeEngine::CopyTexture. See Context::Flush.
void SetBlitViewId(bgfx::ViewId viewId) { m_blitViewId = viewId; }

Graphics::DeviceContext& GetGraphicsContext()
{
return m_graphicsContext;
Expand Down Expand Up @@ -99,6 +103,7 @@ namespace Babylon::Polyfills::Internal

std::unique_ptr<Graphics::FrameBuffer> m_frameBuffer;
std::unique_ptr<Graphics::Texture> m_texture{};
bgfx::ViewId m_blitViewId{UINT16_MAX};
bool m_dirty{};
bool m_clear{};

Expand Down
9 changes: 9 additions & 0 deletions Polyfills/Canvas/Source/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,15 @@ namespace Babylon::Polyfills::Internal
nvgEndFrame(*m_nvg);
frameBuffer.Unbind();

// Reserve the view id for the eventual canvas->texture blit NOW, while we are
// sequenced immediately after this canvas' draws but before the scene/backbuffer
// render is recorded. bgfx processes blits in numeric view-id order, so the copy
// must land AFTER the canvas Flush (source ready) yet BEFORE the fullscreen ADT
// layer samples the destination texture. Deferring to CopyTexture's
// PeekNextViewId() would place the blit after the backbuffer view, so the layer
// would sample the previous frame's content (a one-frame GUI latency).
m_canvas->SetBlitViewId(m_graphicsContext.AcquireNewViewId());

for (auto& buffer : m_canvas->m_frameBufferPool.GetPoolBuffers())
{
// sanity check no unreleased buffers
Expand Down