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,11 +390,15 @@ namespace bgfx { namespace mtl
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;
}
else
{
return [m_obj supportsTextureSampleCount:sampleCount];
}
}
bool depth24Stencil8PixelFormatSupported()
{
@ -1046,11 +1050,12 @@ namespace bgfx { namespace mtl
struct SwapChainMtl
{
SwapChainMtl()
#if BX_PLATFORM_VISIONOS
: m_layerRenderer(NULL)
, m_frame(NULL)
#else
: m_metalLayer(nil)
#if BX_PLATFORM_VISIONOS
, m_layerRenderer(NULL)
, m_layerRendererDrawable(NULL)
, m_frame(NULL)
, m_useLayerRenderer(true)
#endif
, m_drawable(nil)
, m_drawableTexture(nil)
@ -1068,16 +1073,16 @@ namespace bgfx { namespace mtl
id <MTLTexture> currentDrawableTexture();
CAMetalLayer* m_metalLayer;
#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;
cp_drawable_t m_drawable;
#else
CAMetalLayer* m_metalLayer;
id <CAMetalDrawable> m_drawable;
bool m_useLayerRenderer;
#endif
id <CAMetalDrawable> m_drawable;
id <MTLTexture> m_drawableTexture;
Texture m_backBufferColorMsaa;
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 (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
{
m_deviceAnchor = ar_device_anchor_create();
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
m_numWindows = 1;
#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
if (NULL == m_mainFrameBuffer.m_swapChain->m_metalLayer)
#endif // BX_PLATFORM_VISIONOS
@ -612,8 +617,11 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
reset(m_renderPipelineDescriptor);
m_renderPipelineDescriptor.colorAttachments[0].pixelFormat = getSwapChainPixelFormat(m_mainFrameBuffer.m_swapChain);
#if BX_PLATFORM_VISIONOS
if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
{
m_renderPipelineDescriptor.depthAttachmentPixelFormat = cp_layer_renderer_configuration_get_depth_format(m_mainFrameBuffer.m_swapChain->m_layerRendererConfiguration);
#endif
}
#endif // BX_PLATFORM_VISIONOS
m_renderPipelineDescriptor.vertexFunction = m_screenshotBlitProgram.m_vsh->m_function;
m_renderPipelineDescriptor.fragmentFunction = m_screenshotBlitProgram.m_fsh->m_function;
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);
#if BX_PLATFORM_VISIONOS
if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
{
ar_session_stop(m_arSession);
MTL_RELEASE(m_arSession);
MTL_RELEASE(m_worldTracking);
MTL_RELEASE(m_deviceAnchor);
#endif
}
#endif // BX_PLATFORM_VISIONOS
m_mainFrameBuffer.destroy();
@ -1060,11 +1071,14 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
MTLPixelFormat getSwapChainPixelFormat(SwapChainMtl *swapChain)
{
#if BX_PLATFORM_VISIONOS
if (swapChain->m_useLayerRenderer)
{
cp_layer_renderer_configuration_t layerConfiguration = cp_layer_renderer_get_configuration(swapChain->m_layerRenderer);
return cp_layer_renderer_configuration_get_color_format(layerConfiguration);
#else
return swapChain->m_metalLayer.pixelFormat;
}
#endif // BX_PLATFORM_VISIONOS
return swapChain->m_metalLayer.pixelFormat;
}
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]) {
const int viewCount = 2;
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);
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);
}
#endif
#endif // BX_PLATFORM_VISIONOS
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);
#if BX_PLATFORM_VISIONOS
if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
{
if (cp_layer_renderer_configuration_get_layout(m_mainFrameBuffer.m_swapChain->m_layerRendererConfiguration) == cp_layer_renderer_layout_layered) {
MTLViewport viewports[2];
calculateViewPorts(viewports);
rce.setViewports(viewports, 2);
setVertexAmplification(rce);
}
#else
}
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);
#endif
}
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.")
}
}
#endif
#endif // BX_PLATFORM_VISIONOS
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);
if (NULL != frameBuffer.m_swapChain->m_drawable)
{
#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_drawable);
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_drawable, m_deviceAnchor);
cp_drawable_set_device_anchor(frameBuffer.m_swapChain->m_layerRendererDrawable, m_deviceAnchor);
}
cp_drawable_encode_present(frameBuffer.m_swapChain->m_drawable, m_commandBuffer);
cp_drawable_encode_present(frameBuffer.m_swapChain->m_layerRendererDrawable, m_commandBuffer);
cp_frame_end_submission(frameBuffer.m_swapChain->m_frame);
#else
}
}
else
#endif // BX_PLATFORM_VISIONOS
if (NULL != frameBuffer.m_swapChain->m_drawable)
{
m_commandBuffer.presentDrawable(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
Texture texture = cp_drawable_get_depth_texture(swapChain->m_drawable, 0);
if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
{
Texture texture = cp_drawable_get_depth_texture(swapChain->m_layerRendererDrawable, 0);
_renderPassDescriptor.depthAttachment.texture = texture;
_renderPassDescriptor.stencilAttachment.texture = swapChain->m_backBufferStencil;
cp_layer_renderer_configuration_t layerConfiguration = cp_layer_renderer_get_configuration(swapChain->m_layerRenderer);
cp_layer_renderer_layout layout = cp_layer_renderer_configuration_get_layout(layerConfiguration);
if (layout == cp_layer_renderer_layout_layered) {
_renderPassDescriptor.renderTargetArrayLength = cp_drawable_get_view_count(swapChain->m_drawable);
} else {
if (layout == cp_layer_renderer_layout_layered)
{
_renderPassDescriptor.renderTargetArrayLength = cp_drawable_get_view_count(swapChain->m_layerRendererDrawable);
}
else
{
_renderPassDescriptor.renderTargetArrayLength = 1;
}
#else
}
else
#endif // BX_PLATFORM_VISIONOS
{
_renderPassDescriptor.depthAttachment.texture = swapChain->m_backBufferDepth;
_renderPassDescriptor.stencilAttachment.texture = swapChain->m_backBufferStencil;
#endif
}
}
else
{
@ -2341,10 +2374,15 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
;
pd.colorAttachments[0].pixelFormat = swapChain->currentDrawableTexture().pixelFormat;
#if BX_PLATFORM_VISIONOS
if (m_mainFrameBuffer.m_swapChain->m_useLayerRenderer)
{
pd.depthAttachmentPixelFormat = cp_layer_renderer_configuration_get_depth_format(swapChain->m_layerRendererConfiguration);
#else
}
else
#endif // BX_PLATFORM_VISIONOS
{
pd.depthAttachmentPixelFormat = swapChain->m_backBufferDepth.m_obj.pixelFormat;
#endif
}
pd.stencilAttachmentPixelFormat = swapChain->m_backBufferStencil.m_obj.pixelFormat;
}
else
@ -2445,10 +2483,14 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
pd.vertexFunction = program.m_vsh->m_function;
pd.fragmentFunction = program.m_fsh != NULL ? program.m_fsh->m_function : NULL;
#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)
{
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
VertexDescriptor vertexDesc = m_vertexDescriptor;
@ -3437,6 +3479,9 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
void SwapChainMtl::init(void* _nwh)
{
#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;
m_layerRenderer = layerRenderer;
@ -3449,7 +3494,9 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
retain(m_layerRendererConfiguration);
retain(m_layerRenderer);
}
#else
else
#endif // BX_PLATFORM_VISIONOS
{
if (m_metalLayer)
{
release(m_metalLayer);
@ -3469,7 +3516,7 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
if (NULL != NSClassFromString(@"CAMetalLayer") )
{
if (NULL == m_metalLayer)
# if BX_PLATFORM_IOS
# if BX_PLATFORM_IOS || BX_PLATFORM_VISIONOS
{
CAMetalLayer* metalLayer = (CAMetalLayer*)_nwh;
if (NULL == metalLayer
@ -3554,7 +3601,7 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
m_metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
m_metalLayer.magnificationFilter = kCAFilterNearest;
retain(m_metalLayer);
#endif // BX_PLATFORM_VISIONOS
}
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 // BX_PLATFORM_OSX
#if !BX_PLATFORM_VISIONOS
#if BX_PLATFORM_VISIONOS
if (!m_useLayerRenderer)
#endif // BX_PLATFORM_VISIONOS
{
m_metalLayer.drawableSize = CGSizeMake(_width, _height);
m_metalLayer.pixelFormat = (_flags & BGFX_RESET_SRGB_BACKBUFFER)
? MTLPixelFormatBGRA8Unorm_sRGB
: MTLPixelFormatBGRA8Unorm
;
#endif // BX_PLATFORM_VISIONOS
}
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 (m_drawable) {
m_backBufferDepth = cp_drawable_get_depth_texture(m_drawable, 0);
if (m_useLayerRenderer)
{
if (m_layerRendererDrawable)
{
m_backBufferDepth = cp_drawable_get_depth_texture(m_layerRendererDrawable, 0);
}
#else
}
else
#endif // BX_PLATFORM_VISIONOS
{
m_backBufferDepth = s_renderMtl->m_device.newTextureWithDescriptor(desc);
#endif
}
if (NULL != 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 BX_PLATFORM_VISIONOS
if (m_useLayerRenderer)
{
desc.pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
#else
desc.pixelFormat = m_metalLayer.pixelFormat;
}
else
#endif // BX_PLATFORM_VISIONOS
{
desc.pixelFormat = m_metalLayer.pixelFormat;
}
m_backBufferColorMsaa = s_renderMtl->m_device.newTextureWithDescriptor(desc);
}
bx::HashMurmur2A murmur;
murmur.begin();
murmur.add(1);
#if !BX_PLATFORM_VISIONOS
murmur.add( (uint32_t)m_metalLayer.pixelFormat);
#if BX_PLATFORM_VISIONOS
if (!m_useLayerRenderer)
#endif // !BX_PLATFORM_VISIONOS
{
murmur.add( (uint32_t)m_metalLayer.pixelFormat);
}
murmur.add( (uint32_t)m_backBufferDepth.pixelFormat() );
murmur.add( (uint32_t)m_backBufferStencil.pixelFormat() );
murmur.add( (uint32_t)sampleCount);
@ -3677,6 +3741,8 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
if (NULL == m_drawableTexture)
{
#if BX_PLATFORM_VISIONOS
if (m_useLayerRenderer)
{
m_frame = cp_layer_renderer_query_next_frame(m_layerRenderer);
if (m_frame)
{
@ -3689,21 +3755,30 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
cp_time_wait_until(cp_frame_timing_get_optimal_input_time(timing));
cp_frame_start_submission(m_frame);
m_drawable = cp_frame_query_drawable(m_frame);
m_layerRendererDrawable = cp_frame_query_drawable(m_frame);
}
#else
m_drawable = m_metalLayer.nextDrawable;
}
else
#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 BX_PLATFORM_VISIONOS
m_drawableTexture = cp_drawable_get_color_texture(m_drawable, 0);
#else
m_drawableTexture = m_drawable.texture;
retain(m_drawable); // keep alive to be useable at 'flip'
#endif // BX_PLATFORM_VISIONOS
retain(m_drawableTexture);
}
else
@ -3712,12 +3787,17 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
desc.textureType = MTLTextureType2D;
#if BX_PLATFORM_VISIONOS
if (m_useLayerRenderer)
{
desc.pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
#else
}
else
#endif // BX_PLATFORM_VISIONOS
{
desc.pixelFormat = m_metalLayer.pixelFormat;
desc.width = m_metalLayer.drawableSize.width;
desc.height = m_metalLayer.drawableSize.height;
#endif // BX_PLATFORM_VISIONOS
}
desc.depth = 1;
desc.mipmapLevelCount = 1;
@ -4513,13 +4593,19 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
rce.setTriangleFillMode(wireframe ? MTLTriangleFillModeLines : MTLTriangleFillModeFill);
#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)
{
if (cp_layer_renderer_configuration_get_layout(m_mainFrameBuffer.m_swapChain->m_layerRendererConfiguration) == cp_layer_renderer_layout_layered)
{
MTLViewport viewports[2];
calculateViewPorts(viewports);
rce.setViewports(viewports, 1);
setVertexAmplification(rce);
}
#else
}
else
#endif // BX_PLATFORM_VISIONOS
{
MTLViewport vp;
vp.originX = viewState.m_rect.m_x;
vp.originY = viewState.m_rect.m_y;
@ -4536,8 +4622,8 @@ BX_STATIC_ASSERT(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNa
viewState.m_rect.m_height
};
rce.setScissorRect(sciRect);
}
#endif
if (BGFX_CLEAR_NONE != (clr.m_flags & BGFX_CLEAR_MASK)
&& !clearWithRenderPass)
{