Skip to content
Draft
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
32 changes: 29 additions & 3 deletions Plugins/NativeEngine/Source/NativeEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1856,7 +1856,13 @@ namespace Babylon
std::array<bgfx::Attachment, 2> attachments{};
uint8_t numAttachments = 0;

if (texture != nullptr)
// Babylon's NativeEngine._createDepthStencilTexture asks for a standalone, *sampleable* depth/stencil
// texture by passing a freshly created (and therefore uninitialized) color texture: its bgfx handle is
// still kInvalidHandle. Detect that here so we (a) don't attach the invalid handle as a color target and
// (b) create a readable depth attachment and alias it back into the supplied texture so it can be sampled.
const bool requestDepthStencilTexture = (texture != nullptr && !bgfx::isValid(texture->Handle()));

if (texture != nullptr && bgfx::isValid(texture->Handle()))
{
const bgfx::Caps* caps = bgfx::getCaps();
// 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,
Expand All @@ -1869,14 +1875,18 @@ namespace Babylon

bgfx::TextureHandle depthStencilTextureHandle = BGFX_INVALID_HANDLE;
int8_t depthStencilAttachmentIndex = -1;
bgfx::TextureFormat::Enum depthStencilTextureFormat = bgfx::TextureFormat::Unknown;
uint64_t depthStencilTextureFlags = 0;
if (generateStencilBuffer || generateDepth)
{
if (generateStencilBuffer && !generateDepth)
{
JsConsoleLogger::LogWarn(info.Env(), "Stencil without depth is not supported, assuming depth and stencil");
}

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

// bgfx doesn't add flag D3D11_RESOURCE_MISC_GENERATE_MIPS for depth textures (missing that flag will crash D3D with resolving)
// And not sure it makes sense to generate mipmaps from a depth buffer with exponential values.
Expand All @@ -1908,7 +1920,21 @@ namespace Babylon
throw Napi::Error::New(info.Env(), "Failed to create frame buffer");
}

Graphics::FrameBuffer* frameBuffer = new Graphics::FrameBuffer(m_deviceContext, frameBufferHandle, width, height, false, generateDepth, generateStencilBuffer, depthStencilAttachmentIndex);
// Stencil-without-depth still allocates a combined depth/stencil attachment above, so the framebuffer
// genuinely has depth in that case too. Report hasDepth accordingly, otherwise Clear/DrawInternal would
// skip depth clear and Z-writes against a depth buffer that actually exists.
const bool hasDepthAttachment = generateDepth || generateStencilBuffer;
Graphics::FrameBuffer* frameBuffer = new Graphics::FrameBuffer(m_deviceContext, frameBufferHandle, width, height, false, hasDepthAttachment, generateStencilBuffer, depthStencilAttachmentIndex);

// For a standalone depth/stencil texture request, alias the framebuffer's readable depth attachment back
// into the caller-supplied texture so Babylon can sample it (e.g. fluid rendering's depth copy). The
// framebuffer owns the handle (its destructor destroys it), so the texture must not own it.
if (requestDepthStencilTexture && depthStencilAttachmentIndex >= 0)
{
texture->Attach(bgfx::getTexture(frameBufferHandle, static_cast<uint8_t>(depthStencilAttachmentIndex)),
false, width, height, false, 1, depthStencilTextureFormat, depthStencilTextureFlags);
}

return Napi::Pointer<Graphics::FrameBuffer>::Create(info.Env(), frameBuffer, Napi::NapiPointerDeleter(frameBuffer));
}

Expand Down