Skip to content

Commit

Permalink
Basic support of MSAA for render targets (#1261)
Browse files Browse the repository at this point in the history
This is the native counter part to
BabylonJS/Babylon.js#14055.
  • Loading branch information
bghgary authored Jul 31, 2023
1 parent 88d09c8 commit b79e530
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 4 deletions.
17 changes: 17 additions & 0 deletions Plugins/ExternalTexture/Source/ExternalTexture_Base.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,23 @@ namespace Babylon::Plugins
return mipLevel == static_cast<uint16_t>(std::floor(std::log2(std::max(static_cast<float>(width), static_cast<float>(height))) + 1));
}

static auto RenderTargetSamplesToBgfxMsaaFlag(uint32_t renderTargetSamples)
{
switch (renderTargetSamples)
{
case 2:
return BGFX_TEXTURE_RT_MSAA_X2;
case 4:
return BGFX_TEXTURE_RT_MSAA_X4;
case 8:
return BGFX_TEXTURE_RT_MSAA_X8;
case 16:
return BGFX_TEXTURE_RT_MSAA_X16;
}

return BGFX_TEXTURE_NONE;
}

void UpdateHandles(uintptr_t ptr)
{
std::scoped_lock lock{m_mutex};
Expand Down
5 changes: 5 additions & 0 deletions Plugins/ExternalTexture/Source/ExternalTexture_D3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ namespace Babylon::Plugins
if ((desc.BindFlags & D3D11_BIND_RENDER_TARGET) != 0)
{
info.Flags |= BGFX_TEXTURE_RT;

if (desc.SampleDesc.Count > 1)
{
info.Flags |= BGFX_TEXTURE_MSAA_SAMPLE | RenderTargetSamplesToBgfxMsaaFlag(desc.SampleDesc.Count);
}
}

for (int i = 0; i < BX_COUNTOF(s_textureFormat); ++i)
Expand Down
5 changes: 5 additions & 0 deletions Plugins/ExternalTexture/Source/ExternalTexture_D3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@ namespace Babylon::Plugins
if ((desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) != 0)
{
info.Flags |= BGFX_TEXTURE_RT;

if (desc.SampleDesc.Count > 1)
{
info.Flags |= BGFX_TEXTURE_MSAA_SAMPLE | RenderTargetSamplesToBgfxMsaaFlag(desc.SampleDesc.Count);
}
}

for (int i = 0; i < BX_COUNTOF(s_textureFormat); ++i)
Expand Down
7 changes: 6 additions & 1 deletion Plugins/ExternalTexture/Source/ExternalTexture_Metal.mm
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ uintptr_t Ptr() const
private:
void GetInfo(Graphics::TextureT ptr, Info& info)
{
if (ptr.textureType != MTLTextureType2D)
if (ptr.textureType != MTLTextureType2D && ptr.textureType != MTLTextureType2DMultisample)
{
throw std::runtime_error{"Unsupported texture type"};
}
Expand All @@ -148,6 +148,11 @@ void GetInfo(Graphics::TextureT ptr, Info& info)
if ((ptr.usage & MTLTextureUsageRenderTarget) != 0)
{
info.Flags |= BGFX_TEXTURE_RT;

if (ptr.sampleCount > 1)
{
info.Flags |= BGFX_TEXTURE_MSAA_SAMPLE | RenderTargetSamplesToBgfxMsaaFlag(ptr.sampleCount);
}
}

const auto pixelFormat = m_ptr.pixelFormat;
Expand Down
34 changes: 31 additions & 3 deletions Plugins/NativeEngine/Source/NativeEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,23 @@ namespace Babylon
}
}

auto RenderTargetSamplesToBgfxMsaaFlag(uint32_t renderTargetSamples)
{
switch (renderTargetSamples)
{
case 2:
return BGFX_TEXTURE_RT_MSAA_X2;
case 4:
return BGFX_TEXTURE_RT_MSAA_X4;
case 8:
return BGFX_TEXTURE_RT_MSAA_X8;
case 16:
return BGFX_TEXTURE_RT_MSAA_X16;
}

return BGFX_TEXTURE_NONE;
}

using CommandFunctionPointerT = void (NativeEngine::*)(NativeDataStream::Reader&);
}

Expand Down Expand Up @@ -1085,11 +1102,17 @@ namespace Babylon
const bgfx::TextureFormat::Enum format = static_cast<bgfx::TextureFormat::Enum>(info[4].As<Napi::Number>().Uint32Value());
const bool renderTarget = info[5].As<Napi::Boolean>();
const bool srgb = info[6].As<Napi::Boolean>();
const uint32_t samples = info[7].IsUndefined() ? 1 : info[7].As<Napi::Number>().Uint32Value();

auto flags = BGFX_TEXTURE_NONE;
if (renderTarget)
{
flags |= BGFX_TEXTURE_RT;

if (samples > 1)
{
flags |= BGFX_TEXTURE_MSAA_SAMPLE | RenderTargetSamplesToBgfxMsaaFlag(samples);
}
}
if (srgb)
{
Expand Down Expand Up @@ -1517,6 +1540,7 @@ namespace Babylon
const uint16_t height = static_cast<uint16_t>(info[2].As<Napi::Number>().Uint32Value());
const bool generateStencilBuffer = info[3].As<Napi::Boolean>();
const bool generateDepth = info[4].As<Napi::Boolean>();
const uint32_t samples = info[5].IsUndefined() ? 1 : info[5].As<Napi::Number>().Uint32Value();

std::array<bgfx::Attachment, 2> attachments{};
uint8_t numAttachments = 0;
Expand All @@ -1534,18 +1558,22 @@ namespace Babylon
JsConsoleLogger::LogWarn(info.Env(), "Stencil without depth is not supported, assuming depth and stencil");
}

auto flags = BGFX_TEXTURE_RT_WRITE_ONLY | RenderTargetSamplesToBgfxMsaaFlag(samples);
const auto depthStencilFormat{generateStencilBuffer ? bgfx::TextureFormat::D24S8 : bgfx::TextureFormat::D32};
assert(bgfx::isTextureValid(0, false, 1, depthStencilFormat, BGFX_TEXTURE_RT));
assert(bgfx::isTextureValid(0, false, 1, depthStencilFormat, 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.
// only allows mipmaps resolve step when mipmapping is asked and for the color texture, not the depth.
// https://github.com/bkaradzic/bgfx/blob/2c21f68998595fa388e25cb6527e82254d0e9bff/src/renderer_d3d11.cpp#L4525
attachments[numAttachments++].init(bgfx::createTexture2D(width, height, false, 1, depthStencilFormat, BGFX_TEXTURE_RT));
attachments[numAttachments++].init(bgfx::createTexture2D(width, height, false, 1, depthStencilFormat, flags));
}

bgfx::FrameBufferHandle frameBufferHandle = bgfx::createFrameBuffer(numAttachments, attachments.data(), true);
assert(bgfx::isValid(frameBufferHandle));
if (!bgfx::isValid(frameBufferHandle))
{
throw Napi::Error::New(info.Env(), "Failed to create frame buffer");
}

Graphics::FrameBuffer* frameBuffer = new Graphics::FrameBuffer(m_graphicsContext, frameBufferHandle, width, height, false, generateDepth, generateStencilBuffer);
return Napi::Pointer<Graphics::FrameBuffer>::Create(info.Env(), frameBuffer, Napi::NapiPointerDeleter(frameBuffer));
Expand Down

0 comments on commit b79e530

Please sign in to comment.