From 8b8050788c516a1bbaf739cdc456a4e858d393c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Tue, 20 Oct 2026 20:35:15 -0700 Subject: [PATCH] Added per-format MSAA sample count caps, and clamp MSAA requests per format. Closes #1396. (#4072) --- bindings/bf/bgfx.bf | 20 ++++++++ bindings/c3/bgfx.c3 | 12 +++++ bindings/cs/bgfx.cs | 20 ++++++++ bindings/d/package.d | 44 +++++++++-------- .../java/io/github/bkaradzic/bgfx/Bgfx.java | 24 +++++++++- bindings/py/bgfx.py | 4 ++ bindings/py/bgfx.pyi | 8 ++++ bindings/zig/bgfx.zig | 12 +++++ include/bgfx/bgfx.h | 3 ++ include/bgfx/defines.h | 6 ++- scripts/bgfx.idl | 6 ++- src/bgfx.cpp | 14 ++++++ src/bgfx_p.h | 39 ++++++++++++++- src/renderer_d3d11.cpp | 30 +++++++++--- src/renderer_d3d12.cpp | 48 +++++++++++++------ src/renderer_d3d12.h | 2 + src/renderer_gl.cpp | 33 ++++++++----- src/renderer_mtl.cpp | 26 ++++++++-- src/renderer_vk.cpp | 12 ++++- src/renderer_webgpu.cpp | 5 +- 20 files changed, 302 insertions(+), 66 deletions(-) diff --git a/bindings/bf/bgfx.bf b/bindings/bf/bgfx.bf index a760c220b..76eadf98d 100644 --- a/bindings/bf/bgfx.bf +++ b/bindings/bf/bgfx.bf @@ -1265,6 +1265,26 @@ public static class bgfx /// Texture format can be used as video decode destination. /// TextureVideoDecodeDst = 0x00020000, + + /// + /// Texture format can be used as MSAA frame buffer with 2 samples. + /// + TextureFramebufferMsaaX2 = 0x00040000, + + /// + /// Texture format can be used as MSAA frame buffer with 4 samples. + /// + TextureFramebufferMsaaX4 = 0x00080000, + + /// + /// Texture format can be used as MSAA frame buffer with 8 samples. + /// + TextureFramebufferMsaaX8 = 0x00100000, + + /// + /// Texture format can be used as MSAA frame buffer with 16 samples. + /// + TextureFramebufferMsaaX16 = 0x00200000, } [AllowDuplicates] diff --git a/bindings/c3/bgfx.c3 b/bindings/c3/bgfx.c3 index 78315cb91..7e306947b 100644 --- a/bindings/c3/bgfx.c3 +++ b/bindings/c3/bgfx.c3 @@ -802,6 +802,18 @@ constdef CapsFormatFlags : inline uint // Texture format can be used as video decode destination. TEXTUREVIDEODECODEDST = 0x00020000, + + // Texture format can be used as MSAA frame buffer with 2 samples. + TEXTUREFRAMEBUFFERMSAAX2 = 0x00040000, + + // Texture format can be used as MSAA frame buffer with 4 samples. + TEXTUREFRAMEBUFFERMSAAX4 = 0x00080000, + + // Texture format can be used as MSAA frame buffer with 8 samples. + TEXTUREFRAMEBUFFERMSAAX8 = 0x00100000, + + // Texture format can be used as MSAA frame buffer with 16 samples. + TEXTUREFRAMEBUFFERMSAAX16 = 0x00200000, } constdef CapsVideoCodecFlags : inline uint diff --git a/bindings/cs/bgfx.cs b/bindings/cs/bgfx.cs index a05a35bdd..2a59fb881 100644 --- a/bindings/cs/bgfx.cs +++ b/bindings/cs/bgfx.cs @@ -1264,6 +1264,26 @@ public static partial class bgfx /// Texture format can be used as video decode destination. /// TextureVideoDecodeDst = 0x00020000, + + /// + /// Texture format can be used as MSAA frame buffer with 2 samples. + /// + TextureFramebufferMsaaX2 = 0x00040000, + + /// + /// Texture format can be used as MSAA frame buffer with 4 samples. + /// + TextureFramebufferMsaaX4 = 0x00080000, + + /// + /// Texture format can be used as MSAA frame buffer with 8 samples. + /// + TextureFramebufferMsaaX8 = 0x00100000, + + /// + /// Texture format can be used as MSAA frame buffer with 16 samples. + /// + TextureFramebufferMsaaX16 = 0x00200000, } [Flags] diff --git a/bindings/d/package.d b/bindings/d/package.d index 2dcac7b7b..42cde0499 100644 --- a/bindings/d/package.d +++ b/bindings/d/package.d @@ -9,7 +9,7 @@ import bindbc.common.types: c_int64, c_uint64, va_list; import bindbc.bgfx.config; static import bgfx.impl; -enum uint apiVersion = 166; +enum uint apiVersion = 167; alias ViewID = ushort; @@ -565,25 +565,29 @@ enum CapFlags: CapFlags_{ alias CapsFormat_ = uint; enum CapsFormat: CapsFormat_{ - textureNone = 0x0000_0000, ///Texture format is not supported. - texture2D = 0x0000_0001, ///Texture format is supported. - texture2DSRGB = 0x0000_0002, ///Texture as sRGB format is supported. - texture2DEmulated = 0x0000_0004, ///Texture format is emulated. - texture3D = 0x0000_0008, ///Texture format is supported. - texture3DSRGB = 0x0000_0010, ///Texture as sRGB format is supported. - texture3DEmulated = 0x0000_0020, ///Texture format is emulated. - textureCube = 0x0000_0040, ///Texture format is supported. - textureCubeSRGB = 0x0000_0080, ///Texture as sRGB format is supported. - textureCubeEmulated = 0x0000_0100, ///Texture format is emulated. - textureVertex = 0x0000_0200, ///Texture format can be used from vertex shader. - textureImageRead = 0x0000_0400, ///Texture format can be used as image and read from. - textureImageWrite = 0x0000_0800, ///Texture format can be used as image and written to. - textureFramebuffer = 0x0000_1000, ///Texture format can be used as frame buffer. - textureFramebufferMSAA = 0x0000_2000, ///Texture format can be used as MSAA frame buffer. - textureMSAA = 0x0000_4000, ///Texture can be sampled as MSAA. - textureMIPAutogen = 0x0000_8000, ///Texture format supports auto-generated mips. - textureBackbuffer = 0x0001_0000, ///Texture format can be used as back buffer format. - textureVideoDecodeDst = 0x0002_0000, ///Texture format can be used as video decode destination. + textureNone = 0x0000_0000, ///Texture format is not supported. + texture2D = 0x0000_0001, ///Texture format is supported. + texture2DSRGB = 0x0000_0002, ///Texture as sRGB format is supported. + texture2DEmulated = 0x0000_0004, ///Texture format is emulated. + texture3D = 0x0000_0008, ///Texture format is supported. + texture3DSRGB = 0x0000_0010, ///Texture as sRGB format is supported. + texture3DEmulated = 0x0000_0020, ///Texture format is emulated. + textureCube = 0x0000_0040, ///Texture format is supported. + textureCubeSRGB = 0x0000_0080, ///Texture as sRGB format is supported. + textureCubeEmulated = 0x0000_0100, ///Texture format is emulated. + textureVertex = 0x0000_0200, ///Texture format can be used from vertex shader. + textureImageRead = 0x0000_0400, ///Texture format can be used as image and read from. + textureImageWrite = 0x0000_0800, ///Texture format can be used as image and written to. + textureFramebuffer = 0x0000_1000, ///Texture format can be used as frame buffer. + textureFramebufferMSAA = 0x0000_2000, ///Texture format can be used as MSAA frame buffer. + textureMSAA = 0x0000_4000, ///Texture can be sampled as MSAA. + textureMIPAutogen = 0x0000_8000, ///Texture format supports auto-generated mips. + textureBackbuffer = 0x0001_0000, ///Texture format can be used as back buffer format. + textureVideoDecodeDst = 0x0002_0000, ///Texture format can be used as video decode destination. + textureFramebufferMSAAX2 = 0x0004_0000, ///Texture format can be used as MSAA frame buffer with 2 samples. + textureFramebufferMSAAX4 = 0x0008_0000, ///Texture format can be used as MSAA frame buffer with 4 samples. + textureFramebufferMSAAX8 = 0x0010_0000, ///Texture format can be used as MSAA frame buffer with 8 samples. + textureFramebufferMSAAX16 = 0x0020_0000, ///Texture format can be used as MSAA frame buffer with 16 samples. } alias CapsVideoCodec_ = uint; diff --git a/bindings/java/io/github/bkaradzic/bgfx/Bgfx.java b/bindings/java/io/github/bkaradzic/bgfx/Bgfx.java index b1fdc4669..fc336d5b5 100644 --- a/bindings/java/io/github/bkaradzic/bgfx/Bgfx.java +++ b/bindings/java/io/github/bkaradzic/bgfx/Bgfx.java @@ -646,7 +646,7 @@ public final class Bgfx { * Attention: This call doesn’t change the window size, it just resizes * the back-buffer. Your windowing code controls the window size. * @param _flags See: {@code BGFX_RESET_*} for more info. - {@code BGFX_RESET_NONE} - No reset flags. - {@code BGFX_RESET_VSYNC} - Enable V-Sync. - {@code BGFX_RESET_MAXANISOTROPY} - Turn on/off max anisotropy. - {@code BGFX_RESET_CAPTURE} - Begin screen capture. - {@code BGFX_RESET_FLUSH_AFTER_RENDER} - Flush rendering after submitting to GPU. - {@code BGFX_RESET_FLIP_AFTER_RENDER} - This flag specifies where flip occurs. Default behaviour is that flip occurs before rendering new frame. This flag only has effect when {@code BGFX_CONFIG_MULTITHREADED=0}. - {@code BGFX_RESET_LOW_LATENCY_ON} - Enable low latency mode (NVIDIA Reflex). Availability depends on: {@code BGFX_CAPS_LOW_LATENCY}. - {@code BGFX_RESET_LOW_LATENCY_BOOST} - Enable low latency mode, and keep GPU clocks high even when GPU is mostly idle. Availability depends on: {@code BGFX_CAPS_LOW_LATENCY}. Set either {@code BGFX_RESET_LOW_LATENCY_ON} or {@code BGFX_RESET_LOW_LATENCY_BOOST}, not both. Per-surface settings are not here. {@code BGFX_SWAP_CHAIN_*} flags belong on {@code SwapChain.flags}, and are ignored if passed here. - * @param _swapChain Main window swap chain. When {@code NULL} the main window is left untouched and only the device and frame globals above are applied, which is what an application driving its own swap chains wants. Otherwise the main window takes on this description: resize it, change its format, or change its per-surface flags. Fields left neutral keep their current value, and {@code nwh}/{@code ndt} are ignored -- main's are bgfx's own. Must be {@code NULL} when {@code init} created no main window. + * @param _swapChain Main window swap chain. When {@code NULL} the main window is left untouched and only the device and frame globals above are applied, which is what an application driving its own swap chains wants. Otherwise the main window takes on this description: resize it, change its format, or change its per-surface flags. Fields left neutral keep their current value. A new {@code nwh} moves the main window to another native window: the renderer recreates the main swap chain for it and keeps the device, context and every GPU resource. {@code ndt} must stay what {@code init} received. Must be {@code NULL} when {@code init} created no main window. */ public static void reset(@Unsigned int _flags, @Nullable SwapChain _swapChain) { try { @@ -2435,7 +2435,7 @@ public final class Bgfx { /** * Set shader uniform parameter for frame. *

- * Attention: Uniform must be created with {@code UniformFreq.VIEW} argument. + * Attention: Uniform must be created with {@code UniformFreq.FRAME} argument. * @param _handle Uniform. * @param _value Pointer to uniform data. * @param _num Number of elements. Passing {@code UINT16_MAX} will use the _num passed on uniform creation. @@ -5063,6 +5063,26 @@ public final class Bgfx { * Texture format can be used as video decode destination. */ public static final int TextureVideoDecodeDst = 0x00020000; + + /** + * Texture format can be used as MSAA frame buffer with 2 samples. + */ + public static final int TextureFramebufferMsaaX2 = 0x00040000; + + /** + * Texture format can be used as MSAA frame buffer with 4 samples. + */ + public static final int TextureFramebufferMsaaX4 = 0x00080000; + + /** + * Texture format can be used as MSAA frame buffer with 8 samples. + */ + public static final int TextureFramebufferMsaaX8 = 0x00100000; + + /** + * Texture format can be used as MSAA frame buffer with 16 samples. + */ + public static final int TextureFramebufferMsaaX16 = 0x00200000; } /** diff --git a/bindings/py/bgfx.py b/bindings/py/bgfx.py index 29a4cce96..b63f6cd99 100644 --- a/bindings/py/bgfx.py +++ b/bindings/py/bgfx.py @@ -609,6 +609,10 @@ class CapsFormatFlags(enum.IntFlag): TextureMipAutogen = 0x8000 TextureBackbuffer = 0x10000 TextureVideoDecodeDst = 0x20000 + TextureFramebufferMsaaX2 = 0x40000 + TextureFramebufferMsaaX4 = 0x80000 + TextureFramebufferMsaaX8 = 0x100000 + TextureFramebufferMsaaX16 = 0x200000 class CapsVideoCodecFlags(enum.IntFlag): None_ = 0x0 diff --git a/bindings/py/bgfx.pyi b/bindings/py/bgfx.pyi index fff6a51e9..92d94dfd0 100644 --- a/bindings/py/bgfx.pyi +++ b/bindings/py/bgfx.pyi @@ -1126,6 +1126,14 @@ class CapsFormatFlags(enum.IntFlag): TextureBackbuffer = 0x10000 # Texture format can be used as video decode destination. TextureVideoDecodeDst = 0x20000 + # Texture format can be used as MSAA frame buffer with 2 samples. + TextureFramebufferMsaaX2 = 0x40000 + # Texture format can be used as MSAA frame buffer with 4 samples. + TextureFramebufferMsaaX4 = 0x80000 + # Texture format can be used as MSAA frame buffer with 8 samples. + TextureFramebufferMsaaX8 = 0x100000 + # Texture format can be used as MSAA frame buffer with 16 samples. + TextureFramebufferMsaaX16 = 0x200000 class CapsVideoCodecFlags(enum.IntFlag): # Video codec is not supported. diff --git a/bindings/zig/bgfx.zig b/bindings/zig/bgfx.zig index d64af30c3..bbedc9a11 100644 --- a/bindings/zig/bgfx.zig +++ b/bindings/zig/bgfx.zig @@ -781,6 +781,18 @@ pub const CapsFormatFlags_TextureBackbuffer: CapsFormatFlags = 0x00010000; /// Texture format can be used as video decode destination. pub const CapsFormatFlags_TextureVideoDecodeDst: CapsFormatFlags = 0x00020000; +/// Texture format can be used as MSAA frame buffer with 2 samples. +pub const CapsFormatFlags_TextureFramebufferMsaaX2: CapsFormatFlags = 0x00040000; + +/// Texture format can be used as MSAA frame buffer with 4 samples. +pub const CapsFormatFlags_TextureFramebufferMsaaX4: CapsFormatFlags = 0x00080000; + +/// Texture format can be used as MSAA frame buffer with 8 samples. +pub const CapsFormatFlags_TextureFramebufferMsaaX8: CapsFormatFlags = 0x00100000; + +/// Texture format can be used as MSAA frame buffer with 16 samples. +pub const CapsFormatFlags_TextureFramebufferMsaaX16: CapsFormatFlags = 0x00200000; + pub const CapsVideoCodecFlags = u32; /// Video codec is not supported. pub const CapsVideoCodecFlags_None: CapsVideoCodecFlags = 0x00000000; diff --git a/include/bgfx/bgfx.h b/include/bgfx/bgfx.h index 3f9df6e18..6b2b91ca3 100644 --- a/include/bgfx/bgfx.h +++ b/include/bgfx/bgfx.h @@ -677,6 +677,9 @@ namespace bgfx /// - `BGFX_CAPS_FORMAT_TEXTURE_BACKBUFFER` - Texture format can be used as back buffer format. /// - `BGFX_CAPS_FORMAT_TEXTURE_VIDEO_DECODE_DST` - Texture format can be used as video /// decode destination. + /// - `BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X2`, `_X4`, `_X8`, `_X16` - Texture + /// format can be used as MSAA frame buffer with that many samples. A + /// `BGFX_TEXTURE_RT_MSAA_X*` request is clamped to the highest one set. uint32_t codecs[VideoCodec::Count]; //!< Supported video codec capabilities flags. A non-zero entry means the codec is /// supported for hardware decode; bits describe sample depths and chroma /// subsamplings: diff --git a/include/bgfx/defines.h b/include/bgfx/defines.h index 4a9d70902..f9b23e86e 100644 --- a/include/bgfx/defines.h +++ b/include/bgfx/defines.h @@ -15,7 +15,7 @@ #ifndef BGFX_DEFINES_H_HEADER_GUARD #define BGFX_DEFINES_H_HEADER_GUARD -#define BGFX_API_VERSION UINT32_C(166) +#define BGFX_API_VERSION UINT32_C(167) /** * Color RGB/alpha/depth write. When it's not specified write will be disabled. @@ -524,6 +524,10 @@ #define BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN UINT32_C(0x00008000) //!< Texture format supports auto-generated mips. #define BGFX_CAPS_FORMAT_TEXTURE_BACKBUFFER UINT32_C(0x00010000) //!< Texture format can be used as back buffer format. #define BGFX_CAPS_FORMAT_TEXTURE_VIDEO_DECODE_DST UINT32_C(0x00020000) //!< Texture format can be used as video decode destination. +#define BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X2 UINT32_C(0x00040000) //!< Texture format can be used as MSAA frame buffer with 2 samples. +#define BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X4 UINT32_C(0x00080000) //!< Texture format can be used as MSAA frame buffer with 4 samples. +#define BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X8 UINT32_C(0x00100000) //!< Texture format can be used as MSAA frame buffer with 8 samples. +#define BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X16 UINT32_C(0x00200000) //!< Texture format can be used as MSAA frame buffer with 16 samples. #define BGFX_CAPS_VIDEO_CODEC_NONE UINT32_C(0x00000000) //!< Video codec is not supported. #define BGFX_CAPS_VIDEO_CODEC_BIT_8 UINT32_C(0x00000001) //!< 8-bit sample depth is supported. diff --git a/scripts/bgfx.idl b/scripts/bgfx.idl index 2a9189628..4dd47d187 100644 --- a/scripts/bgfx.idl +++ b/scripts/bgfx.idl @@ -1,7 +1,7 @@ -- vim: syntax=lua -- bgfx interface -version(166) +version(167) typedef "bool" typedef "char" @@ -437,6 +437,10 @@ flag.CapsFormat { bits = 32 } .TextureMipAutogen --- Texture format supports auto-generated mips. .TextureBackbuffer --- Texture format can be used as back buffer format. .TextureVideoDecodeDst --- Texture format can be used as video decode destination. + .TextureFramebufferMsaaX2 --- Texture format can be used as MSAA frame buffer with 2 samples. + .TextureFramebufferMsaaX4 --- Texture format can be used as MSAA frame buffer with 4 samples. + .TextureFramebufferMsaaX8 --- Texture format can be used as MSAA frame buffer with 8 samples. + .TextureFramebufferMsaaX16 --- Texture format can be used as MSAA frame buffer with 16 samples. () flag.CapsVideoCodec { bits = 32 } diff --git a/src/bgfx.cpp b/src/bgfx.cpp index b87f31b36..f4f692372 100644 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -2648,6 +2648,20 @@ namespace bgfx g_caps.formats[ii] |= 0 == (g_caps.formats[ii] & BGFX_CAPS_FORMAT_TEXTURE_CUBE) && convertable ? BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED : 0; } + for (uint32_t ii = 0; ii < TextureFormat::Count; ++ii) + { + uint32_t& formatCaps = g_caps.formats[ii]; + + if (0 == (formatCaps & BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA) ) + { + formatCaps &= ~kCapsFormatTextureFramebufferMsaaMask; + } + else if (0 == (formatCaps & kCapsFormatTextureFramebufferMsaaMask) ) + { + formatCaps |= kCapsFormatTextureFramebufferMsaaMask; + } + } + g_caps.rendererType = m_renderCtx->getRendererType(); initAttribTypeSizeTable(g_caps.rendererType); diff --git a/src/bgfx_p.h b/src/bgfx_p.h index 863ff1371..175482074 100644 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -3000,6 +3000,39 @@ namespace bgfx int16_t m_refCount; }; + constexpr uint32_t kCapsFormatTextureFramebufferMsaaMask = 0 + | BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X2 + | BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X4 + | BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X8 + | BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X16 + ; + + inline uint64_t clampTextureMsaa(TextureFormat::Enum _format, uint64_t _flags) + { + const uint32_t rt = uint32_t( (_flags & BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT); + + if (1 >= rt) + { + return _flags; + } + + uint32_t msaa = rt - 1; + + while (0 < msaa + && 0 == (g_caps.formats[_format] & (BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X2 << (msaa - 1) ) ) ) + { + --msaa; + } + + return (_flags & ~BGFX_TEXTURE_RT_MSAA_MASK) | (uint64_t(msaa + 1) << BGFX_TEXTURE_RT_MSAA_SHIFT); + } + + inline uint8_t getTextureMsaaSamples(TextureFormat::Enum _format, uint64_t _flags) + { + const uint64_t flags = clampTextureMsaa(_format, _flags); + return uint8_t(1 << bx::satSub(uint32_t( (flags & BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT), 1u) ); + } + struct TextureRef { void init( @@ -7657,6 +7690,7 @@ namespace bgfx } _flags |= imageContainer.m_srgb ? BGFX_TEXTURE_SRGB : 0; + _flags = clampTextureMsaa(_info->format, _flags); TextureHandle handle = { m_textureHandle.alloc() }; BX_WARN(isValid(handle), "Failed to allocate texture handle."); @@ -8243,7 +8277,10 @@ namespace bgfx ); const uint32_t msaa = (_desc.flags & BGFX_SWAP_CHAIN_MSAA_MASK) >> BGFX_SWAP_CHAIN_MSAA_SHIFT; - const uint32_t numSamples = 0 == msaa ? 1 : 1<CheckMultisampleQualityLevels(fmt, s_checkMsaa[jj], &quality); + + if (SUCCEEDED(hr) + && 0 < quality) + { + support |= BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X2 << (jj - 1); + } + } + + if (0 == (support & kCapsFormatTextureFramebufferMsaaMask) ) + { + support &= ~BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA; + } + } + if (0 != (support & BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ) ) { D3D11_FEATURE_DATA_FORMAT_SUPPORT2 data2; @@ -2493,7 +2513,6 @@ namespace bgfx { namespace d3d11 && 0 < quality) { s_msaa[ii].Count = msaa; - s_msaa[ii].Quality = quality - 1; last = ii; } else @@ -5102,8 +5121,7 @@ namespace bgfx { namespace d3d11 const bool readBack = 0 != (m_flags & BGFX_TEXTURE_READ_BACK); const bool externalShared = 0 != (m_flags & BGFX_TEXTURE_EXTERNAL_SHARED); - const uint32_t msaaQuality = bx::satSub(uint32_t( (m_flags&BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT ), 1u); - const DXGI_SAMPLE_DESC& msaa = s_msaa[msaaQuality]; + const DXGI_SAMPLE_DESC msaa = { getTextureMsaaSamples(TextureFormat::Enum(m_textureFormat), m_flags), 0 }; const bool blitUav = true && blit @@ -5851,9 +5869,8 @@ namespace bgfx { namespace d3d11 bool TextureD3D11::isMsaaSurface() const { - const uint32_t msaaQuality = bx::satSub(uint32_t( (m_flags&BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT), 1u); return true - && 1 < s_msaa[msaaQuality].Count + && 1 < getTextureMsaaSamples(TextureFormat::Enum(m_textureFormat), m_flags) && 0 != (m_flags & BGFX_TEXTURE_MSAA_SAMPLE) && !bimg::isDepth(bimg::TextureFormat::Enum(m_textureFormat) ) ; @@ -6234,8 +6251,7 @@ namespace bgfx { namespace d3d11 } } - const uint32_t msaaQuality = bx::satSub(uint32_t( (texture.m_flags&BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT ), 1u); - const DXGI_SAMPLE_DESC& msaa = s_msaa[msaaQuality]; + const DXGI_SAMPLE_DESC msaa = { getTextureMsaaSamples(TextureFormat::Enum(texture.m_textureFormat), texture.m_flags), 0 }; if (bimg::isDepth(bimg::TextureFormat::Enum(texture.m_textureFormat) ) ) { diff --git a/src/renderer_d3d12.cpp b/src/renderer_d3d12.cpp index 468c480ea..671147b0d 100644 --- a/src/renderer_d3d12.cpp +++ b/src/renderer_d3d12.cpp @@ -1935,6 +1935,32 @@ namespace bgfx { namespace d3d12 } } + if (0 != (support & BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA) ) + { + for (uint32_t jj = 1; jj < BX_COUNTOF(s_checkMsaa); ++jj) + { + D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaData = + { + .Format = fmt, + .SampleCount = s_checkMsaa[jj], + .Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE, + .NumQualityLevels = 0, + }; + hr = m_device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaData, sizeof(msaaData) ); + + if (SUCCEEDED(hr) + && 0 < msaaData.NumQualityLevels) + { + support |= BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X2 << (jj - 1); + } + } + + if (0 == (support & kCapsFormatTextureFramebufferMsaaMask) ) + { + support &= ~BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA; + } + } + if (0 != (support & BGFX_CAPS_FORMAT_TEXTURE_IMAGE_READ) ) { // clear image flag for additional testing @@ -3247,7 +3273,6 @@ namespace bgfx { namespace d3d12 && 0 < data.NumQualityLevels) { s_msaa[ii].Count = data.SampleCount; - s_msaa[ii].Quality = data.NumQualityLevels-1; last = ii; } else @@ -4234,10 +4259,7 @@ namespace bgfx { namespace d3d12 ? frameBuffer.m_texture[0] : frameBuffer.m_depth ; - const uint64_t flags = m_textures[th.idx].m_flags; - const uint32_t msaaQuality = bx::satSub(uint32_t( (flags & BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT), 1u); - - desc.SampleDesc = s_msaa[msaaQuality]; + desc.SampleDesc = m_textures[th.idx].m_sampleDesc; } } @@ -6936,11 +6958,12 @@ namespace bgfx { namespace d3d12 const bool blit = 0 != (m_flags & BGFX_TEXTURE_BLIT_DST); const bool externalShared = 0 != (m_flags & BGFX_TEXTURE_EXTERNAL_SHARED); - const uint32_t msaaQuality = bx::satSub(uint32_t( (m_flags & BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT ), 1u); - const DXGI_SAMPLE_DESC& msaa = s_msaa[msaaQuality]; - const bool depth = bimg::isDepth(bimg::TextureFormat::Enum(m_textureFormat) ); + m_sampleDesc = { getTextureMsaaSamples(TextureFormat::Enum(m_textureFormat), m_flags), 0 }; + + const DXGI_SAMPLE_DESC& msaa = m_sampleDesc; + const bool needResolve = true && 1 < msaa.Count && (0 == (m_flags & BGFX_TEXTURE_MSAA_SAMPLE) || depth) @@ -7796,9 +7819,8 @@ namespace bgfx { namespace d3d12 bool TextureD3D12::isMsaaSurface() const { - const uint32_t msaaQuality = bx::satSub(uint32_t( (m_flags&BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT), 1u); return true - && 1 < s_msaa[msaaQuality].Count + && 1 < m_sampleDesc.Count && 0 != (m_flags & BGFX_TEXTURE_MSAA_SAMPLE) && !bimg::isDepth(bimg::TextureFormat::Enum(m_textureFormat) ) ; @@ -7806,8 +7828,7 @@ namespace bgfx { namespace d3d12 bool TextureD3D12::isMultisampled() const { - const uint32_t msaaQuality = bx::satSub(uint32_t( (m_flags&BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT), 1u); - return 1 < s_msaa[msaaQuality].Count; + return 1 < m_sampleDesc.Count; } uint32_t TextureD3D12::getNumSlices() const @@ -8542,8 +8563,7 @@ namespace bgfx { namespace d3d12 m_height = bx::max(1, uint32_t(desc.Height) >> at.mip); } - const uint32_t msaaQuality = bx::satSub(uint32_t( (texture.m_flags & BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT ), 1u); - const DXGI_SAMPLE_DESC& msaa = s_msaa[msaaQuality]; + const DXGI_SAMPLE_DESC& msaa = texture.m_sampleDesc; if (bimg::isDepth(bimg::TextureFormat::Enum(texture.m_textureFormat) ) ) { diff --git a/src/renderer_d3d12.h b/src/renderer_d3d12.h index 56e0239d5..bb39658c8 100644 --- a/src/renderer_d3d12.h +++ b/src/renderer_d3d12.h @@ -462,6 +462,7 @@ namespace bgfx { namespace d3d12 bx::memSet(&m_srvd, 0, sizeof(m_srvd) ); bx::memSet(&m_uavd, 0, sizeof(m_uavd) ); m_srvHandle.ptr = 0; + m_sampleDesc = { 1, 0 }; } void* create(const Memory* _mem, uint64_t _flags, uint8_t _skip, uint64_t _external); @@ -493,6 +494,7 @@ namespace bgfx { namespace d3d12 void* m_directAccessPtr; D3D12_RESOURCE_STATES m_state; D3D12_RESOURCE_STATES* m_subStates; + DXGI_SAMPLE_DESC m_sampleDesc; uint64_t m_flags; uint32_t m_width; uint32_t m_height; diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 4068789a3..c0eace460 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -2752,22 +2752,35 @@ namespace bgfx { namespace gl if (NULL != glGetInternalformativ) { - GLint maxSamples = 0; + GLint sampleCounts[16] = {}; glGetInternalformativ(GL_RENDERBUFFER , s_textureFormat[ii].m_internalFmt , GL_SAMPLES - , 1 - , &maxSamples + , BX_COUNTOF(sampleCounts) + , sampleCounts ); GLenum err = getGlError(); - supported |= 0 == err && maxSamples > 0 + + for (uint32_t jj = 0; jj < BX_COUNTOF(sampleCounts) && 0 == err; ++jj) + { + const uint32_t numSamples = uint32_t(sampleCounts[jj]); + + if (2 <= numSamples + && 16 >= numSamples + && bx::isPowerOf2(numSamples) ) + { + supported |= BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X2 << (bx::countTrailingZeros(numSamples) - 1); + } + } + + supported |= 0 != (supported & kCapsFormatTextureFramebufferMsaaMask) ? BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA : BGFX_CAPS_FORMAT_TEXTURE_NONE ; if (m_textureMultisampleSupport) { - maxSamples = 0; + GLint maxSamples = 0; glGetInternalformativ( GL_TEXTURE_2D_MULTISAMPLE , s_textureFormat[ii].m_internalFmt @@ -6367,9 +6380,8 @@ namespace bgfx { namespace gl if (renderTarget) { - uint32_t msaaQuality = ( (m_flags&BGFX_TEXTURE_RT_MSAA_MASK)>>BGFX_TEXTURE_RT_MSAA_SHIFT); - msaaQuality = bx::satSub(msaaQuality, 1u); - msaaQuality = bx::min(s_renderGL->m_maxMsaa, msaaQuality == 0 ? 0 : 1<(s_renderGL->m_maxMsaa, numSamples); const bool msaaSample = 0 != (m_flags&BGFX_TEXTURE_MSAA_SAMPLE); if (!msaaSample @@ -6616,9 +6628,8 @@ namespace bgfx { namespace gl const bool computeWrite = 0 != (_flags&BGFX_TEXTURE_COMPUTE_WRITE); const bool srgb = 0 != (_flags&BGFX_TEXTURE_SRGB); const bool msaaSample = 0 != (_flags&BGFX_TEXTURE_MSAA_SAMPLE); - uint32_t msaaQuality = ( (_flags&BGFX_TEXTURE_RT_MSAA_MASK)>>BGFX_TEXTURE_RT_MSAA_SHIFT); - msaaQuality = bx::satSub(msaaQuality, 1u); - msaaQuality = bx::min(s_renderGL->m_maxMsaa, msaaQuality == 0 ? 0 : 1<(s_renderGL->m_maxMsaa, numSamples); GLenum target = msaaSample ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; if (imageContainer.m_cubeMap) diff --git a/src/renderer_mtl.cpp b/src/renderer_mtl.cpp index 0c5bf9213..a6ec0ba98 100644 --- a/src/renderer_mtl.cpp +++ b/src/renderer_mtl.cpp @@ -1135,9 +1135,27 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames TextureFormatCaps textureFormatCaps(m_device, hasPacked16Formats, hasPixelFormatDepth32Float_Stencil8); + uint32_t msaaCaps = 0; + + for (uint32_t ii = 1; ii < BX_COUNTOF(s_msaa); ++ii) + { + msaaCaps |= m_device->supportsTextureSampleCount(1<(uint32_t( (_flags&BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT ), 1u); - const int32_t sampleCount = s_msaa[msaaQuality]; + const int32_t sampleCount = getTextureMsaaSamples(TextureFormat::Enum(m_textureFormat), _flags); const bool isVideoDecodeDst = 0 != (_flags & BGFX_TEXTURE_INTERNAL_VIDEO_DECODE_DST); @@ -5481,8 +5498,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames } const TextureMtl &firstTexture = s_renderMtl->m_textures[_attachment[0].handle.idx]; - const uint32_t msaaQuality = bx::satSub(uint32_t( (firstTexture.m_flags&BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT ), 1u); - const int32_t sampleCount = s_msaa[msaaQuality]; + const int32_t sampleCount = getTextureMsaaSamples(TextureFormat::Enum(firstTexture.m_textureFormat), firstTexture.m_flags); murmur.add(sampleCount); m_pixelFormatHash = murmur.end(); diff --git a/src/renderer_vk.cpp b/src/renderer_vk.cpp index 8c3408784..cd20dfe10 100644 --- a/src/renderer_vk.cpp +++ b/src/renderer_vk.cpp @@ -2242,6 +2242,14 @@ VK_IMPORT_INSTANCE | BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN | (multisample ? BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA : 0) ; + + for (uint32_t kk = 1; kk < BX_COUNTOF(s_msaa); ++kk) + { + support |= 0 != (ifp.sampleCounts & VkSampleCountFlags(1 << kk) ) + ? BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X2 << (kk - 1) + : 0 + ; + } } } } @@ -7839,7 +7847,9 @@ VK_DESTROY const uint8_t bpp = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(m_textureFormat) ); m_aspectFlags = getAspectMask(m_format); - m_sampler = s_msaa[bx::satSub(uint32_t( (m_flags & BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT ), 1u)]; + + const uint8_t numSamples = getTextureMsaaSamples(TextureFormat::Enum(m_textureFormat), m_flags); + m_sampler = { numSamples, VkSampleCountFlagBits(numSamples) }; if (imageContainer.m_cubeMap) { diff --git a/src/renderer_webgpu.cpp b/src/renderer_webgpu.cpp index 84cac8497..ebb1d9f56 100644 --- a/src/renderer_webgpu.cpp +++ b/src/renderer_webgpu.cpp @@ -724,6 +724,7 @@ namespace bgfx { namespace wgpu if (multisample) { caps |= BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA + | BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA_X4 | BGFX_CAPS_FORMAT_TEXTURE_MSAA ; } @@ -4924,10 +4925,8 @@ WGPU_IMPORT ; const bool blit = 0 != (m_flags&BGFX_TEXTURE_BLIT_DST); - const uint32_t msaaQuality = bx::satSub(uint32_t( (m_flags & BGFX_TEXTURE_RT_MSAA_MASK) >> BGFX_TEXTURE_RT_MSAA_SHIFT ), 1u); - m_msaaCount = 1 == depthOrArrayLayers && WGPUTextureDimension_2D == dimension - ? s_msaa[msaaQuality] + ? getTextureMsaaSamples(TextureFormat::Enum(m_textureFormat), m_flags) : 1 ;