Skip to content

Commit d0a9eeb

Browse files
committed
feat: add visionOS examples
1 parent 85b33a0 commit d0a9eeb

File tree

6 files changed

+335
-2
lines changed

6 files changed

+335
-2
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import SwiftUI
2+
import CompositorServices
3+
4+
// Default configuration
5+
struct ContentStageConfiguration: CompositorLayerConfiguration {
6+
func makeConfiguration(capabilities: LayerRenderer.Capabilities, configuration: inout LayerRenderer.Configuration) {
7+
configuration.depthFormat = .depth32Float
8+
configuration.colorFormat = .bgra8Unorm_srgb
9+
10+
let foveationEnabled = capabilities.supportsFoveation
11+
configuration.isFoveationEnabled = foveationEnabled
12+
13+
let options: LayerRenderer.Capabilities.SupportedLayoutsOptions = foveationEnabled ? [.foveationEnabled] : []
14+
let supportedLayouts = capabilities.supportedLayouts(options: options)
15+
16+
configuration.layout = supportedLayouts.contains(.layered) ? .layered : .dedicated
17+
}
18+
}
19+
20+
@main
21+
struct ExampleApp: App {
22+
var body: some Scene {
23+
ImmersiveSpace {
24+
CompositorLayer(configuration: ContentStageConfiguration()) { layerRenderer in
25+
let renderThread = Thread {
26+
var engine = BgfxAdapter(layerRenderer)
27+
engine.renderLoop()
28+
}
29+
renderThread.name = "Render Thread"
30+
renderThread.start()
31+
}
32+
}
33+
}
34+
}
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
#include "entry_p.h"
2+
3+
#if ENTRY_CONFIG_USE_NATIVE && BX_PLATFORM_VISIONOS
4+
5+
#include "swift_adapter.h"
6+
7+
#include <bgfx/platform.h>
8+
#include <bx/uint32_t.h>
9+
#include <bx/thread.h>
10+
11+
namespace entry
12+
{
13+
struct MainThreadEntry
14+
{
15+
int m_argc;
16+
const char* const* m_argv;
17+
18+
static int32_t threadFunc(bx::Thread* _thread, void* _userData);
19+
};
20+
21+
static WindowHandle s_defaultWindow = { 0 };
22+
23+
struct Context
24+
{
25+
Context(uint32_t _width, uint32_t _height)
26+
{
27+
static const char* const argv[] = { "visionos" };
28+
m_mte.m_argc = BX_COUNTOF(argv);
29+
m_mte.m_argv = argv;
30+
31+
m_eventQueue.postSizeEvent(s_defaultWindow, _width, _height);
32+
33+
34+
// Prevent render thread creation.
35+
bgfx::renderFrame();
36+
37+
m_thread.init(MainThreadEntry::threadFunc, &m_mte);
38+
}
39+
40+
41+
~Context()
42+
{
43+
m_thread.shutdown();
44+
}
45+
46+
MainThreadEntry m_mte;
47+
bx::Thread m_thread;
48+
void* m_window;
49+
50+
EventQueue m_eventQueue;
51+
};
52+
53+
static Context* s_ctx;
54+
55+
int32_t MainThreadEntry::threadFunc(bx::Thread* _thread, void* _userData)
56+
{
57+
BX_UNUSED(_thread);
58+
59+
if (_thread != NULL) {
60+
_thread->setThreadName("Main Thread BGFX");
61+
}
62+
63+
CFBundleRef mainBundle = CFBundleGetMainBundle();
64+
if (mainBundle != nil)
65+
{
66+
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
67+
if (resourcesURL != nil)
68+
{
69+
char path[PATH_MAX];
70+
if (CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8*)path, PATH_MAX) )
71+
{
72+
chdir(path);
73+
}
74+
75+
CFRelease(resourcesURL);
76+
}
77+
}
78+
79+
MainThreadEntry* self = (MainThreadEntry*)_userData;
80+
int32_t result = main(self->m_argc, self->m_argv);
81+
return result;
82+
}
83+
84+
const Event* poll()
85+
{
86+
return s_ctx->m_eventQueue.poll();
87+
}
88+
89+
const Event* poll(WindowHandle _handle)
90+
{
91+
return s_ctx->m_eventQueue.poll(_handle);
92+
}
93+
94+
void release(const Event* _event)
95+
{
96+
s_ctx->m_eventQueue.release(_event);
97+
}
98+
99+
WindowHandle createWindow(int32_t _x, int32_t _y, uint32_t _width, uint32_t _height, uint32_t _flags, const char* _title)
100+
{
101+
BX_UNUSED(_x, _y, _width, _height, _flags, _title);
102+
WindowHandle handle = { UINT16_MAX };
103+
return handle;
104+
}
105+
106+
void destroyWindow(WindowHandle _handle)
107+
{
108+
BX_UNUSED(_handle);
109+
}
110+
111+
void setWindowPos(WindowHandle _handle, int32_t _x, int32_t _y)
112+
{
113+
BX_UNUSED(_handle, _x, _y);
114+
}
115+
116+
void setWindowSize(WindowHandle _handle, uint32_t _width, uint32_t _height)
117+
{
118+
BX_UNUSED(_handle, _width, _height);
119+
}
120+
121+
void setWindowTitle(WindowHandle _handle, const char* _title)
122+
{
123+
BX_UNUSED(_handle, _title);
124+
}
125+
126+
void setWindowFlags(WindowHandle _handle, uint32_t _flags, bool _enabled)
127+
{
128+
BX_UNUSED(_handle, _flags, _enabled);
129+
}
130+
131+
void toggleFullscreen(WindowHandle _handle)
132+
{
133+
BX_UNUSED(_handle);
134+
}
135+
136+
void setMouseLock(WindowHandle _handle, bool _lock)
137+
{
138+
BX_UNUSED(_handle, _lock);
139+
}
140+
141+
void* getNativeWindowHandle(WindowHandle _handle)
142+
{
143+
if (kDefaultWindowHandle.idx == _handle.idx)
144+
{
145+
return s_ctx->m_window;
146+
}
147+
148+
return NULL;
149+
}
150+
151+
void* getNativeDisplayHandle()
152+
{
153+
return NULL;
154+
}
155+
156+
bgfx::NativeWindowHandleType::Enum getNativeWindowHandleType()
157+
{
158+
return bgfx::NativeWindowHandleType::Default;
159+
}
160+
161+
} // namespace entry
162+
163+
using namespace entry;
164+
165+
bool BgfxAdapter::initialize(void) {
166+
if (!m_initialized) {
167+
// Set context width and height to default visionOS resolution. It's different for the headset and device.
168+
#if TARGET_OS_SIMULATOR
169+
s_ctx = new Context(2732, 2048);
170+
#else
171+
s_ctx = new Context(1920, 1824);
172+
#endif
173+
s_ctx->m_window = m_layerRenderer;
174+
m_initialized = true;
175+
}
176+
177+
return m_initialized;
178+
}
179+
180+
void BgfxAdapter::shutdown(void) {
181+
if (m_initialized) {
182+
s_ctx->m_eventQueue.postExitEvent();
183+
s_ctx = NULL;
184+
}
185+
186+
m_initialized = false;
187+
}
188+
189+
void BgfxAdapter::render() {
190+
if (!m_initialized) {
191+
return;
192+
}
193+
bgfx::renderFrame();
194+
}
195+
196+
void BgfxAdapter::renderLoop() {
197+
bool isRendering = true;
198+
while (isRendering) {
199+
switch (cp_layer_renderer_get_state(m_layerRenderer)) {
200+
case cp_layer_renderer_state_paused:
201+
cp_layer_renderer_wait_until_running(m_layerRenderer);
202+
break;
203+
204+
case cp_layer_renderer_state_running:
205+
this->initialize();
206+
this->render();
207+
break;
208+
209+
case cp_layer_renderer_state_invalidated:
210+
isRendering = false;
211+
break;
212+
}
213+
}
214+
215+
this->shutdown();
216+
}
217+
218+
#endif // BX_PLATFORM_VISIONOS
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#ifndef SWIFT_ADAPTER_H_HEADER_GUARD
2+
#define SWIFT_ADAPTER_H_HEADER_GUARD
3+
4+
#include <CompositorServices/CompositorServices.h>
5+
6+
class BgfxAdapter {
7+
private:
8+
bool m_initialized = false;
9+
cp_layer_renderer_t m_layerRenderer = NULL;
10+
void render(void);
11+
12+
public:
13+
BgfxAdapter(cp_layer_renderer_t layerRenderer) : m_layerRenderer(layerRenderer) {
14+
}
15+
16+
~BgfxAdapter() {
17+
shutdown();
18+
}
19+
20+
bool initialize(void);
21+
void shutdown(void);
22+
void renderLoop(void);
23+
};
24+
25+
#endif

examples/runtime/xros-info.plist

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>en</string>
7+
<key>CFBundleDisplayName</key>
8+
<string>Examples Debug</string>
9+
<key>CFBundleExecutable</key>
10+
<string>$(EXECUTABLE_NAME)</string>
11+
<key>CFBundleIdentifier</key>
12+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13+
<key>CFBundleInfoDictionaryVersion</key>
14+
<string>6.0</string>
15+
<key>CFBundleName</key>
16+
<string>$(PRODUCT_NAME)</string>
17+
<key>CFBundlePackageType</key>
18+
<string>APPL</string>
19+
<key>CFBundleShortVersionString</key>
20+
<string>1.0</string>
21+
<key>CFBundleSignature</key>
22+
<string>????</string>
23+
<key>CFBundleVersion</key>
24+
<string>1</string>
25+
<key>UIApplicationSceneManifest</key>
26+
<dict>
27+
<key>UIApplicationPreferredDefaultSceneSessionRole</key>
28+
<string>CPSceneSessionRoleImmersiveSpaceApplication</string>
29+
<key>UIApplicationSupportsMultipleScenes</key>
30+
<true/>
31+
</dict>
32+
</dict>
33+
</plist>

scripts/example-common.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,18 @@ project ("example-common")
9191
path.join(BGFX_DIR, "examples/common/**.mm"),
9292
}
9393

94+
configuration { "xros*" }
95+
files {
96+
path.join(BGFX_DIR, "examples/common/**.swift"),
97+
path.join(BGFX_DIR, "examples/common/**.hpp"),
98+
path.join(BGFX_DIR, "examples/common/**.modulemap"),
99+
}
100+
xcodeprojectopts {
101+
SWIFT_VERSION = "5.0",
102+
SWIFT_OBJC_BRIDGING_HEADER = path.join(BGFX_DIR, "examples/common/entry/swift_adapter.h"),
103+
SWIFT_OBJC_INTEROP_MODE = "objcxx",
104+
}
105+
94106
configuration { "winstore* or durango"}
95107
files {
96108
path.join(BGFX_DIR, "examples/common/**.cx"),

scripts/genie.lua

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,8 @@ function exampleProjectDefaults()
408408
"-weak_framework Metal",
409409
}
410410

411-
configuration { "ios* or tvos*" }
412-
kind "ConsoleApp"
411+
configuration { "ios* or tvos* or xros*" }
412+
kind "WindowedApp"
413413
linkoptions {
414414
"-framework CoreFoundation",
415415
"-framework Foundation",
@@ -419,6 +419,11 @@ function exampleProjectDefaults()
419419
"-framework UIKit",
420420
"-weak_framework Metal",
421421
}
422+
xcodecopyresources {
423+
{ "shaders/metal", {
424+
os.matchfiles(path.join(BGFX_DIR, "examples/runtime/shaders/metal/**.bin"))
425+
}}
426+
}
422427

423428
configuration { "xcode*", "ios" }
424429
kind "WindowedApp"
@@ -432,6 +437,12 @@ function exampleProjectDefaults()
432437
path.join(BGFX_DIR, "examples/runtime/tvOS-Info.plist"),
433438
}
434439

440+
configuration { "xcode*", "xros" }
441+
kind "WindowedApp"
442+
files {
443+
path.join(BGFX_DIR, "examples/runtime/xros-info.plist"),
444+
}
445+
435446
configuration {}
436447

437448
strip()

0 commit comments

Comments
 (0)