feat: optional immersive rendering in visionOS (#3335)

* Implements optional code path for immersive rendering based on the type of nwh

* Reverted change in SwapChainMtl destructor
This commit is contained in:
Sim Saëns 2024-08-10 15:55:47 +09:30 committed by GitHub
parent 85726bcb53
commit 3f3d3b4433
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 311 additions and 220 deletions

View File

@ -390,10 +390,14 @@ namespace bgfx { namespace mtl
bool supportsTextureSampleCount(int sampleCount) bool supportsTextureSampleCount(int sampleCount)
{ {
if (BX_ENABLED(BX_PLATFORM_VISIONOS) || (BX_ENABLED(BX_PLATFORM_IOS) && !iOSVersionEqualOrGreater("9.0.0")) ) if (BX_ENABLED(BX_PLATFORM_IOS) && !iOSVersionEqualOrGreater("9.0.0"))
{
return sampleCount == 1 || sampleCount == 2 || sampleCount == 4; return sampleCount == 1 || sampleCount == 2 || sampleCount == 4;
}
else else
{
return [m_obj supportsTextureSampleCount:sampleCount]; return [m_obj supportsTextureSampleCount:sampleCount];
}
} }
bool depth24Stencil8PixelFormatSupported() bool depth24Stencil8PixelFormatSupported()
@ -1046,11 +1050,12 @@ namespace bgfx { namespace mtl
struct SwapChainMtl struct SwapChainMtl
{ {
SwapChainMtl() SwapChainMtl()
#if BX_PLATFORM_VISIONOS
: m_layerRenderer(NULL)
, m_frame(NULL)
#else
: m_metalLayer(nil) : m_metalLayer(nil)
#if BX_PLATFORM_VISIONOS
, m_layerRenderer(NULL)
, m_layerRendererDrawable(NULL)
, m_frame(NULL)
, m_useLayerRenderer(true)
#endif #endif
, m_drawable(nil) , m_drawable(nil)
, m_drawableTexture(nil) , m_drawableTexture(nil)
@ -1067,17 +1072,17 @@ namespace bgfx { namespace mtl
void resize(FrameBufferMtl &_frameBuffer, uint32_t _width, uint32_t _height, uint32_t _flags, uint32_t _maximumDrawableCount); void resize(FrameBufferMtl &_frameBuffer, uint32_t _width, uint32_t _height, uint32_t _flags, uint32_t _maximumDrawableCount);
id <MTLTexture> currentDrawableTexture(); id <MTLTexture> currentDrawableTexture();
#if BX_PLATFORM_VISIONOS
cp_layer_renderer_t m_layerRenderer;
cp_layer_renderer_configuration_t m_layerRendererConfiguration;
cp_frame_t m_frame;
cp_drawable_t m_drawable;
#else
CAMetalLayer* m_metalLayer; CAMetalLayer* m_metalLayer;
id <CAMetalDrawable> m_drawable; #if BX_PLATFORM_VISIONOS
cp_layer_renderer_t m_layerRenderer;
cp_drawable_t m_layerRendererDrawable;
cp_layer_renderer_configuration_t m_layerRendererConfiguration;
cp_frame_t m_frame;
bool m_useLayerRenderer;
#endif #endif
id <CAMetalDrawable> m_drawable;
id <MTLTexture> m_drawableTexture; id <MTLTexture> m_drawableTexture;
Texture m_backBufferColorMsaa; Texture m_backBufferColorMsaa;
Texture m_backBufferDepth; Texture m_backBufferDepth;

View File

@ -535,15 +535,20 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
); );
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
m_deviceAnchor = ar_device_anchor_create(); if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
m_worldTracking = ar_world_tracking_provider_create(ar_world_tracking_configuration_create()); {
m_arSession = ar_session_create(); m_deviceAnchor = ar_device_anchor_create();
ar_session_run(m_arSession, ar_data_providers_create_with_data_providers(m_worldTracking, nil)); m_worldTracking = ar_world_tracking_provider_create(ar_world_tracking_configuration_create());
m_arSession = ar_session_create();
ar_session_run(m_arSession, ar_data_providers_create_with_data_providers(m_worldTracking, nil));
}
#endif #endif
m_numWindows = 1; m_numWindows = 1;
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
if (NULL == m_mainFrameBuffer.m_swapChain->m_layerRenderer) if ((m_mainFrameBuffer.m_swapChain->m_useLayerRenderer
&& NULL == m_mainFrameBuffer.m_swapChain->m_layerRenderer)
|| NULL == m_mainFrameBuffer.m_swapChain->m_metalLayer)
#else #else
if (NULL == m_mainFrameBuffer.m_swapChain->m_metalLayer) if (NULL == m_mainFrameBuffer.m_swapChain->m_metalLayer)
#endif // BX_PLATFORM_VISIONOS #endif // BX_PLATFORM_VISIONOS
@ -612,8 +617,11 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
reset(m_renderPipelineDescriptor); reset(m_renderPipelineDescriptor);
m_renderPipelineDescriptor.colorAttachments[0].pixelFormat = getSwapChainPixelFormat(m_mainFrameBuffer.m_swapChain); m_renderPipelineDescriptor.colorAttachments[0].pixelFormat = getSwapChainPixelFormat(m_mainFrameBuffer.m_swapChain);
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
m_renderPipelineDescriptor.depthAttachmentPixelFormat = cp_layer_renderer_configuration_get_depth_format(m_mainFrameBuffer.m_swapChain->m_layerRendererConfiguration); if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
#endif {
m_renderPipelineDescriptor.depthAttachmentPixelFormat = cp_layer_renderer_configuration_get_depth_format(m_mainFrameBuffer.m_swapChain->m_layerRendererConfiguration);
}
#endif // BX_PLATFORM_VISIONOS
m_renderPipelineDescriptor.vertexFunction = m_screenshotBlitProgram.m_vsh->m_function; m_renderPipelineDescriptor.vertexFunction = m_screenshotBlitProgram.m_vsh->m_function;
m_renderPipelineDescriptor.fragmentFunction = m_screenshotBlitProgram.m_fsh->m_function; m_renderPipelineDescriptor.fragmentFunction = m_screenshotBlitProgram.m_fsh->m_function;
m_screenshotBlitRenderPipelineState = m_device.newRenderPipelineStateWithDescriptor(m_renderPipelineDescriptor); m_screenshotBlitRenderPipelineState = m_device.newRenderPipelineStateWithDescriptor(m_renderPipelineDescriptor);
@ -917,11 +925,14 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
MTL_RELEASE(m_samplerDescriptor); MTL_RELEASE(m_samplerDescriptor);
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
ar_session_stop(m_arSession); if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
MTL_RELEASE(m_arSession); {
MTL_RELEASE(m_worldTracking); ar_session_stop(m_arSession);
MTL_RELEASE(m_deviceAnchor); MTL_RELEASE(m_arSession);
#endif MTL_RELEASE(m_worldTracking);
MTL_RELEASE(m_deviceAnchor);
}
#endif // BX_PLATFORM_VISIONOS
m_mainFrameBuffer.destroy(); m_mainFrameBuffer.destroy();
@ -1060,11 +1071,14 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
MTLPixelFormat getSwapChainPixelFormat(SwapChainMtl *swapChain) MTLPixelFormat getSwapChainPixelFormat(SwapChainMtl *swapChain)
{ {
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
cp_layer_renderer_configuration_t layerConfiguration = cp_layer_renderer_get_configuration(swapChain->m_layerRenderer); if (swapChain->m_useLayerRenderer)
return cp_layer_renderer_configuration_get_color_format(layerConfiguration); {
#else cp_layer_renderer_configuration_t layerConfiguration = cp_layer_renderer_get_configuration(swapChain->m_layerRenderer);
return swapChain->m_metalLayer.pixelFormat; return cp_layer_renderer_configuration_get_color_format(layerConfiguration);
}
#endif // BX_PLATFORM_VISIONOS #endif // BX_PLATFORM_VISIONOS
return swapChain->m_metalLayer.pixelFormat;
} }
void readTexture(TextureHandle _handle, void* _data, uint8_t _mip) override void readTexture(TextureHandle _handle, void* _data, uint8_t _mip) override
@ -1319,7 +1333,7 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
void calculateViewPorts(MTLViewport (&viewports)[2]) { void calculateViewPorts(MTLViewport (&viewports)[2]) {
const int viewCount = 2; const int viewCount = 2;
for (int i = 0; i < viewCount; i++) { for (int i = 0; i < viewCount; i++) {
cp_view_t view = cp_drawable_get_view(m_mainFrameBuffer.m_swapChain->m_drawable, i); cp_view_t view = cp_drawable_get_view(m_mainFrameBuffer.m_swapChain->m_layerRendererDrawable, i);
cp_view_texture_map_t texture_map = cp_view_get_view_texture_map(view); cp_view_texture_map_t texture_map = cp_view_get_view_texture_map(view);
viewports[i] = cp_view_texture_map_get_viewport(texture_map); viewports[i] = cp_view_texture_map_get_viewport(texture_map);
} }
@ -1339,7 +1353,7 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
_rce.setVertexAmplificationCount(2, mappings); _rce.setVertexAmplificationCount(2, mappings);
} }
#endif #endif // BX_PLATFORM_VISIONOS
void blitRender(TextVideoMemBlitter& _blitter, uint32_t _numIndices) override void blitRender(TextVideoMemBlitter& _blitter, uint32_t _numIndices) override
{ {
@ -1383,19 +1397,24 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
MTL_RELEASE(renderPassDescriptor); MTL_RELEASE(renderPassDescriptor);
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
if (cp_layer_renderer_configuration_get_layout(m_mainFrameBuffer.m_swapChain->m_layerRendererConfiguration) == cp_layer_renderer_layout_layered) { if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
MTLViewport viewports[2]; {
calculateViewPorts(viewports); if (cp_layer_renderer_configuration_get_layout(m_mainFrameBuffer.m_swapChain->m_layerRendererConfiguration) == cp_layer_renderer_layout_layered) {
rce.setViewports(viewports, 2); MTLViewport viewports[2];
setVertexAmplification(rce); calculateViewPorts(viewports);
rce.setViewports(viewports, 2);
setVertexAmplification(rce);
}
}
else
#endif // BX_PLATFORM_VISIONOS
{
MTLViewport viewport = { 0.0f, 0.0f, (float)width, (float)height, 0.0f, 1.0f };
rce.setViewport(viewport);
MTLScissorRect rc = { 0, 0, width, height };
rce.setScissorRect(rc);
} }
#else
MTLViewport viewport = { 0.0f, 0.0f, (float)width, (float)height, 0.0f, 1.0f };
rce.setViewport(viewport);
MTLScissorRect rc = { 0, 0, width, height };
rce.setScissorRect(rc);
#endif
rce.setCullMode(MTLCullModeNone); rce.setCullMode(MTLCullModeNone);
@ -1479,7 +1498,7 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
BX_WARN(false, "Device anchor query failed.") BX_WARN(false, "Device anchor query failed.")
} }
} }
#endif #endif // BX_PLATFORM_VISIONOS
void flip() override void flip() override
{ {
@ -1496,21 +1515,27 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
{ {
MTL_RELEASE(frameBuffer.m_swapChain->m_drawableTexture); MTL_RELEASE(frameBuffer.m_swapChain->m_drawableTexture);
#if BX_PLATFORM_VISIONOS
if (frameBuffer.m_swapChain->m_useLayerRenderer)
{
if (NULL != frameBuffer.m_swapChain->m_layerRendererDrawable)
{
if (m_worldTracking != NULL)
{
auto timingInfo = cp_drawable_get_frame_timing(frameBuffer.m_swapChain->m_layerRendererDrawable);
createPoseForTiming(timingInfo, m_worldTracking);
cp_drawable_set_device_anchor(frameBuffer.m_swapChain->m_layerRendererDrawable, m_deviceAnchor);
}
cp_drawable_encode_present(frameBuffer.m_swapChain->m_layerRendererDrawable, m_commandBuffer);
cp_frame_end_submission(frameBuffer.m_swapChain->m_frame);
}
}
else
#endif // BX_PLATFORM_VISIONOS
if (NULL != frameBuffer.m_swapChain->m_drawable) if (NULL != frameBuffer.m_swapChain->m_drawable)
{ {
#if BX_PLATFORM_VISIONOS
if (m_worldTracking != NULL)
{
auto timingInfo = cp_drawable_get_frame_timing(frameBuffer.m_swapChain->m_drawable);
createPoseForTiming(timingInfo, m_worldTracking);
cp_drawable_set_device_anchor(frameBuffer.m_swapChain->m_drawable, m_deviceAnchor);
}
cp_drawable_encode_present(frameBuffer.m_swapChain->m_drawable, m_commandBuffer);
cp_frame_end_submission(frameBuffer.m_swapChain->m_frame);
#else
m_commandBuffer.presentDrawable(frameBuffer.m_swapChain->m_drawable); m_commandBuffer.presentDrawable(frameBuffer.m_swapChain->m_drawable);
MTL_RELEASE(frameBuffer.m_swapChain->m_drawable); MTL_RELEASE(frameBuffer.m_swapChain->m_drawable);
#endif // BX_PLATFORM_VISIONOS
} }
} }
} }
@ -1953,21 +1978,29 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
; ;
} }
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
Texture texture = cp_drawable_get_depth_texture(swapChain->m_drawable, 0); if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
_renderPassDescriptor.depthAttachment.texture = texture; {
_renderPassDescriptor.stencilAttachment.texture = swapChain->m_backBufferStencil; Texture texture = cp_drawable_get_depth_texture(swapChain->m_layerRendererDrawable, 0);
_renderPassDescriptor.depthAttachment.texture = texture;
cp_layer_renderer_configuration_t layerConfiguration = cp_layer_renderer_get_configuration(swapChain->m_layerRenderer); _renderPassDescriptor.stencilAttachment.texture = swapChain->m_backBufferStencil;
cp_layer_renderer_layout layout = cp_layer_renderer_configuration_get_layout(layerConfiguration);
if (layout == cp_layer_renderer_layout_layered) { cp_layer_renderer_configuration_t layerConfiguration = cp_layer_renderer_get_configuration(swapChain->m_layerRenderer);
_renderPassDescriptor.renderTargetArrayLength = cp_drawable_get_view_count(swapChain->m_drawable); cp_layer_renderer_layout layout = cp_layer_renderer_configuration_get_layout(layerConfiguration);
} else { if (layout == cp_layer_renderer_layout_layered)
_renderPassDescriptor.renderTargetArrayLength = 1; {
_renderPassDescriptor.renderTargetArrayLength = cp_drawable_get_view_count(swapChain->m_layerRendererDrawable);
}
else
{
_renderPassDescriptor.renderTargetArrayLength = 1;
}
}
else
#endif // BX_PLATFORM_VISIONOS
{
_renderPassDescriptor.depthAttachment.texture = swapChain->m_backBufferDepth;
_renderPassDescriptor.stencilAttachment.texture = swapChain->m_backBufferStencil;
} }
#else
_renderPassDescriptor.depthAttachment.texture = swapChain->m_backBufferDepth;
_renderPassDescriptor.stencilAttachment.texture = swapChain->m_backBufferStencil;
#endif
} }
else else
{ {
@ -2341,11 +2374,16 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
; ;
pd.colorAttachments[0].pixelFormat = swapChain->currentDrawableTexture().pixelFormat; pd.colorAttachments[0].pixelFormat = swapChain->currentDrawableTexture().pixelFormat;
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
pd.depthAttachmentPixelFormat = cp_layer_renderer_configuration_get_depth_format(swapChain->m_layerRendererConfiguration); if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
#else {
pd.depthAttachmentPixelFormat = swapChain->m_backBufferDepth.m_obj.pixelFormat; pd.depthAttachmentPixelFormat = cp_layer_renderer_configuration_get_depth_format(swapChain->m_layerRendererConfiguration);
#endif }
pd.stencilAttachmentPixelFormat = swapChain->m_backBufferStencil.m_obj.pixelFormat; else
#endif // BX_PLATFORM_VISIONOS
{
pd.depthAttachmentPixelFormat = swapChain->m_backBufferDepth.m_obj.pixelFormat;
}
pd.stencilAttachmentPixelFormat = swapChain->m_backBufferStencil.m_obj.pixelFormat;
} }
else else
{ {
@ -2445,9 +2483,13 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
pd.vertexFunction = program.m_vsh->m_function; pd.vertexFunction = program.m_vsh->m_function;
pd.fragmentFunction = program.m_fsh != NULL ? program.m_fsh->m_function : NULL; pd.fragmentFunction = program.m_fsh != NULL ? program.m_fsh->m_function : NULL;
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
if (cp_layer_renderer_configuration_get_layout(m_mainFrameBuffer.m_swapChain->m_layerRendererConfiguration) == cp_layer_renderer_layout_layered) { if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
auto properties = cp_layer_renderer_get_properties(m_mainFrameBuffer.m_swapChain->m_layerRenderer); {
pd.maxVertexAmplificationCount = cp_layer_renderer_properties_get_view_count(properties); if (cp_layer_renderer_configuration_get_layout(m_mainFrameBuffer.m_swapChain->m_layerRendererConfiguration) == cp_layer_renderer_layout_layered)
{
auto properties = cp_layer_renderer_get_properties(m_mainFrameBuffer.m_swapChain->m_layerRenderer);
pd.maxVertexAmplificationCount = cp_layer_renderer_properties_get_view_count(properties);
}
} }
#endif #endif
@ -3437,6 +3479,9 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
void SwapChainMtl::init(void* _nwh) void SwapChainMtl::init(void* _nwh)
{ {
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
NSObject* nvh = (NSObject*)_nwh;
m_useLayerRenderer = ![nvh isKindOfClass:[CAMetalLayer class]];
if (m_useLayerRenderer)
{ {
cp_layer_renderer_t layerRenderer = (cp_layer_renderer_t)_nwh; cp_layer_renderer_t layerRenderer = (cp_layer_renderer_t)_nwh;
m_layerRenderer = layerRenderer; m_layerRenderer = layerRenderer;
@ -3449,113 +3494,115 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
retain(m_layerRendererConfiguration); retain(m_layerRendererConfiguration);
retain(m_layerRenderer); retain(m_layerRenderer);
} }
#else else
if (m_metalLayer) #endif // BX_PLATFORM_VISIONOS
{ {
release(m_metalLayer); if (m_metalLayer)
}
if (NULL != NSClassFromString(@"MTKView") )
{
MTKView *view = (MTKView *)_nwh;
if (NULL != view
&& [view isKindOfClass:NSClassFromString(@"MTKView")])
{ {
m_metalLayer = (CAMetalLayer *)view.layer; release(m_metalLayer);
} }
}
if (NULL != NSClassFromString(@"MTKView") )
if (NULL != NSClassFromString(@"CAMetalLayer") )
{
if (NULL == m_metalLayer)
# if BX_PLATFORM_IOS
{ {
CAMetalLayer* metalLayer = (CAMetalLayer*)_nwh; MTKView *view = (MTKView *)_nwh;
if (NULL == metalLayer
|| ![metalLayer isKindOfClass:NSClassFromString(@"CAMetalLayer")]) if (NULL != view
&& [view isKindOfClass:NSClassFromString(@"MTKView")])
{ {
BX_WARN(false, "Unable to create Metal device. Please set platform data window to a CAMetalLayer"); m_metalLayer = (CAMetalLayer *)view.layer;
return;
} }
m_metalLayer = metalLayer;
} }
# elif BX_PLATFORM_OSX
if (NULL != NSClassFromString(@"CAMetalLayer") )
{ {
NSObject* nvh = (NSObject*)_nwh; if (NULL == m_metalLayer)
if ([nvh isKindOfClass:[CAMetalLayer class]]) # if BX_PLATFORM_IOS || BX_PLATFORM_VISIONOS
{ {
CAMetalLayer* metalLayer = (CAMetalLayer*)_nwh; CAMetalLayer* metalLayer = (CAMetalLayer*)_nwh;
if (NULL == metalLayer
|| ![metalLayer isKindOfClass:NSClassFromString(@"CAMetalLayer")])
{
BX_WARN(false, "Unable to create Metal device. Please set platform data window to a CAMetalLayer");
return;
}
m_metalLayer = metalLayer; m_metalLayer = metalLayer;
} }
else # elif BX_PLATFORM_OSX
{ {
NSView *contentView; NSObject* nvh = (NSObject*)_nwh;
if ([nvh isKindOfClass:[CAMetalLayer class]])
if ([nvh isKindOfClass:[NSView class]])
{ {
contentView = (NSView*)nvh; CAMetalLayer* metalLayer = (CAMetalLayer*)_nwh;
} m_metalLayer = metalLayer;
else if ([nvh isKindOfClass:[NSWindow class]])
{
NSWindow* nsWindow = (NSWindow*)nvh;
contentView = [nsWindow contentView];
} }
else else
{ {
BX_WARN(0, "Unable to create Metal device. Please set platform data window to an NSWindow, NSView, or CAMetalLayer"); NSView *contentView;
return;
} if ([nvh isKindOfClass:[NSView class]])
void (^setLayer)(void) = ^{
CALayer* layer = contentView.layer;
if(NULL != layer && [layer isKindOfClass:NSClassFromString(@"CAMetalLayer")])
{ {
m_metalLayer = (CAMetalLayer*)layer; contentView = (NSView*)nvh;
}
else if ([nvh isKindOfClass:[NSWindow class]])
{
NSWindow* nsWindow = (NSWindow*)nvh;
contentView = [nsWindow contentView];
} }
else else
{ {
[contentView setWantsLayer:YES]; BX_WARN(0, "Unable to create Metal device. Please set platform data window to an NSWindow, NSView, or CAMetalLayer");
m_metalLayer = [CAMetalLayer layer]; return;
[contentView setLayer:m_metalLayer]; }
void (^setLayer)(void) = ^{
CALayer* layer = contentView.layer;
if(NULL != layer && [layer isKindOfClass:NSClassFromString(@"CAMetalLayer")])
{
m_metalLayer = (CAMetalLayer*)layer;
}
else
{
[contentView setWantsLayer:YES];
m_metalLayer = [CAMetalLayer layer];
[contentView setLayer:m_metalLayer];
}
};
if ([NSThread isMainThread])
{
setLayer();
}
else
{
bx::Semaphore semaphore;
bx::Semaphore* psemaphore = &semaphore;
CFRunLoopPerformBlock([[NSRunLoop mainRunLoop] getCFRunLoop],
kCFRunLoopCommonModes,
^{
setLayer();
psemaphore->post();
});
semaphore.wait();
} }
};
if ([NSThread isMainThread])
{
setLayer();
}
else
{
bx::Semaphore semaphore;
bx::Semaphore* psemaphore = &semaphore;
CFRunLoopPerformBlock([[NSRunLoop mainRunLoop] getCFRunLoop],
kCFRunLoopCommonModes,
^{
setLayer();
psemaphore->post();
});
semaphore.wait();
} }
} }
}
# endif // BX_PLATFORM_* # endif // BX_PLATFORM_*
}
if (NULL == m_metalLayer)
{
BX_WARN(NULL != s_renderMtl->m_device, "Unable to create Metal device.");
return;
}
m_metalLayer.device = s_renderMtl->m_device;
m_metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
m_metalLayer.magnificationFilter = kCAFilterNearest;
retain(m_metalLayer);
} }
if (NULL == m_metalLayer)
{
BX_WARN(NULL != s_renderMtl->m_device, "Unable to create Metal device.");
return;
}
m_metalLayer.device = s_renderMtl->m_device;
m_metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
m_metalLayer.magnificationFilter = kCAFilterNearest;
retain(m_metalLayer);
#endif // BX_PLATFORM_VISIONOS
m_nwh = _nwh; m_nwh = _nwh;
} }
@ -3581,13 +3628,16 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
# endif // __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 # endif // __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
#endif // BX_PLATFORM_OSX #endif // BX_PLATFORM_OSX
#if !BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
m_metalLayer.drawableSize = CGSizeMake(_width, _height); if (!m_useLayerRenderer)
m_metalLayer.pixelFormat = (_flags & BGFX_RESET_SRGB_BACKBUFFER) #endif // BX_PLATFORM_VISIONOS
{
m_metalLayer.drawableSize = CGSizeMake(_width, _height);
m_metalLayer.pixelFormat = (_flags & BGFX_RESET_SRGB_BACKBUFFER)
? MTLPixelFormatBGRA8Unorm_sRGB ? MTLPixelFormatBGRA8Unorm_sRGB
: MTLPixelFormatBGRA8Unorm : MTLPixelFormatBGRA8Unorm
; ;
#endif // BX_PLATFORM_VISIONOS }
TextureDescriptor desc = s_renderMtl->m_textureDescriptor; TextureDescriptor desc = s_renderMtl->m_textureDescriptor;
@ -3622,12 +3672,18 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
} }
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
if (m_drawable) { if (m_useLayerRenderer)
m_backBufferDepth = cp_drawable_get_depth_texture(m_drawable, 0); {
if (m_layerRendererDrawable)
{
m_backBufferDepth = cp_drawable_get_depth_texture(m_layerRendererDrawable, 0);
}
}
else
#endif // BX_PLATFORM_VISIONOS
{
m_backBufferDepth = s_renderMtl->m_device.newTextureWithDescriptor(desc);
} }
#else
m_backBufferDepth = s_renderMtl->m_device.newTextureWithDescriptor(desc);
#endif
if (NULL != m_backBufferStencil) if (NULL != m_backBufferStencil)
{ {
release(m_backBufferStencil); release(m_backBufferStencil);
@ -3653,19 +3709,27 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
if (sampleCount > 1) if (sampleCount > 1)
{ {
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
desc.pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB; if (m_useLayerRenderer)
#else {
desc.pixelFormat = m_metalLayer.pixelFormat; desc.pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
}
else
#endif // BX_PLATFORM_VISIONOS #endif // BX_PLATFORM_VISIONOS
{
desc.pixelFormat = m_metalLayer.pixelFormat;
}
m_backBufferColorMsaa = s_renderMtl->m_device.newTextureWithDescriptor(desc); m_backBufferColorMsaa = s_renderMtl->m_device.newTextureWithDescriptor(desc);
} }
bx::HashMurmur2A murmur; bx::HashMurmur2A murmur;
murmur.begin(); murmur.begin();
murmur.add(1); murmur.add(1);
#if !BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
murmur.add( (uint32_t)m_metalLayer.pixelFormat); if (!m_useLayerRenderer)
#endif // !BX_PLATFORM_VISIONOS #endif // !BX_PLATFORM_VISIONOS
{
murmur.add( (uint32_t)m_metalLayer.pixelFormat);
}
murmur.add( (uint32_t)m_backBufferDepth.pixelFormat() ); murmur.add( (uint32_t)m_backBufferDepth.pixelFormat() );
murmur.add( (uint32_t)m_backBufferStencil.pixelFormat() ); murmur.add( (uint32_t)m_backBufferStencil.pixelFormat() );
murmur.add( (uint32_t)sampleCount); murmur.add( (uint32_t)sampleCount);
@ -3677,33 +3741,44 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
if (NULL == m_drawableTexture) if (NULL == m_drawableTexture)
{ {
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
m_frame = cp_layer_renderer_query_next_frame(m_layerRenderer); if (m_useLayerRenderer)
if (m_frame)
{ {
cp_frame_timing_t timing = cp_frame_predict_timing(m_frame); m_frame = cp_layer_renderer_query_next_frame(m_layerRenderer);
if (timing == nullptr) { return nullptr; } if (m_frame)
{
cp_frame_start_update(m_frame); cp_frame_timing_t timing = cp_frame_predict_timing(m_frame);
if (timing == nullptr) { return nullptr; }
cp_frame_end_update(m_frame);
cp_frame_start_update(m_frame);
cp_time_wait_until(cp_frame_timing_get_optimal_input_time(timing));
cp_frame_start_submission(m_frame); cp_frame_end_update(m_frame);
m_drawable = cp_frame_query_drawable(m_frame);
cp_time_wait_until(cp_frame_timing_get_optimal_input_time(timing));
cp_frame_start_submission(m_frame);
m_layerRendererDrawable = cp_frame_query_drawable(m_frame);
}
} }
#else else
m_drawable = m_metalLayer.nextDrawable;
#endif // BX_PLATFORM_VISIONOS #endif // BX_PLATFORM_VISIONOS
{
m_drawable = m_metalLayer.nextDrawable;
}
#if BX_PLATFORM_VISIONOS
if (m_useLayerRenderer)
{
if (m_layerRendererDrawable != NULL)
{
m_drawableTexture = cp_drawable_get_color_texture(m_layerRendererDrawable, 0);
retain(m_drawableTexture);
}
}
else
#endif // BX_PLATFORM_VISIONOS
if (m_drawable != NULL) if (m_drawable != NULL)
{ {
#if BX_PLATFORM_VISIONOS
m_drawableTexture = cp_drawable_get_color_texture(m_drawable, 0);
#else
m_drawableTexture = m_drawable.texture; m_drawableTexture = m_drawable.texture;
retain(m_drawable); // keep alive to be useable at 'flip' retain(m_drawable); // keep alive to be useable at 'flip'
#endif // BX_PLATFORM_VISIONOS
retain(m_drawableTexture); retain(m_drawableTexture);
} }
else else
@ -3712,12 +3787,17 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
desc.textureType = MTLTextureType2D; desc.textureType = MTLTextureType2D;
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
desc.pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB; if (m_useLayerRenderer)
#else {
desc.pixelFormat = m_metalLayer.pixelFormat; desc.pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
desc.width = m_metalLayer.drawableSize.width; }
desc.height = m_metalLayer.drawableSize.height; else
#endif // BX_PLATFORM_VISIONOS #endif // BX_PLATFORM_VISIONOS
{
desc.pixelFormat = m_metalLayer.pixelFormat;
desc.width = m_metalLayer.drawableSize.width;
desc.height = m_metalLayer.drawableSize.height;
}
desc.depth = 1; desc.depth = 1;
desc.mipmapLevelCount = 1; desc.mipmapLevelCount = 1;
@ -4513,31 +4593,37 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
rce.setTriangleFillMode(wireframe ? MTLTriangleFillModeLines : MTLTriangleFillModeFill); rce.setTriangleFillMode(wireframe ? MTLTriangleFillModeLines : MTLTriangleFillModeFill);
#if BX_PLATFORM_VISIONOS #if BX_PLATFORM_VISIONOS
if (cp_layer_renderer_configuration_get_layout(m_mainFrameBuffer.m_swapChain->m_layerRendererConfiguration) == cp_layer_renderer_layout_layered) { if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
MTLViewport viewports[2]; {
calculateViewPorts(viewports); if (cp_layer_renderer_configuration_get_layout(m_mainFrameBuffer.m_swapChain->m_layerRendererConfiguration) == cp_layer_renderer_layout_layered)
rce.setViewports(viewports, 1); {
setVertexAmplification(rce); MTLViewport viewports[2];
calculateViewPorts(viewports);
rce.setViewports(viewports, 1);
setVertexAmplification(rce);
}
} }
#else else
MTLViewport vp; #endif // BX_PLATFORM_VISIONOS
vp.originX = viewState.m_rect.m_x; {
vp.originY = viewState.m_rect.m_y; MTLViewport vp;
vp.width = viewState.m_rect.m_width; vp.originX = viewState.m_rect.m_x;
vp.height = viewState.m_rect.m_height; vp.originY = viewState.m_rect.m_y;
vp.znear = 0.0f; vp.width = viewState.m_rect.m_width;
vp.zfar = 1.0f; vp.height = viewState.m_rect.m_height;
rce.setViewport(vp); vp.znear = 0.0f;
vp.zfar = 1.0f;
MTLScissorRect sciRect = { rce.setViewport(vp);
viewState.m_rect.m_x,
viewState.m_rect.m_y, MTLScissorRect sciRect = {
viewState.m_rect.m_width, viewState.m_rect.m_x,
viewState.m_rect.m_height viewState.m_rect.m_y,
}; viewState.m_rect.m_width,
rce.setScissorRect(sciRect); viewState.m_rect.m_height
};
#endif rce.setScissorRect(sciRect);
}
if (BGFX_CLEAR_NONE != (clr.m_flags & BGFX_CLEAR_MASK) if (BGFX_CLEAR_NONE != (clr.m_flags & BGFX_CLEAR_MASK)
&& !clearWithRenderPass) && !clearWithRenderPass)
{ {