Skip to content

Commit db75d2e

Browse files
bkaradzicCopilot
authored andcommitted
NativeEngine: MultiRenderTarget framebuffers + OIT alpha blend modes
Foundational native-engine support for MultiRenderTarget (MRT) and the order- independent-transparency blend modes, removing several "engine._gl is null" crash classes. It does not by itself land the MRT/OIT/FrameGraph validation tests, which need further work (see follow-ups below). - Add NativeEngine::CreateMultiFrameBuffer: build one bgfx framebuffer with N color attachments (+ optional depth) so a MultiRenderTarget renders to all targets at once (bgfx writes every attachment of the bound framebuffer, so no drawBuffers is needed). JS-controlled attachment count is validated against caps->limits.maxFBAttachments. - Add alpha blend modes ALPHA_ONEONE_ONEONE (11) and ALPHA_LAYER_ACCUMULATE (17) used by the depth-peeling OIT renderer. Pairs with the Babylon.js change (createMultipleRenderTarget + MRT helper overrides, applyStates, reverse-Z clear). Known follow-ups: the OIT depth- peeling path still faults inside the D3D11 driver on submit (needs interactive GPU debugging), and the blend equation (MAX) is not yet applied natively. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 158e2ef commit db75d2e

2 files changed

Lines changed: 66 additions & 0 deletions

File tree

Plugins/NativeEngine/Source/NativeEngine.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ namespace Babylon
7777
constexpr uint64_t MULTIPLY = BGFX_STATE_BLEND_FUNC_SEPARATE(BGFX_STATE_BLEND_DST_COLOR, BGFX_STATE_BLEND_ZERO, BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE);
7878
constexpr uint64_t MAXIMIZED = BGFX_STATE_BLEND_FUNC_SEPARATE(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_COLOR, BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE);
7979
constexpr uint64_t ONEONE = BGFX_STATE_BLEND_FUNC_SEPARATE(BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ZERO, BGFX_STATE_BLEND_ONE);
80+
constexpr uint64_t ONEONE_ONEONE = BGFX_STATE_BLEND_FUNC_SEPARATE(BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE);
81+
constexpr uint64_t LAYER_ACCUMULATE = BGFX_STATE_BLEND_FUNC_SEPARATE(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA, BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_INV_SRC_ALPHA);
8082
constexpr uint64_t PREMULTIPLIED = BGFX_STATE_BLEND_FUNC_SEPARATE(BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_INV_SRC_ALPHA, BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE);
8183
constexpr uint64_t PREMULTIPLIED_PORTERDUFF = BGFX_STATE_BLEND_FUNC_SEPARATE(BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_INV_SRC_ALPHA, BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_INV_SRC_ALPHA);
8284
constexpr uint64_t INTERPOLATE = BGFX_STATE_BLEND_FUNC_SEPARATE(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_FACTOR, BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_FACTOR);
@@ -598,6 +600,8 @@ namespace Babylon
598600
StaticValue("ALPHA_MULTIPLY", Napi::Number::From(env, AlphaMode::MULTIPLY)),
599601
StaticValue("ALPHA_MAXIMIZED", Napi::Number::From(env, AlphaMode::MAXIMIZED)),
600602
StaticValue("ALPHA_ONEONE", Napi::Number::From(env, AlphaMode::ONEONE)),
603+
StaticValue("ALPHA_ONEONE_ONEONE", Napi::Number::From(env, AlphaMode::ONEONE_ONEONE)),
604+
StaticValue("ALPHA_LAYER_ACCUMULATE", Napi::Number::From(env, AlphaMode::LAYER_ACCUMULATE)),
601605
StaticValue("ALPHA_PREMULTIPLIED", Napi::Number::From(env, AlphaMode::PREMULTIPLIED)),
602606
StaticValue("ALPHA_PREMULTIPLIED_PORTERDUFF", Napi::Number::From(env, AlphaMode::PREMULTIPLIED_PORTERDUFF)),
603607
StaticValue("ALPHA_INTERPOLATE", Napi::Number::From(env, AlphaMode::INTERPOLATE)),
@@ -726,6 +730,7 @@ namespace Babylon
726730
InstanceMethod("resizeImageBitmap", &NativeEngine::ResizeImageBitmap),
727731

728732
InstanceMethod("createFrameBuffer", &NativeEngine::CreateFrameBuffer),
733+
InstanceMethod("createMultiFrameBuffer", &NativeEngine::CreateMultiFrameBuffer),
729734

730735
InstanceMethod("getRenderWidth", &NativeEngine::GetRenderWidth),
731736
InstanceMethod("getRenderHeight", &NativeEngine::GetRenderHeight),
@@ -1912,6 +1917,66 @@ namespace Babylon
19121917
return Napi::Pointer<Graphics::FrameBuffer>::Create(info.Env(), frameBuffer, Napi::NapiPointerDeleter(frameBuffer));
19131918
}
19141919

1920+
Napi::Value NativeEngine::CreateMultiFrameBuffer(const Napi::CallbackInfo& info)
1921+
{
1922+
const auto colorTextures = info[0].As<Napi::Array>();
1923+
const uint16_t width = static_cast<uint16_t>(info[1].As<Napi::Number>().Uint32Value());
1924+
const uint16_t height = static_cast<uint16_t>(info[2].As<Napi::Number>().Uint32Value());
1925+
const bool generateStencilBuffer = info[3].As<Napi::Boolean>();
1926+
const bool generateDepth = info[4].As<Napi::Boolean>();
1927+
const uint32_t samples = info[5].IsUndefined() ? 1 : info[5].As<Napi::Number>().Uint32Value();
1928+
1929+
const bgfx::Caps* caps = bgfx::getCaps();
1930+
const uint32_t colorCount = colorTextures.Length();
1931+
// One slot per color attachment plus a single depth/stencil attachment. bgfx caps the total via
1932+
// maxFBAttachments; reject out-of-range counts up front rather than relying on the validation assert.
1933+
if (colorCount == 0 || colorCount + 1 > caps->limits.maxFBAttachments)
1934+
{
1935+
throw Napi::Error::New(info.Env(), "Invalid number of color attachments for multi render target frame buffer");
1936+
}
1937+
1938+
// BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS is 8, so 8 color + 1 depth fits in a fixed array.
1939+
std::array<bgfx::Attachment, 9> attachments{};
1940+
uint8_t numAttachments = 0;
1941+
1942+
for (uint32_t i = 0; i < colorCount; ++i)
1943+
{
1944+
const auto texture = colorTextures.Get(i).As<Napi::Pointer<Graphics::Texture>>().Get();
1945+
attachments[numAttachments++].init(texture->Handle(), bgfx::Access::Write, 0, 1, 0
1946+
, 0 != (caps->formats[texture->Format()] & BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN) ? BGFX_RESOLVE_AUTO_GEN_MIPS : BGFX_RESOLVE_NONE
1947+
);
1948+
}
1949+
1950+
bgfx::TextureHandle depthStencilTextureHandle = BGFX_INVALID_HANDLE;
1951+
int8_t depthStencilAttachmentIndex = -1;
1952+
if (generateStencilBuffer || generateDepth)
1953+
{
1954+
auto flags = BGFX_TEXTURE_RT_WRITE_ONLY | RenderTargetSamplesToBgfxMsaaFlag(samples);
1955+
#ifdef ANDROID
1956+
const auto depthStencilFormat{bgfx::TextureFormat::D24S8};
1957+
#else
1958+
const auto depthStencilFormat{generateStencilBuffer ? bgfx::TextureFormat::D24S8 : bgfx::TextureFormat::D32};
1959+
#endif
1960+
depthStencilTextureHandle = bgfx::createTexture2D(width, height, false, 1, depthStencilFormat, flags);
1961+
depthStencilAttachmentIndex = numAttachments;
1962+
attachments[numAttachments++].init(depthStencilTextureHandle, bgfx::Access::Write, 0, 1, 0, BGFX_RESOLVE_NONE);
1963+
}
1964+
1965+
bgfx::FrameBufferHandle frameBufferHandle = bgfx::createFrameBuffer(numAttachments, attachments.data());
1966+
if (!bgfx::isValid(frameBufferHandle))
1967+
{
1968+
if (bgfx::isValid(depthStencilTextureHandle))
1969+
{
1970+
bgfx::destroy(depthStencilTextureHandle);
1971+
}
1972+
1973+
throw Napi::Error::New(info.Env(), "Failed to create multi render target frame buffer");
1974+
}
1975+
1976+
Graphics::FrameBuffer* frameBuffer = new Graphics::FrameBuffer(m_deviceContext, frameBufferHandle, width, height, false, generateDepth, generateStencilBuffer, depthStencilAttachmentIndex);
1977+
return Napi::Pointer<Graphics::FrameBuffer>::Create(info.Env(), frameBuffer, Napi::NapiPointerDeleter(frameBuffer));
1978+
}
1979+
19151980
// TODO: This doesn't get called when an Engine instance is disposed.
19161981
void NativeEngine::DeleteFrameBuffer(NativeDataStream::Reader& data)
19171982
{

Plugins/NativeEngine/Source/NativeEngine.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ namespace Babylon
115115
void DeleteTexture(const Napi::CallbackInfo& info);
116116
Napi::Value ReadTexture(const Napi::CallbackInfo& info);
117117
Napi::Value CreateFrameBuffer(const Napi::CallbackInfo& info);
118+
Napi::Value CreateMultiFrameBuffer(const Napi::CallbackInfo& info);
118119
void DeleteFrameBuffer(NativeDataStream::Reader& data);
119120
void BindFrameBuffer(NativeDataStream::Reader& data);
120121
void UnbindFrameBuffer(NativeDataStream::Reader& data);

0 commit comments

Comments
 (0)