Skip to content

Commit 73adf6f

Browse files
NativeEngine: support standalone sampleable depth/stencil textures
Babylon's NativeEngine._createDepthStencilTexture requests a standalone, sampleable depth/stencil texture by calling createFrameBuffer with a freshly-created (and therefore uninitialized) color texture whose bgfx handle is still kInvalidHandle. CreateFrameBuffer only guarded against a null texture, so it attached the invalid handle as a color target. bgfx framebuffer validation then rejected the attachment ("Invalid texture attachment") and threw, aborting the entire headless Playground sweep. Detect this request (non-null texture with an invalid bgfx handle) and: - skip attaching the invalid color handle (depth-only framebuffer), - allocate the depth attachment as a readable BGFX_TEXTURE_RT so it can be sampled, and - alias the framebuffer's depth attachment back into the caller-supplied texture (ownsHandle=false; the framebuffer owns the handle) so Babylon can sample it (e.g. fluid rendering's depth copy). This removes the whole-sweep abort and makes the depth/stencil texture sampleable per Babylon's contract. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ff9d4db commit 73adf6f

1 file changed

Lines changed: 24 additions & 2 deletions

File tree

Plugins/NativeEngine/Source/NativeEngine.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,7 +1814,13 @@ namespace Babylon
18141814
std::array<bgfx::Attachment, 2> attachments{};
18151815
uint8_t numAttachments = 0;
18161816

1817-
if (texture != nullptr)
1817+
// Babylon's NativeEngine._createDepthStencilTexture asks for a standalone, *sampleable* depth/stencil
1818+
// texture by passing a freshly created (and therefore uninitialized) color texture: its bgfx handle is
1819+
// still kInvalidHandle. Detect that here so we (a) don't attach the invalid handle as a color target and
1820+
// (b) create a readable depth attachment and alias it back into the supplied texture so it can be sampled.
1821+
const bool requestDepthStencilTexture = (texture != nullptr && !bgfx::isValid(texture->Handle()));
1822+
1823+
if (texture != nullptr && bgfx::isValid(texture->Handle()))
18181824
{
18191825
const bgfx::Caps* caps = bgfx::getCaps();
18201826
// bgfx validation now asserts when trying to use BGFX_RESOLVE_AUTO_GEN_MIPS with a texture that doesn't have the BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN flag,
@@ -1827,14 +1833,18 @@ namespace Babylon
18271833

18281834
bgfx::TextureHandle depthStencilTextureHandle = BGFX_INVALID_HANDLE;
18291835
int8_t depthStencilAttachmentIndex = -1;
1836+
bgfx::TextureFormat::Enum depthStencilTextureFormat = bgfx::TextureFormat::Unknown;
1837+
uint64_t depthStencilTextureFlags = 0;
18301838
if (generateStencilBuffer || generateDepth)
18311839
{
18321840
if (generateStencilBuffer && !generateDepth)
18331841
{
18341842
JsConsoleLogger::LogWarn(info.Env(), "Stencil without depth is not supported, assuming depth and stencil");
18351843
}
18361844

1837-
auto flags = BGFX_TEXTURE_RT_WRITE_ONLY | RenderTargetSamplesToBgfxMsaaFlag(samples);
1845+
// A standalone depth/stencil texture must be readable; render-target-only depth attachments stay
1846+
// write-only (cheaper, and the resolve path below relies on it).
1847+
auto flags = (requestDepthStencilTexture ? BGFX_TEXTURE_RT : BGFX_TEXTURE_RT_WRITE_ONLY) | RenderTargetSamplesToBgfxMsaaFlag(samples);
18381848
#ifdef ANDROID
18391849
// On Android with Mali GPU (Oppo Find x5 lite, Google Pixel 8, Samsung Galaxy Tab Active 3, ...)
18401850
// D32 depth buffer gives glitches. Everything is fine with D24S8.
@@ -1846,6 +1856,8 @@ namespace Babylon
18461856
#endif
18471857
assert(bgfx::isTextureValid(0, false, 1, depthStencilFormat, flags));
18481858
depthStencilTextureHandle = bgfx::createTexture2D(width, height, false, 1, depthStencilFormat, flags);
1859+
depthStencilTextureFormat = depthStencilFormat;
1860+
depthStencilTextureFlags = flags;
18491861

18501862
// bgfx doesn't add flag D3D11_RESOURCE_MISC_GENERATE_MIPS for depth textures (missing that flag will crash D3D with resolving)
18511863
// And not sure it makes sense to generate mipmaps from a depth buffer with exponential values.
@@ -1867,6 +1879,16 @@ namespace Babylon
18671879
}
18681880

18691881
Graphics::FrameBuffer* frameBuffer = new Graphics::FrameBuffer(m_deviceContext, frameBufferHandle, width, height, false, generateDepth, generateStencilBuffer, depthStencilAttachmentIndex);
1882+
1883+
// For a standalone depth/stencil texture request, alias the framebuffer's readable depth attachment back
1884+
// into the caller-supplied texture so Babylon can sample it (e.g. fluid rendering's depth copy). The
1885+
// framebuffer owns the handle (its destructor destroys it), so the texture must not own it.
1886+
if (requestDepthStencilTexture && depthStencilAttachmentIndex >= 0)
1887+
{
1888+
texture->Attach(bgfx::getTexture(frameBufferHandle, static_cast<uint8_t>(depthStencilAttachmentIndex)),
1889+
false, width, height, false, 1, depthStencilTextureFormat, depthStencilTextureFlags);
1890+
}
1891+
18701892
return Napi::Pointer<Graphics::FrameBuffer>::Create(info.Env(), frameBuffer, Napi::NapiPointerDeleter(frameBuffer));
18711893
}
18721894

0 commit comments

Comments
 (0)