mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-10-24 18:00:54 +00:00
Metal: Fixed occlusion queries and depth texture data, added HDR10 and unretained command buffers. Closes #2356, #2017, #1827, #2974, #3642. (#4060)
This commit is contained in:
committed by
GitHub
parent
32966cfc7c
commit
227eac0d75
@@ -209,6 +209,53 @@ Linux
|
||||
|
||||
make linux-release64
|
||||
|
||||
Android
|
||||
~~~~~~~
|
||||
|
||||
With ``ANDROID_NDK_ROOT`` set (see `Prerequisites <#prerequisites>`_):
|
||||
|
||||
::
|
||||
|
||||
make android-arm64-release
|
||||
|
||||
Libraries are in ``.build/android-arm64/bin``. Link ``libbgfxRelease.a``, ``libbimgRelease.a`` and
|
||||
``libbxRelease.a`` into your native library, and add ``bgfx/include``, ``bimg/include`` and
|
||||
``bx/include`` to its include paths.
|
||||
|
||||
iOS
|
||||
~~~
|
||||
|
||||
For the command line:
|
||||
|
||||
::
|
||||
|
||||
make ios-arm64-release
|
||||
|
||||
Libraries are in ``.build/ios-arm64/bin``. To use them in your own Xcode project:
|
||||
|
||||
1. Link ``libbgfxRelease.a``, ``libbimgRelease.a`` and ``libbxRelease.a``.
|
||||
2. Link the ``Foundation``, ``CoreGraphics``, ``QuartzCore``, ``UIKit`` and ``Metal`` frameworks,
|
||||
plus ``VideoToolbox``, ``CoreMedia`` and ``CoreVideo`` for video decode.
|
||||
3. Add ``bgfx/include``, ``bimg/include`` and ``bx/include`` to *Header Search Paths*.
|
||||
4. Pass a ``CAMetalLayer``, or an ``MTKView``, as ``bgfx::PlatformData::nwh``.
|
||||
|
||||
Or build ``src/amalgamated.mm`` directly in your project instead of linking the libraries
|
||||
(see `Amalgamated Build <#amalgamated-build>`_).
|
||||
|
||||
For the Xcode IDE:
|
||||
|
||||
::
|
||||
|
||||
../bx/tools/bin/darwin/genie --with-combined-examples --xcode=ios xcode9
|
||||
open .build/projects/xcode9-ios/bgfx.xcworkspace
|
||||
|
||||
For tvOS, generate gmake projects with ``--gcc=tvos-arm64``:
|
||||
|
||||
::
|
||||
|
||||
../bx/tools/bin/darwin/genie --gcc=tvos-arm64 gmake
|
||||
make -R -C .build/projects/gmake-tvos-arm64 config=release
|
||||
|
||||
For more options, see `General (directly with GENie) <#general-directly-with-genie>`_.
|
||||
|
||||
WinRT / UWP
|
||||
|
||||
@@ -724,3 +724,14 @@ https://sluglibrary.com/
|
||||
|
||||
.. figure:: https://github.com/bkaradzic/bgfx/raw/master/examples/51-gpufont/screenshot.png
|
||||
:alt: example-51-gpufont
|
||||
|
||||
`55-hdr10 <https://github.com/bkaradzic/bgfx/tree/master/examples/55-hdr10>`__
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
HDR10 test pattern. Gray steps at 0 to 10000 nits and BT.2020 color bars at 203 nits, PQ encoded into
|
||||
an RGB10A2 back buffer, or as multiples of SDR white in an RGBA16F extended linear back buffer. HDR10
|
||||
can be toggled to compare HDR output against SDR on an HDR capable display.
|
||||
|
||||
Reference(s):
|
||||
- `ITU-R BT.2100 <https://www.itu.int/rec/R-REC-BT.2100>`__.
|
||||
- `ITU-R BT.2408 <https://www.itu.int/pub/R-REP-BT.2408>`__.
|
||||
|
||||
309
examples/55-hdr10/hdr10.cpp
Normal file
309
examples/55-hdr10/hdr10.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright 2011-2026 Branimir Karadzic. All rights reserved.
|
||||
* License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "bgfx_utils.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <bx/math.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr uint32_t kSwapChainFlags = 0
|
||||
| BGFX_SWAP_CHAIN_FULLSCREEN_MASK
|
||||
| BGFX_SWAP_CHAIN_MSAA_MASK
|
||||
| BGFX_SWAP_CHAIN_SRGB_BACKBUFFER
|
||||
| BGFX_SWAP_CHAIN_HDR10
|
||||
| BGFX_SWAP_CHAIN_HIDPI
|
||||
| BGFX_SWAP_CHAIN_TRANSPARENT_BACKBUFFER
|
||||
;
|
||||
|
||||
constexpr uint32_t kNumGray = 7;
|
||||
constexpr uint32_t kNumBars = 6;
|
||||
|
||||
constexpr float kGrayNits[kNumGray] = { 0.0f, 100.0f, 203.0f, 400.0f, 1000.0f, 4000.0f, 10000.0f };
|
||||
constexpr float kGrayScale[kNumGray] = { 0.0f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f, 16.0f };
|
||||
constexpr float kBarNits = 203.0f;
|
||||
|
||||
constexpr float kBarColor[kNumBars][3] =
|
||||
{
|
||||
{ 1.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 1.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, 1.0f },
|
||||
{ 0.0f, 1.0f, 1.0f },
|
||||
{ 1.0f, 0.0f, 1.0f },
|
||||
{ 1.0f, 1.0f, 0.0f },
|
||||
};
|
||||
|
||||
constexpr const char* kBarName[kNumBars] = { "R", "G", "B", "C", "M", "Y" };
|
||||
|
||||
float encodePq(float _nits)
|
||||
{
|
||||
constexpr float m1 = 2610.0f/16384.0f;
|
||||
constexpr float m2 = 2523.0f/4096.0f*128.0f;
|
||||
constexpr float c1 = 3424.0f/4096.0f;
|
||||
constexpr float c2 = 2413.0f/4096.0f*32.0f;
|
||||
constexpr float c3 = 2392.0f/4096.0f*32.0f;
|
||||
|
||||
const float yy = bx::pow(bx::clamp(_nits/10000.0f, 0.0f, 1.0f), m1);
|
||||
|
||||
return bx::pow( (c1 + c2*yy) / (1.0f + c3*yy), m2);
|
||||
}
|
||||
|
||||
class ExampleHdr10 : public entry::AppI
|
||||
{
|
||||
public:
|
||||
ExampleHdr10(const char* _name, const char* _description, const char* _url)
|
||||
: entry::AppI(_name, _description, _url)
|
||||
{
|
||||
}
|
||||
|
||||
void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override
|
||||
{
|
||||
Args args(_argc, _argv);
|
||||
|
||||
m_width = _width;
|
||||
m_height = _height;
|
||||
m_debug = BGFX_DEBUG_NONE;
|
||||
m_reset = BGFX_RESET_VSYNC|BGFX_RESET_HDR10;
|
||||
m_pq = true;
|
||||
|
||||
bgfx::Init init;
|
||||
init.type = args.m_type;
|
||||
init.vendorId = args.m_pciId;
|
||||
init.swapChain.nwh = entry::getNativeWindowHandle(entry::kDefaultWindowHandle);
|
||||
init.swapChain.ndt = entry::getNativeDisplayHandle();
|
||||
init.platformData.type = entry::getNativeWindowHandleType();
|
||||
init.swapChain.width = m_width;
|
||||
init.swapChain.height = m_height;
|
||||
init.swapChain.formatColor = getFormat();
|
||||
init.reset = m_reset;
|
||||
bgfx::init(init);
|
||||
|
||||
bgfx::setDebug(m_debug);
|
||||
|
||||
m_appliedWidth = m_width;
|
||||
m_appliedHeight = m_height;
|
||||
m_appliedReset = m_reset;
|
||||
m_appliedPq = m_pq;
|
||||
|
||||
imguiCreate();
|
||||
}
|
||||
|
||||
int shutdown() override
|
||||
{
|
||||
imguiDestroy();
|
||||
|
||||
bgfx::shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bgfx::TextureFormat::Enum getFormat() const
|
||||
{
|
||||
return m_pq
|
||||
? bgfx::TextureFormat::RGB10A2
|
||||
: bgfx::TextureFormat::RGBA16F
|
||||
;
|
||||
}
|
||||
|
||||
void setPatch(uint8_t _index, float _red, float _green, float _blue)
|
||||
{
|
||||
const float rgba[4] = { _red, _green, _blue, 1.0f };
|
||||
bgfx::setPaletteColor(_index, rgba);
|
||||
}
|
||||
|
||||
float encode(float _nits, float _scale) const
|
||||
{
|
||||
return m_pq ? encodePq(_nits) : _scale;
|
||||
}
|
||||
|
||||
void imguiLabel(float _x, float _y, const char* _id, const char* _text)
|
||||
{
|
||||
ImGui::SetNextWindowPos(ImVec2(_x, _y), 0, ImVec2(0.5f, 1.0f) );
|
||||
ImGui::SetNextWindowBgAlpha(0.5f);
|
||||
|
||||
ImGui::Begin(_id, NULL, 0
|
||||
| ImGuiWindowFlags_NoInputs
|
||||
| ImGuiWindowFlags_NoTitleBar
|
||||
| ImGuiWindowFlags_NoMove
|
||||
| ImGuiWindowFlags_NoResize
|
||||
| ImGuiWindowFlags_NoSavedSettings
|
||||
| ImGuiWindowFlags_AlwaysAutoResize
|
||||
);
|
||||
ImGui::Text("%s", _text);
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void submitPatch(bgfx::ViewId _view, uint8_t _index, uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height)
|
||||
{
|
||||
bgfx::setViewRect(_view, _x, _y, _width, _height);
|
||||
bgfx::setViewClear(_view, BGFX_CLEAR_COLOR, 1.0f, 0, _index);
|
||||
bgfx::touch(_view);
|
||||
}
|
||||
|
||||
bool update() override
|
||||
{
|
||||
if (entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
imguiBeginFrame(m_mouseState.m_mx
|
||||
, m_mouseState.m_my
|
||||
, (m_mouseState.m_buttons[entry::MouseButton::Left ] ? IMGUI_MBUT_LEFT : 0)
|
||||
| (m_mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0)
|
||||
| (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
|
||||
, m_mouseState.m_mz
|
||||
, uint16_t(m_width)
|
||||
, uint16_t(m_height)
|
||||
);
|
||||
|
||||
showExampleDialog(this);
|
||||
|
||||
bool hdr10 = 0 != (m_reset & BGFX_RESET_HDR10);
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(m_width / 5.0f, m_height / 6.0f), ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin("Settings", NULL, 0);
|
||||
|
||||
if (ImGui::RadioButton("PQ, RGB10A2", m_pq) )
|
||||
{
|
||||
m_pq = true;
|
||||
}
|
||||
|
||||
if (ImGui::RadioButton("Linear, RGBA16F", !m_pq) )
|
||||
{
|
||||
m_pq = false;
|
||||
}
|
||||
|
||||
ImGui::Checkbox("HDR10", &hdr10);
|
||||
|
||||
ImGui::End();
|
||||
|
||||
const float labelRowHeight = float(m_height*2/5);
|
||||
|
||||
char id[32];
|
||||
char text[128];
|
||||
|
||||
for (uint32_t ii = 0; ii < kNumGray; ++ii)
|
||||
{
|
||||
if (m_pq)
|
||||
{
|
||||
bx::snprintf(text, BX_COUNTOF(text), "%.0f nits", kGrayNits[ii]);
|
||||
}
|
||||
else
|
||||
{
|
||||
bx::snprintf(text, BX_COUNTOF(text), "%.1fx white", kGrayScale[ii]);
|
||||
}
|
||||
|
||||
bx::snprintf(id, BX_COUNTOF(id), "gray%d", ii);
|
||||
imguiLabel(m_width*(ii + 0.5f)/kNumGray, labelRowHeight - 10.0f, id, text);
|
||||
}
|
||||
|
||||
for (uint32_t ii = 0; ii < kNumBars; ++ii)
|
||||
{
|
||||
if (m_pq)
|
||||
{
|
||||
bx::snprintf(text, BX_COUNTOF(text), "%s %.0f nits", kBarName[ii], kBarNits);
|
||||
}
|
||||
else
|
||||
{
|
||||
bx::snprintf(text, BX_COUNTOF(text), "%s 1.0x white", kBarName[ii]);
|
||||
}
|
||||
|
||||
bx::snprintf(id, BX_COUNTOF(id), "bar%d", ii);
|
||||
imguiLabel(m_width*(ii + 0.5f)/kNumBars, 2.0f*labelRowHeight - 10.0f, id, text);
|
||||
}
|
||||
|
||||
const bgfx::Caps* caps = bgfx::getCaps();
|
||||
|
||||
bx::snprintf(text, BX_COUNTOF(text), "BGFX_CAPS_HDR10: %s, back buffer: %s"
|
||||
, 0 != (caps->supported & BGFX_CAPS_HDR10) ? "supported" : "not supported"
|
||||
, m_pq ? "RGB10A2, PQ BT.2020" : "RGBA16F, extended linear sRGB"
|
||||
);
|
||||
imguiLabel(m_width*0.5f, m_height - 10.0f, "status", text);
|
||||
|
||||
imguiEndFrame();
|
||||
|
||||
m_reset = (m_reset & ~BGFX_RESET_HDR10) | (hdr10 ? BGFX_RESET_HDR10 : 0);
|
||||
|
||||
if (m_width != m_appliedWidth
|
||||
|| m_height != m_appliedHeight
|
||||
|| m_reset != m_appliedReset
|
||||
|| m_pq != m_appliedPq)
|
||||
{
|
||||
m_appliedWidth = m_width;
|
||||
m_appliedHeight = m_height;
|
||||
m_appliedReset = m_reset;
|
||||
m_appliedPq = m_pq;
|
||||
|
||||
bgfx::SwapChain swapChain;
|
||||
swapChain.width = m_width;
|
||||
swapChain.height = m_height;
|
||||
swapChain.flags = m_reset & kSwapChainFlags;
|
||||
swapChain.formatColor = getFormat();
|
||||
|
||||
bgfx::reset(m_reset & ~kSwapChainFlags, &swapChain);
|
||||
}
|
||||
|
||||
bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height) );
|
||||
bgfx::setViewClear(0, BGFX_CLEAR_COLOR, 0x000000ff, 1.0f, 0);
|
||||
bgfx::touch(0);
|
||||
|
||||
const uint16_t rowHeight = uint16_t(m_height*2/5);
|
||||
|
||||
for (uint32_t ii = 0; ii < kNumGray; ++ii)
|
||||
{
|
||||
const float value = encode(kGrayNits[ii], kGrayScale[ii]);
|
||||
setPatch(uint8_t(ii), value, value, value);
|
||||
|
||||
const uint16_t x0 = uint16_t(m_width* ii /kNumGray);
|
||||
const uint16_t x1 = uint16_t(m_width*(ii + 1)/kNumGray);
|
||||
submitPatch(bgfx::ViewId(1 + ii), uint8_t(ii), x0, 0, x1 - x0, rowHeight);
|
||||
}
|
||||
|
||||
for (uint32_t ii = 0; ii < kNumBars; ++ii)
|
||||
{
|
||||
const float on = encode(kBarNits, 1.0f);
|
||||
setPatch(uint8_t(kNumGray + ii)
|
||||
, kBarColor[ii][0]*on
|
||||
, kBarColor[ii][1]*on
|
||||
, kBarColor[ii][2]*on
|
||||
);
|
||||
|
||||
const uint16_t x0 = uint16_t(m_width* ii /kNumBars);
|
||||
const uint16_t x1 = uint16_t(m_width*(ii + 1)/kNumBars);
|
||||
submitPatch(bgfx::ViewId(1 + kNumGray + ii), uint8_t(kNumGray + ii), x0, rowHeight, x1 - x0, rowHeight);
|
||||
}
|
||||
|
||||
bgfx::frame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
entry::MouseState m_mouseState;
|
||||
|
||||
uint32_t m_width;
|
||||
uint32_t m_height;
|
||||
uint32_t m_debug;
|
||||
uint32_t m_reset;
|
||||
bool m_pq;
|
||||
|
||||
uint32_t m_appliedWidth;
|
||||
uint32_t m_appliedHeight;
|
||||
uint32_t m_appliedReset;
|
||||
bool m_appliedPq;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ENTRY_IMPLEMENT_MAIN(
|
||||
ExampleHdr10
|
||||
, "55-hdr10"
|
||||
, "HDR10 test pattern."
|
||||
, "https://bkaradzic.github.io/bgfx/examples.html#hdr10"
|
||||
);
|
||||
@@ -9,13 +9,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <QuartzCore/CAEAGLLayer.h>
|
||||
|
||||
#if __IPHONE_8_0 && !TARGET_IPHONE_SIMULATOR // check if sdk/target supports metal
|
||||
# import <Metal/Metal.h>
|
||||
# import <QuartzCore/CAMetalLayer.h>
|
||||
# define HAS_METAL_SDK
|
||||
#endif
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
#include <bgfx/bgfx.h>
|
||||
|
||||
@@ -190,21 +184,7 @@ using namespace entry;
|
||||
|
||||
+ (Class)layerClass
|
||||
{
|
||||
#ifdef HAS_METAL_SDK
|
||||
static id<MTLDevice> device = NULL;
|
||||
Class metalClass = NSClassFromString(@"CAMetalLayer"); //is metal runtime sdk available
|
||||
if ( metalClass != nil)
|
||||
{
|
||||
device = MTLCreateSystemDefaultDevice(); // is metal supported on this device (is there a better way to do this - without creating device ?)
|
||||
if (NULL != device)
|
||||
{
|
||||
[device retain];
|
||||
return metalClass;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return [CAEAGLLayer class];
|
||||
return [CAMetalLayer class];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)rect
|
||||
|
||||
@@ -139,6 +139,9 @@ function bgfxProjectBase(_kind, _defines)
|
||||
"-Wno-microsoft-const-init", -- default initialization of an object of const type '' without a user-provided default constructor is a Microsoft extension
|
||||
}
|
||||
|
||||
configuration { "ios* or tvos* or xros*" }
|
||||
buildoptions { "-x objective-c++" }
|
||||
|
||||
configuration { "osx*" }
|
||||
buildoptions { "-x objective-c++" } -- additional build option for osx
|
||||
linkoptions {
|
||||
|
||||
@@ -403,9 +403,9 @@ function exampleProjectDefaults()
|
||||
kind "ConsoleApp"
|
||||
linkoptions {
|
||||
"-framework CoreFoundation",
|
||||
"-framework CoreGraphics",
|
||||
"-framework Foundation",
|
||||
"-framework IOKit",
|
||||
"-framework OpenGLES",
|
||||
"-framework QuartzCore",
|
||||
"-framework UIKit",
|
||||
"-weak_framework Metal",
|
||||
@@ -591,6 +591,7 @@ or _OPTIONS["with-combined-examples"] then
|
||||
, "52-layered"
|
||||
, "53-sky2"
|
||||
, "54-s2h"
|
||||
, "55-hdr10"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -149,11 +149,15 @@ project ("geometryv")
|
||||
kind "ConsoleApp"
|
||||
linkoptions {
|
||||
"-framework CoreFoundation",
|
||||
"-framework CoreGraphics",
|
||||
"-framework Foundation",
|
||||
"-framework IOKit",
|
||||
"-framework OpenGLES",
|
||||
"-framework QuartzCore",
|
||||
"-framework UIKit",
|
||||
"-weak_framework Metal",
|
||||
"-weak_framework VideoToolbox",
|
||||
"-weak_framework CoreMedia",
|
||||
"-weak_framework CoreVideo",
|
||||
}
|
||||
|
||||
configuration { "xcode4", "ios" }
|
||||
|
||||
@@ -209,11 +209,15 @@ project "texturev"
|
||||
kind "ConsoleApp"
|
||||
linkoptions {
|
||||
"-framework CoreFoundation",
|
||||
"-framework CoreGraphics",
|
||||
"-framework Foundation",
|
||||
"-framework IOKit",
|
||||
"-framework OpenGLES",
|
||||
"-framework QuartzCore",
|
||||
"-framework UIKit",
|
||||
"-weak_framework Metal",
|
||||
"-weak_framework VideoToolbox",
|
||||
"-weak_framework CoreMedia",
|
||||
"-weak_framework CoreVideo",
|
||||
}
|
||||
|
||||
configuration { "xcode*", "ios" }
|
||||
|
||||
@@ -187,7 +187,7 @@ namespace bgfx
|
||||
, 1
|
||||
);
|
||||
|
||||
bimg::imageWriteTga(&writer, _width, _height, _pitch, _data, false, _yflip);
|
||||
bimg::imageWriteTga(&writer, _width, _height, dstPitch, dst, false, _yflip);
|
||||
|
||||
bx::free(g_allocator, dst);
|
||||
}
|
||||
|
||||
@@ -674,10 +674,11 @@ BX_PRAGMA_DIAGNOSTIC_POP();
|
||||
|
||||
if (false
|
||||
|| TextureFormat::BGRA8 == _fmt
|
||||
|| TextureFormat::RGB10A2 == _fmt
|
||||
|| TextureFormat::RGBA16F == _fmt
|
||||
)
|
||||
{
|
||||
// CAMetalLayer accepts BGRA8Unorm(_sRGB) and RGBA16Float as drawable pixel formats.
|
||||
// CAMetalLayer accepts BGRA8Unorm(_sRGB), RGB10A2Unorm and RGBA16Float as drawable pixel formats.
|
||||
caps |= BGFX_CAPS_FORMAT_TEXTURE_BACKBUFFER;
|
||||
}
|
||||
|
||||
@@ -1011,6 +1012,19 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
| BGFX_CAPS_VERTEX_ATTRIB_UINT10
|
||||
);
|
||||
|
||||
#if BX_PLATFORM_OSX
|
||||
if (__builtin_available(macOS 11.0, *) )
|
||||
{
|
||||
void* screen = MtlObjAccess::send<void*>(objc_lookUpClass("NSScreen"), sel_registerName("mainScreen") );
|
||||
|
||||
if (NULL != screen
|
||||
&& 1.0 < MtlObjAccess::send<double>(screen, sel_registerName("maximumPotentialExtendedDynamicRangeColorComponentValue") ) )
|
||||
{
|
||||
g_caps.supported |= BGFX_CAPS_HDR10;
|
||||
}
|
||||
}
|
||||
#endif // BX_PLATFORM_OSX
|
||||
|
||||
g_caps.supported |= (m_device->supportsFamily(MTL::GPUFamilyApple7) || m_device->supportsFamily(MTL::GPUFamilyMac2) )
|
||||
? BGFX_CAPS_PRIMITIVE_ID
|
||||
: 0
|
||||
@@ -2048,12 +2062,12 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
if (NULL != frameBuffer.m_swapChain
|
||||
&& frameBuffer.m_swapChain->m_drawableTexture)
|
||||
{
|
||||
MTL_RELEASE_I(frameBuffer.m_swapChain->m_drawableTexture);
|
||||
MTL_RELEASE_DEFERRED(frameBuffer.m_swapChain->m_drawableTexture);
|
||||
|
||||
if (NULL != frameBuffer.m_swapChain->m_drawable)
|
||||
{
|
||||
presentCommandBuffer->presentDrawable( (MTL::Drawable*)frameBuffer.m_swapChain->m_drawable);
|
||||
MTL_RELEASE_I(frameBuffer.m_swapChain->m_drawable);
|
||||
MTL_RELEASE_DEFERRED(frameBuffer.m_swapChain->m_drawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2143,7 +2157,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
if (NULL == m_screenshotBlitRenderPipelineState
|
||||
|| m_screenshotBlitPixelFormat != _pixelFormat)
|
||||
{
|
||||
MTL_RELEASE_I(m_screenshotBlitRenderPipelineState);
|
||||
MTL_RELEASE_DEFERRED(m_screenshotBlitRenderPipelineState);
|
||||
reset(m_renderPipelineDescriptor);
|
||||
|
||||
m_renderPipelineDescriptor->colorAttachments()->object(0)->setPixelFormat(_pixelFormat);
|
||||
@@ -2437,7 +2451,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
, MTL::Origin::Make(_rect.m_x, _rect.m_y, 0)
|
||||
);
|
||||
|
||||
MTL_RELEASE_I(buffer);
|
||||
MTL_RELEASE_DEFERRED(buffer);
|
||||
}
|
||||
|
||||
endBlitEncoding();
|
||||
@@ -3875,7 +3889,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
|
||||
void ChunkedScratchBufferMtl::destroyChunk(ChunkMtl& _chunk)
|
||||
{
|
||||
MTL_RELEASE_W(_chunk.buffer, 0);
|
||||
MTL_RELEASE_DEFERRED(_chunk.buffer);
|
||||
}
|
||||
|
||||
void ChunkedScratchBufferMtl::flushChunk(ChunkMtl& _chunk, uint32_t _size)
|
||||
@@ -4569,7 +4583,33 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
;
|
||||
}
|
||||
|
||||
m_ptr->replaceRegion(region, lod, side, data, bytesPerRow, bytesPerImage);
|
||||
if (MTL::StorageModePrivate == m_ptr->storageMode() )
|
||||
{
|
||||
const uint32_t size = convert
|
||||
? width*height*depth*4
|
||||
: mip.m_size
|
||||
;
|
||||
|
||||
MTL::Buffer* staging = s_renderMtl->m_device->newBuffer(data, size, MTL::ResourceCPUCacheModeDefaultCache);
|
||||
|
||||
s_renderMtl->getBlitCommandEncoder()->copyFromBuffer(
|
||||
staging
|
||||
, 0
|
||||
, bytesPerRow
|
||||
, bytesPerImage
|
||||
, MTL::Size::Make(width, height, depth)
|
||||
, m_ptr
|
||||
, side
|
||||
, lod
|
||||
, MTL::Origin::Make(0, 0, 0)
|
||||
);
|
||||
|
||||
s_renderMtl->m_cmd.release(staging);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ptr->replaceRegion(region, lod, side, data, bytesPerRow, bytesPerImage);
|
||||
}
|
||||
}
|
||||
|
||||
width >>= 1;
|
||||
@@ -4594,18 +4634,18 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
|
||||
if (0 == (m_flags & BGFX_SAMPLER_INTERNAL_SHARED) )
|
||||
{
|
||||
MTL_RELEASE_W(m_ptr, 0);
|
||||
MTL_RELEASE_DEFERRED(m_ptr);
|
||||
}
|
||||
|
||||
MTL_RELEASE_W(m_ptrMsaa, 0);
|
||||
MTL_RELEASE_W(m_ptrStencil, 0);
|
||||
MTL_RELEASE_W(m_ptrAlt, 0);
|
||||
MTL_RELEASE_W(m_ptrMsaaAlt, 0);
|
||||
MTL_RELEASE_DEFERRED(m_ptrMsaa);
|
||||
MTL_RELEASE_DEFERRED(m_ptrStencil);
|
||||
MTL_RELEASE_DEFERRED(m_ptrAlt);
|
||||
MTL_RELEASE_DEFERRED(m_ptrMsaaAlt);
|
||||
|
||||
for (stl::unordered_map<uint64_t, MTL::Texture*>::iterator it = m_ptrViews.begin(), itEnd = m_ptrViews.end(); it != itEnd; ++it)
|
||||
{
|
||||
MTL::Texture* view = it->second;
|
||||
MTL_RELEASE_W(view, 0);
|
||||
MTL_RELEASE_DEFERRED(view);
|
||||
}
|
||||
m_ptrViews.clear();
|
||||
}
|
||||
@@ -4729,7 +4769,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
);
|
||||
|
||||
MTL_RELEASE(desc, 0);
|
||||
MTL_RELEASE(tempTexture, 1);
|
||||
MTL_RELEASE_DEFERRED(tempTexture);
|
||||
}
|
||||
|
||||
if (NULL != temp)
|
||||
@@ -4958,10 +4998,10 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
SwapChainMtl::~SwapChainMtl()
|
||||
{
|
||||
MTL_RELEASE(m_metalLayer, 2);
|
||||
MTL_RELEASE(m_drawable, 0);
|
||||
MTL_RELEASE_DEFERRED(m_drawable);
|
||||
|
||||
MTL_RELEASE(m_drawableTexture, 0);
|
||||
MTL_RELEASE(m_screenshotTarget, 0);
|
||||
MTL_RELEASE_DEFERRED(m_drawableTexture);
|
||||
MTL_RELEASE_DEFERRED(m_screenshotTarget);
|
||||
|
||||
releaseBackBuffer();
|
||||
}
|
||||
@@ -5130,11 +5170,11 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
}
|
||||
else
|
||||
{
|
||||
MTL_RELEASE(m_backBufferStencil, m_backBufferDepth == m_backBufferStencil ? 1 : 0);
|
||||
MTL_RELEASE_W(m_backBufferDepth, 0);
|
||||
MTL_RELEASE_DEFERRED(m_backBufferStencil);
|
||||
MTL_RELEASE_DEFERRED(m_backBufferDepth);
|
||||
}
|
||||
|
||||
MTL_RELEASE_W(m_backBufferColorMsaa, 0);
|
||||
MTL_RELEASE_DEFERRED(m_backBufferColorMsaa);
|
||||
}
|
||||
|
||||
uint32_t SwapChainMtl::resize(const SwapChain& _desc)
|
||||
@@ -5174,6 +5214,33 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
: s_textureFormat[formatColor].fmt) )
|
||||
;
|
||||
|
||||
const bool hdr10 = 0 != (_desc.flags & BGFX_SWAP_CHAIN_HDR10);
|
||||
|
||||
if (hdr10
|
||||
|| m_hdr10)
|
||||
{
|
||||
if (__builtin_available(macOS 11.0, iOS 16.0, tvOS 16.0, macCatalyst 16.0, VISION_OS_MINIMUM *) )
|
||||
{
|
||||
CFStringRef colorSpaceName = !hdr10 ? NULL
|
||||
: TextureFormat::RGB10A2 == formatColor ? kCGColorSpaceITUR_2100_PQ
|
||||
: TextureFormat::RGBA16F == formatColor ? kCGColorSpaceExtendedLinearSRGB
|
||||
: NULL
|
||||
;
|
||||
|
||||
CGColorSpaceRef colorSpace = NULL != colorSpaceName
|
||||
? CGColorSpaceCreateWithName(colorSpaceName)
|
||||
: NULL
|
||||
;
|
||||
|
||||
MtlObjAccess::send<void>(m_metalLayer, sel_registerName("setColorspace:"), colorSpace);
|
||||
MtlObjAccess::send<void>(m_metalLayer, sel_registerName("setWantsExtendedDynamicRangeContent:"), NULL != colorSpace);
|
||||
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
}
|
||||
|
||||
m_hdr10 = hdr10;
|
||||
}
|
||||
|
||||
const CGSize actualSize = m_metalLayer->drawableSize();
|
||||
BX_WARN(true
|
||||
&& uint32_t(actualSize.width) == _desc.width
|
||||
@@ -5506,18 +5573,38 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
{
|
||||
NS::AutoreleasePool* pool = NS::AutoreleasePool::alloc()->init();
|
||||
|
||||
for (ReleaseArray::iterator it = m_release.begin(), itEnd = m_release.end(); it != itEnd; ++it)
|
||||
{
|
||||
MTL_RELEASE_I(it->ptr);
|
||||
}
|
||||
|
||||
m_release.clear();
|
||||
|
||||
MTL_RELEASE(m_commandQueue, 0);
|
||||
|
||||
pool->release();
|
||||
}
|
||||
}
|
||||
|
||||
void deferredRelease(NS::Object* _obj)
|
||||
{
|
||||
if (NULL != s_renderMtl
|
||||
&& NULL != s_renderMtl->m_cmd.m_commandQueue)
|
||||
{
|
||||
s_renderMtl->m_cmd.release(_obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
_obj->release();
|
||||
}
|
||||
}
|
||||
|
||||
MTL::CommandBuffer* CommandQueueMtl::alloc()
|
||||
{
|
||||
{
|
||||
NS::AutoreleasePool* pool = NS::AutoreleasePool::alloc()->init();
|
||||
|
||||
m_activeCommandBuffer = m_commandQueue->commandBuffer();
|
||||
m_activeCommandBuffer = m_commandQueue->commandBufferWithUnretainedReferences();
|
||||
retain(m_activeCommandBuffer);
|
||||
|
||||
pool->release();
|
||||
@@ -5531,6 +5618,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
|
||||
if (queue)
|
||||
{
|
||||
bx::atomicFetchAndAdd<uint32_t>(&queue->m_completedFrames, 1);
|
||||
queue->m_framesSemaphore.post();
|
||||
}
|
||||
}
|
||||
@@ -5541,7 +5629,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
{
|
||||
if (_endFrame)
|
||||
{
|
||||
m_releaseWriteIndex = (m_releaseWriteIndex + 1) % BGFX_CONFIG_MAX_FRAME_LATENCY;
|
||||
++m_submittedFrames;
|
||||
m_activeCommandBuffer->addCompletedHandler(
|
||||
MTL::HandlerFunction([this](MTL::CommandBuffer*) { commandBufferFinishedCallback(this); })
|
||||
);
|
||||
@@ -5588,22 +5676,23 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
|
||||
void CommandQueueMtl::release(NS::Object* _ptr)
|
||||
{
|
||||
m_release[m_releaseWriteIndex].push_back(_ptr);
|
||||
m_release.push_back({ _ptr, m_submittedFrames });
|
||||
}
|
||||
|
||||
void CommandQueueMtl::consume()
|
||||
{
|
||||
m_framesSemaphore.wait();
|
||||
m_releaseReadIndex = (m_releaseReadIndex + 1) % BGFX_CONFIG_MAX_FRAME_LATENCY;
|
||||
|
||||
ResourceArray& ra = m_release[m_releaseReadIndex];
|
||||
const uint32_t completedFrames = bx::atomicLoad(&m_completedFrames);
|
||||
|
||||
for (ResourceArray::iterator it = ra.begin(), itEnd = ra.end(); it != itEnd; ++it)
|
||||
ReleaseArray::iterator it = m_release.begin();
|
||||
|
||||
for (ReleaseArray::iterator itEnd = m_release.end(); it != itEnd && 0 < int32_t(completedFrames - it->frame); ++it)
|
||||
{
|
||||
MTL_RELEASE_I(*it);
|
||||
MTL_RELEASE_I(it->ptr);
|
||||
}
|
||||
|
||||
ra.clear();
|
||||
m_release.erase(m_release.begin(), it);
|
||||
}
|
||||
|
||||
static constexpr uint64_t kNanosecondsPerSecond = UINT64_C(1000000000);
|
||||
@@ -5681,7 +5770,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
{
|
||||
for (uint32_t ii = 0; ii < BX_COUNTOF(m_sampling); ++ii)
|
||||
{
|
||||
MTL_RELEASE_W(m_sampling[ii].m_sampleBuffer, 0);
|
||||
MTL_RELEASE_DEFERRED(m_sampling[ii].m_sampleBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5877,7 +5966,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
|
||||
void OcclusionQueryMTL::postReset()
|
||||
{
|
||||
MTL_RELEASE_W(m_buffer, 0);
|
||||
MTL_RELEASE_DEFERRED(m_buffer);
|
||||
}
|
||||
|
||||
void OcclusionQueryMTL::preReset()
|
||||
@@ -5894,8 +5983,9 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
|
||||
Query& query = m_query[m_control.m_current];
|
||||
query.m_handle = _handle;
|
||||
query.m_frame = s_renderMtl->m_cmd.m_submittedFrames;
|
||||
uint32_t offset = _handle.idx * 8;
|
||||
_rce->setVisibilityResultMode( (MTL::VisibilityResultMode)MTL::VisibilityResultModeBoolean, offset);
|
||||
_rce->setVisibilityResultMode( (MTL::VisibilityResultMode)MTL::VisibilityResultModeCounting, offset);
|
||||
}
|
||||
|
||||
void OcclusionQueryMTL::end(MTL::RenderCommandEncoder*& _rce)
|
||||
@@ -5908,12 +5998,19 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
|
||||
void OcclusionQueryMTL::resolve(Frame* _render, bool _wait)
|
||||
{
|
||||
BX_UNUSED(_wait);
|
||||
const uint32_t completedFrames = bx::atomicLoad(&s_renderMtl->m_cmd.m_completedFrames);
|
||||
|
||||
while (0 != m_control.getNumUsed() )
|
||||
{
|
||||
Query& query = m_query[m_control.m_read];
|
||||
|
||||
if (!_wait
|
||||
&& isValid(query.m_handle)
|
||||
&& int32_t(completedFrames - query.m_frame) <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (isValid(query.m_handle) )
|
||||
{
|
||||
uint64_t result = ( (uint64_t*)m_buffer->contents() )[query.m_handle.idx];
|
||||
@@ -6161,7 +6258,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
&& (swapChain->m_screenshotTarget->width() != width
|
||||
|| swapChain->m_screenshotTarget->height() != height) )
|
||||
{
|
||||
MTL_RELEASE(swapChain->m_screenshotTarget, 0);
|
||||
MTL_RELEASE_DEFERRED(swapChain->m_screenshotTarget);
|
||||
}
|
||||
|
||||
if (NULL == swapChain->m_screenshotTarget)
|
||||
@@ -6197,7 +6294,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
|
||||
}
|
||||
else
|
||||
{
|
||||
MTL_RELEASE(swapChain->m_screenshotTarget, 0);
|
||||
MTL_RELEASE_DEFERRED(swapChain->m_screenshotTarget);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,15 @@
|
||||
#define MTL_RELEASE_W(_obj, _expected) _MTL_RELEASE(_obj, _expected, BX_WARN)
|
||||
#define MTL_RELEASE_I(_obj) _MTL_RELEASE(_obj, 0, BX_NOOP)
|
||||
|
||||
#define MTL_RELEASE_DEFERRED(_obj) \
|
||||
BX_MACRO_BLOCK_BEGIN \
|
||||
if (NULL != _obj) \
|
||||
{ \
|
||||
bgfx::mtl::deferredRelease( (NS::Object*)(void*)_obj); \
|
||||
_obj = NULL; \
|
||||
} \
|
||||
BX_MACRO_BLOCK_END
|
||||
|
||||
namespace bgfx { namespace mtl
|
||||
{
|
||||
// Helper to access NS::Object's protected sendMessage for label retrieval
|
||||
@@ -243,6 +252,8 @@ namespace bgfx { namespace mtl
|
||||
return MTL::RasterizationRateMapDescriptor::alloc()->init();
|
||||
}
|
||||
|
||||
void deferredRelease(NS::Object* _obj);
|
||||
|
||||
//helper functions
|
||||
template<typename T>
|
||||
inline void release(T* _obj)
|
||||
@@ -277,7 +288,7 @@ namespace bgfx { namespace mtl
|
||||
|
||||
void destroy()
|
||||
{
|
||||
MTL_RELEASE_W(m_ptr, 0);
|
||||
MTL_RELEASE_DEFERRED(m_ptr);
|
||||
|
||||
if (NULL != m_dynamic)
|
||||
{
|
||||
@@ -324,13 +335,13 @@ namespace bgfx { namespace mtl
|
||||
{
|
||||
for (FunctionMap::iterator it = m_functions.begin(), itEnd = m_functions.end(); it != itEnd; ++it)
|
||||
{
|
||||
MTL_RELEASE_W(it->second, 0);
|
||||
MTL_RELEASE_DEFERRED(it->second);
|
||||
}
|
||||
|
||||
m_functions.clear();
|
||||
m_function = NULL;
|
||||
|
||||
MTL_RELEASE_W(m_lib, 0);
|
||||
MTL_RELEASE_DEFERRED(m_lib);
|
||||
}
|
||||
|
||||
typedef stl::unordered_map<uint32_t, MTL::Function*> FunctionMap;
|
||||
@@ -403,8 +414,8 @@ namespace bgfx { namespace mtl
|
||||
m_fshConstantBuffer = NULL;
|
||||
}
|
||||
|
||||
MTL_RELEASE_W(m_rps, 0);
|
||||
MTL_RELEASE_W(m_cps, 0);
|
||||
MTL_RELEASE_DEFERRED(m_rps);
|
||||
MTL_RELEASE_DEFERRED(m_cps);
|
||||
}
|
||||
|
||||
UniformBuffer* m_vshConstantBuffer;
|
||||
@@ -436,6 +447,17 @@ namespace bgfx { namespace mtl
|
||||
bx::deleteObject(g_allocator, _ptr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void evict(T* _ptr)
|
||||
{
|
||||
deferredRelease( (NS::Object*)(void*)_ptr);
|
||||
}
|
||||
|
||||
inline void evict(PipelineStateMtl* _ptr)
|
||||
{
|
||||
release(_ptr);
|
||||
}
|
||||
|
||||
struct VideoDecoderMtl;
|
||||
|
||||
struct TextureMtl
|
||||
@@ -530,6 +552,7 @@ namespace bgfx { namespace mtl
|
||||
, m_maxAnisotropy(0)
|
||||
, m_colorFormat(TextureFormat::Count)
|
||||
, m_borrowedDepth(false)
|
||||
, m_hdr10(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -557,6 +580,7 @@ namespace bgfx { namespace mtl
|
||||
void* m_nwh;
|
||||
TextureFormat::Enum m_colorFormat;
|
||||
bool m_borrowedDepth;
|
||||
bool m_hdr10;
|
||||
};
|
||||
|
||||
struct FrameBufferMtl
|
||||
@@ -598,9 +622,9 @@ namespace bgfx { namespace mtl
|
||||
CommandQueueMtl()
|
||||
: m_commandQueue(NULL)
|
||||
, m_activeCommandBuffer(NULL)
|
||||
, m_releaseWriteIndex(0)
|
||||
, m_releaseReadIndex(0)
|
||||
, m_maxFrameLatency(BGFX_CONFIG_MAX_FRAME_LATENCY)
|
||||
, m_submittedFrames(0)
|
||||
, m_completedFrames(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -621,11 +645,17 @@ namespace bgfx { namespace mtl
|
||||
MTL::CommandQueue* m_commandQueue;
|
||||
MTL::CommandBuffer* m_activeCommandBuffer;
|
||||
|
||||
int m_releaseWriteIndex;
|
||||
int m_releaseReadIndex;
|
||||
uint32_t m_maxFrameLatency;
|
||||
typedef stl::vector<NS::Object*> ResourceArray;
|
||||
ResourceArray m_release[BGFX_CONFIG_MAX_FRAME_LATENCY];
|
||||
uint32_t m_submittedFrames;
|
||||
volatile uint32_t m_completedFrames;
|
||||
struct Release
|
||||
{
|
||||
NS::Object* ptr;
|
||||
uint32_t frame;
|
||||
};
|
||||
|
||||
typedef stl::vector<Release> ReleaseArray;
|
||||
ReleaseArray m_release;
|
||||
};
|
||||
|
||||
struct TimerQueryMtl
|
||||
@@ -720,6 +750,7 @@ namespace bgfx { namespace mtl
|
||||
struct Query
|
||||
{
|
||||
OcclusionQueryHandle m_handle;
|
||||
uint32_t m_frame;
|
||||
};
|
||||
|
||||
MTL::Buffer* m_buffer;
|
||||
@@ -736,7 +767,7 @@ namespace bgfx
|
||||
{
|
||||
static void evict(Ty* _ptr)
|
||||
{
|
||||
mtl::release(_ptr);
|
||||
mtl::evict(_ptr);
|
||||
}
|
||||
|
||||
static void validate(Ty* /*_ptr*/, uint64_t /*_key*/)
|
||||
|
||||
Reference in New Issue
Block a user