Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add visionOS Examples #3292

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions examples/common/entry/entry_visionos.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import SwiftUI
import CompositorServices

// Default configuration
struct ContentStageConfiguration: CompositorLayerConfiguration {
func makeConfiguration(capabilities: LayerRenderer.Capabilities, configuration: inout LayerRenderer.Configuration) {
configuration.depthFormat = .depth32Float
configuration.colorFormat = .bgra8Unorm_srgb

let foveationEnabled = capabilities.supportsFoveation
configuration.isFoveationEnabled = foveationEnabled

let options: LayerRenderer.Capabilities.SupportedLayoutsOptions = foveationEnabled ? [.foveationEnabled] : []
let supportedLayouts = capabilities.supportedLayouts(options: options)

configuration.layout = supportedLayouts.contains(.layered) ? .layered : .dedicated
}
}

@main
struct ExampleApp: App {
var body: some Scene {
ImmersiveSpace {
CompositorLayer(configuration: ContentStageConfiguration()) { layerRenderer in
let renderThread = Thread {
var engine = BgfxAdapter(layerRenderer)
engine.renderLoop()
}
renderThread.name = "Render Thread"
renderThread.start()
}
}
}
}
218 changes: 218 additions & 0 deletions examples/common/entry/swift_adapter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
#include "entry_p.h"

#if ENTRY_CONFIG_USE_NATIVE && BX_PLATFORM_VISIONOS

#include "swift_adapter.h"

#include <bgfx/platform.h>
#include <bx/uint32_t.h>
#include <bx/thread.h>

namespace entry
{
struct MainThreadEntry
{
int m_argc;
const char* const* m_argv;

static int32_t threadFunc(bx::Thread* _thread, void* _userData);
};

static WindowHandle s_defaultWindow = { 0 };

struct Context
{
Context(uint32_t _width, uint32_t _height)
{
static const char* const argv[] = { "visionos" };
m_mte.m_argc = BX_COUNTOF(argv);
m_mte.m_argv = argv;

m_eventQueue.postSizeEvent(s_defaultWindow, _width, _height);


// Prevent render thread creation.
bgfx::renderFrame();

m_thread.init(MainThreadEntry::threadFunc, &m_mte);
}


~Context()
{
m_thread.shutdown();
}

MainThreadEntry m_mte;
bx::Thread m_thread;
void* m_window;

EventQueue m_eventQueue;
};

static Context* s_ctx;

int32_t MainThreadEntry::threadFunc(bx::Thread* _thread, void* _userData)
{
BX_UNUSED(_thread);

if (_thread != NULL) {
_thread->setThreadName("Main Thread BGFX");
}

CFBundleRef mainBundle = CFBundleGetMainBundle();
if (mainBundle != nil)
{
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
if (resourcesURL != nil)
{
char path[PATH_MAX];
if (CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8*)path, PATH_MAX) )
{
chdir(path);
}

CFRelease(resourcesURL);
}
}

MainThreadEntry* self = (MainThreadEntry*)_userData;
int32_t result = main(self->m_argc, self->m_argv);
return result;
}

const Event* poll()
{
return s_ctx->m_eventQueue.poll();
}

const Event* poll(WindowHandle _handle)
{
return s_ctx->m_eventQueue.poll(_handle);
}

void release(const Event* _event)
{
s_ctx->m_eventQueue.release(_event);
}

WindowHandle createWindow(int32_t _x, int32_t _y, uint32_t _width, uint32_t _height, uint32_t _flags, const char* _title)
{
BX_UNUSED(_x, _y, _width, _height, _flags, _title);
WindowHandle handle = { UINT16_MAX };
return handle;
}

void destroyWindow(WindowHandle _handle)
{
BX_UNUSED(_handle);
}

void setWindowPos(WindowHandle _handle, int32_t _x, int32_t _y)
{
BX_UNUSED(_handle, _x, _y);
}

void setWindowSize(WindowHandle _handle, uint32_t _width, uint32_t _height)
{
BX_UNUSED(_handle, _width, _height);
}

void setWindowTitle(WindowHandle _handle, const char* _title)
{
BX_UNUSED(_handle, _title);
}

void setWindowFlags(WindowHandle _handle, uint32_t _flags, bool _enabled)
{
BX_UNUSED(_handle, _flags, _enabled);
}

void toggleFullscreen(WindowHandle _handle)
{
BX_UNUSED(_handle);
}

void setMouseLock(WindowHandle _handle, bool _lock)
{
BX_UNUSED(_handle, _lock);
}

void* getNativeWindowHandle(WindowHandle _handle)
{
if (kDefaultWindowHandle.idx == _handle.idx)
{
return s_ctx->m_window;
}

return NULL;
}

void* getNativeDisplayHandle()
{
return NULL;
}

bgfx::NativeWindowHandleType::Enum getNativeWindowHandleType()
{
return bgfx::NativeWindowHandleType::Default;
}

} // namespace entry

using namespace entry;

bool BgfxAdapter::initialize(void) {
if (!m_initialized) {
// Set context width and height to default visionOS resolution. It's different for the headset and device.
#if TARGET_OS_SIMULATOR
s_ctx = new Context(2732, 2048);
#else
s_ctx = new Context(1920, 1824);
#endif
s_ctx->m_window = m_layerRenderer;
m_initialized = true;
}

return m_initialized;
}

void BgfxAdapter::shutdown(void) {
if (m_initialized) {
s_ctx->m_eventQueue.postExitEvent();
s_ctx = NULL;
}

m_initialized = false;
}

void BgfxAdapter::render() {
if (!m_initialized) {
return;
}
bgfx::renderFrame();
}

void BgfxAdapter::renderLoop() {
bool isRendering = true;
while (isRendering) {
switch (cp_layer_renderer_get_state(m_layerRenderer)) {
case cp_layer_renderer_state_paused:
cp_layer_renderer_wait_until_running(m_layerRenderer);
break;

case cp_layer_renderer_state_running:
this->initialize();
this->render();
break;

case cp_layer_renderer_state_invalidated:
isRendering = false;
break;
}
}

this->shutdown();
}

#endif // BX_PLATFORM_VISIONOS
25 changes: 25 additions & 0 deletions examples/common/entry/swift_adapter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef SWIFT_ADAPTER_H_HEADER_GUARD
#define SWIFT_ADAPTER_H_HEADER_GUARD

#include <CompositorServices/CompositorServices.h>

class BgfxAdapter {
private:
bool m_initialized = false;
cp_layer_renderer_t m_layerRenderer = NULL;
void render(void);

public:
BgfxAdapter(cp_layer_renderer_t layerRenderer) : m_layerRenderer(layerRenderer) {
}

~BgfxAdapter() {
shutdown();
}

bool initialize(void);
void shutdown(void);
void renderLoop(void);
};

#endif
33 changes: 33 additions & 0 deletions examples/runtime/xros-info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>Examples Debug</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationPreferredDefaultSceneSessionRole</key>
<string>CPSceneSessionRoleImmersiveSpaceApplication</string>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
</dict>
</dict>
</plist>
12 changes: 12 additions & 0 deletions scripts/example-common.lua
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,18 @@ project ("example-common")
path.join(BGFX_DIR, "examples/common/**.mm"),
}

configuration { "xros*" }
files {
path.join(BGFX_DIR, "examples/common/**.swift"),
path.join(BGFX_DIR, "examples/common/**.hpp"),
path.join(BGFX_DIR, "examples/common/**.modulemap"),
}
xcodeprojectopts {
SWIFT_VERSION = "5.0",
SWIFT_OBJC_BRIDGING_HEADER = path.join(BGFX_DIR, "examples/common/entry/swift_adapter.h"),
SWIFT_OBJC_INTEROP_MODE = "objcxx",
}

configuration { "winstore* or durango"}
files {
path.join(BGFX_DIR, "examples/common/**.cx"),
Expand Down
15 changes: 13 additions & 2 deletions scripts/genie.lua
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,8 @@ function exampleProjectDefaults()
"-weak_framework Metal",
}

configuration { "ios* or tvos*" }
kind "ConsoleApp"
configuration { "ios* or tvos* or xros*" }
kind "WindowedApp"
linkoptions {
"-framework CoreFoundation",
"-framework Foundation",
Expand All @@ -419,6 +419,11 @@ function exampleProjectDefaults()
"-framework UIKit",
"-weak_framework Metal",
}
xcodecopyresources {
{ "shaders/metal", {
os.matchfiles(path.join(BGFX_DIR, "examples/runtime/shaders/metal/**.bin"))
}}
}

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

configuration { "xcode*", "xros" }
kind "WindowedApp"
files {
path.join(BGFX_DIR, "examples/runtime/xros-info.plist"),
}

configuration {}

strip()
Expand Down
Loading