summaryrefslogtreecommitdiffstats
path: root/src/main.zig
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2021-03-09 17:40:29 +0000
committers-ol <s-ol@users.noreply.github.com>2021-03-09 17:40:29 +0000
commit40c7bc1f0f58d3e19d9b4d610454745cfbb005aa (patch)
tree709c7e99854d92988ca5d296afd539559a13761c /src/main.zig
parentintial commit (diff)
downloadopenxPriments-40c7bc1f0f58d3e19d9b4d610454745cfbb005aa.tar.gz
openxPriments-40c7bc1f0f58d3e19d9b4d610454745cfbb005aa.zip
Vulkan wip
Diffstat (limited to 'src/main.zig')
-rw-r--r--src/main.zig434
1 files changed, 278 insertions, 156 deletions
diff --git a/src/main.zig b/src/main.zig
index b7c7174..1d10253 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -1,179 +1,301 @@
+usingnamespace @import("xrvk.zig");
const std = @import("std");
-const xr = @import("openxr");
-const c = @import("c.zig");
+const gfx = @import("graphics.zig");
+const renderdoc = @import("renderdoc.zig");
const Allocator = std.mem.Allocator;
-const graphics = @import("./graphics.zig");
+pub fn main() !void {
+ try renderdoc.load_api();
+ var session = try Session.init(std.heap.page_allocator);
+ try session.loop();
+ session.deinit();
+}
-const BaseDispatch = struct {
- xrCreateInstance: xr.PfnCreateInstance,
- usingnamespace xr.BaseWrapper(@This());
-};
+const Session = struct {
+ xrb: xr.BaseDispatch,
+ xri: xr.InstanceDispatch,
-const InstanceDispatch = struct {
- xrDestroyInstance: xr.PfnDestroyInstance,
- xrGetSystem: xr.PfnGetSystem,
- xrGetSystemProperties: xr.PfnGetSystemProperties,
- xrCreateSession: xr.PfnCreateSession,
- xrBeginSession: xr.PfnBeginSession,
- xrEndSession: xr.PfnEndSession,
- xrWaitFrame: xr.PfnWaitFrame,
- xrBeginFrame: xr.PfnBeginFrame,
- xrEndFrame: xr.PfnEndFrame,
- xrPollEvent: xr.PfnPollEvent,
- xrLocateViews: xr.PfnLocateViews,
- xrCreateReferenceSpace: xr.PfnCreateReferenceSpace,
- xrCreateVulkanInstanceKHR: xr.PfnCreateVulkanInstanceKHR,
- xrGetVulkanGraphicsDevice2KHR: xr.PfnGetVulkanGraphicsDevice2KHR,
- xrGetVulkanGraphicsRequirements2KHR: xr.PfnGetVulkanGraphicsRequirements2KHR,
- xrCreateVulkanDeviceKHR: xr.PfnCreateVulkanDeviceKHR,
- usingnamespace xr.InstanceWrapper(@This());
-};
+ instance: xr.Instance,
+ session: xr.Session,
+ system: xr.SystemId,
-fn xrGetProcAddr(instance: xr.Instance, name: [*:0]const u8) !xr.PfnVoidFunction {
- var out: xr.PfnVoidFunction = undefined;
- const result = c.xrGetInstanceProcAddr(instance, name, &out);
- return switch (result) {
- .success => out,
- .error_handle_invalid => error.HandleInvalid,
- .error_instance_lost => error.InstanceLost,
- .error_runtime_failure => error.RuntimeFailure,
- .error_out_of_memory => error.OutOfMemory,
- .error_function_unsupported => error.FunctionUnsupported,
- .error_validation_failure => error.ValidationFailure,
- else => error.Unknown,
- };
-}
+ allocator: *Allocator,
-pub fn main() !void {
- const allocator = std.heap.page_allocator;
-
- var name: [128]u8 = undefined;
- std.mem.copy(u8, name[0..], "openxr-zig-test" ++ [_]u8{0});
- const zero = [_:0]u8{0};
-
- const extensions = [_][*:0]const u8 {
- "XR_KHR_vulkan_enable2",
- };
+ state: xr.SessionState,
+ views: ?ViewInfo,
+ graphics: gfx.Graphics,
+ layers: []*const xr.CompositionLayerBaseHeader,
+ scene_space: xr.Space,
- const xrb = try BaseDispatch.load(xrGetProcAddr);
- const inst = try xrb.createInstance(.{
- .create_flags = .{},
- .application_info = .{
- .application_name = name,
- .application_version = 0,
- .engine_name = name,
- .engine_version = 0,
- .api_version = xr.makeVersion(1, 0, 0),
- },
- .enabled_api_layer_count = 0,
- .enabled_api_layer_names = @ptrCast([*]const [*:0]const u8, &zero),
- .enabled_extension_count = extensions.len,
- .enabled_extension_names = &extensions,
- });
-
- const xri = try InstanceDispatch.load(inst, xrGetProcAddr);
- defer xri.destroyInstance(inst) catch unreachable;
-
- const system = try xri.getSystem(inst, .{ .form_factor = .head_mounted_display });
-
- var system_properties = xr.SystemProperties.empty();
- try xri.getSystemProperties(inst, system, &system_properties);
-
- std.debug.print(
- \\system {}:
- \\ vendor Id: {}
- \\ systemName: {}
- \\ gfx
- \\ max swapchain image resolution: {}x{}
- \\ max layer count: {}
- \\ tracking
- \\ orientation tracking: {}
- \\ positional tracking: {}
- \\
- , .{
- system,
- system_properties.vendor_id,
- system_properties.system_name,
- system_properties.graphics_properties.max_swapchain_image_width,
- system_properties.graphics_properties.max_swapchain_image_height,
- system_properties.graphics_properties.max_layer_count,
- system_properties.tracking_properties.orientation_tracking,
- system_properties.tracking_properties.position_tracking,
- });
-
- const session = try xri.createSession(inst, .{
- .next = try graphics.get_binding(xri, inst, system, allocator),
- .create_flags = .{},
- .system_id = system,
- });
-
- _ = try xri.beginSession(session, .{
- .primary_view_configuration_type = .primary_stereo,
- });
-
- const sceneSpace = (try xri.createReferenceSpace(session, .{
- .reference_space_type = .stage,
- .pose_in_reference_space = .{
- .orientation = .{ .w = 1 },
- },
- })).space;
-
- var projViews = [_]xr.CompositionLayerProjectionView{xr.CompositionLayerProjectionView.empty()} ** 2;
-
- const compositionLayer = xr.CompositionLayerProjection{
- .layer_flags = .{ .blend_texture_source_alpha_bit = true },
- .space = sceneSpace,
- .view_count = 2,
- .views = &projViews,
- };
- const layers = [_]*const xr.CompositionLayerBaseHeader{
- @ptrCast(*const xr.CompositionLayerBaseHeader, &compositionLayer),
+ first_render: bool = true,
+
+ const ViewInfo = struct {
+ configurations: []xr.ViewConfigurationView,
+ projections: []xr.CompositionLayerProjectionView,
+ swapchains: []gfx.Swapchain,
};
- while (true) {
- // todo: fix API
- var frameWaitInfo = xr.FrameWaitInfo.empty();
- var frameState = xr.FrameState.empty();
+ pub fn init(allocator: *Allocator) !Session {
+ var name: [128]u8 = undefined;
+ std.mem.copy(u8, name[0..], "openxr-zig-test" ++ [_]u8{0});
+ const zero = [_:0]u8{};
- _ = try xri.waitFrame(session, &frameWaitInfo, &frameState);
+ const layers = [_][*:0]const u8{
+ "XR_APILAYER_LUNARG_core_validation",
+ };
+
+ const extensions = [_][*:0]const u8{
+ "XR_KHR_vulkan_enable2",
+ };
- _ = try xri.beginFrame(session, &xr.FrameBeginInfo{});
+ const xrb = try xr.BaseDispatch.load(xr.getProcAddr);
+ const instance = try xrb.createInstance(.{
+ .create_flags = .{},
+ .application_info = .{
+ .application_name = name,
+ .application_version = 0,
+ .engine_name = name,
+ .engine_version = 0,
+ .api_version = xr.makeVersion(1, 0, 0),
+ },
+ .enabled_api_layer_count = 0,
+ .enabled_api_layer_names = @ptrCast([*]const [*:0]const u8, &zero),
+ .enabled_extension_count = extensions.len,
+ .enabled_extension_names = &extensions,
+ });
- var layer_count: u32 = 0;
+ const xri = try xr.InstanceDispatch.load(instance, xr.getProcAddr);
+ errdefer xri.destroyInstance(instance) catch unreachable;
- if (frameState.should_render > 0) {
- var views = [_]xr.View{xr.View.empty()} ** 2;
- var viewState = xr.ViewState.empty();
+ const system = try xri.getSystem(instance, .{ .form_factor = .head_mounted_display });
- _ = try xri.locateViews(session, .{
- .view_configuration_type = .primary_stereo,
- .display_time = frameState.predicted_display_time,
- .space = sceneSpace,
- }, &viewState, 2, &views);
+ var system_properties = xr.SystemProperties.empty();
+ try xri.getSystemProperties(instance, system, &system_properties);
- std.debug.print("views: {}\n", .{ views });
+ std.debug.print(
+ \\system {}:
+ \\ vendor Id: {}
+ \\ systemName: {}
+ \\ gfx
+ \\ max swapchain image resolution: {}x{}
+ \\ max layer count: {}
+ \\ tracking
+ \\ orientation tracking: {}
+ \\ positional tracking: {}
+ \\
+ , .{
+ system,
+ system_properties.vendor_id,
+ system_properties.system_name,
+ system_properties.graphics_properties.max_swapchain_image_width,
+ system_properties.graphics_properties.max_swapchain_image_height,
+ system_properties.graphics_properties.max_layer_count,
+ system_properties.tracking_properties.orientation_tracking,
+ system_properties.tracking_properties.position_tracking,
+ });
+
+ var graphics = try gfx.Graphics.init(allocator, xri, instance, system);
+ try graphics.setup_debugging();
+
+ const binding = graphics.get_binding();
+ const session = try xri.createSession(instance, .{
+ .next = &binding,
+ .create_flags = .{},
+ .system_id = system,
+ });
+ errdefer xri.destroySession(session) catch unreachable;
- for (views) |view, i| {
- projViews[i].pose = view.pose;
- projViews[i].fov = view.fov;
- projViews[i].sub_image = .{
- .swapchain = xr.Swapchain.null_handle,
- .image_rect = .{},
- .image_array_index = 0,
- };
+ const scene_space = (try xri.createReferenceSpace(session, .{
+ .reference_space_type = .stage,
+ .pose_in_reference_space = .{
+ .orientation = .{ .w = 1 },
+ },
+ })).space;
+
+ return Session{
+ .xrb = xrb,
+ .xri = xri,
+
+ .instance = instance,
+ .session = session,
+ .system = system,
+ .allocator = allocator,
+
+ .state = .idle,
+ .views = null,
+ .graphics = graphics,
+ .scene_space = scene_space,
+ .layers = &[_]*const xr.CompositionLayerBaseHeader{},
+ };
+ }
+
+ pub fn deinit(self: *const Session) void {
+ if (self.views) |views| {
+ for (views.swapchains) |swapchain| {
+ swapchain.deinit();
}
+ self.allocator.free(views.configurations);
+ self.allocator.free(views.projections);
+ self.allocator.free(views.swapchains);
+ }
- layer_count = 1;
+ for (self.layers) |layer| {
+ self.allocator.destroy(layer);
}
- _ = try xri.endFrame(session, .{
- .display_time = frameState.predicted_display_time,
- .environment_blend_mode = .@"opaque",
- .layer_count = layer_count,
- .layers = &layers,
- });
+ _ = self.xri.destroySession(self.session) catch null;
+ _ = self.xri.destroyInstance(self.instance) catch null;
}
- try xri.endSession(session);
-}
+ pub fn loop(self: *Session) !void {
+ const view_count = try self.xri.enumerateViewConfigurationViews(self.instance, self.system, .primary_stereo, 0, null);
+ const views = ViewInfo{
+ .configurations = try self.allocator.alloc(xr.ViewConfigurationView, view_count),
+ .projections = try self.allocator.alloc(xr.CompositionLayerProjectionView, view_count),
+ .swapchains = try self.allocator.alloc(gfx.Swapchain, view_count),
+ };
+
+ _ = try self.xri.enumerateViewConfigurationViews(self.instance, self.system, .primary_stereo, view_count, views.configurations.ptr);
+
+ for (views.configurations) |config, i| {
+ if (renderdoc.api) |api| api.StartFrameCapture(null, null);
+ views.projections[i] = xr.CompositionLayerProjectionView.empty();
+ views.swapchains[i] = try gfx.Swapchain.init(&self.graphics, self.session, config);
+ if (renderdoc.api) |api| _ = api.EndFrameCapture(null, null);
+ }
+
+ const composition_layer = try self.allocator.create(xr.CompositionLayerProjection);
+ composition_layer.* = .{
+ .layer_flags = .{ .blend_texture_source_alpha_bit = true },
+ .space = self.scene_space,
+ .view_count = view_count,
+ .views = views.projections.ptr,
+ };
+
+ self.views = views;
+ self.layers = try self.allocator.alloc(*xr.CompositionLayerBaseHeader, 1);
+ self.layers[0] = @ptrCast(*const xr.CompositionLayerBaseHeader, composition_layer);
+
+ while (true) main: {
+ while (true) {
+ var event = xr.EventDataBuffer.empty();
+ const poll_result = try self.xri.pollEvent(self.instance, &event);
+
+ if (poll_result == .event_unavailable) {
+ break;
+ }
+
+ switch (event.type) {
+ .event_data_session_state_changed => {
+ const state_event = @ptrCast(*const xr.EventDataSessionStateChanged, &event);
+ std.debug.print("session state {} → {}\n", .{ self.state, state_event.state });
+ self.state = state_event.state;
+ switch (self.state) {
+ .ready => {
+ _ = try self.xri.beginSession(self.session, .{ .primary_view_configuration_type = .primary_stereo });
+ },
+ .stopping => {
+ _ = try self.xri.endSession(self.session);
+ break :main;
+ },
+ .idle, .synchronized, .visible, .focused, .exiting => {},
+ .loss_pending => return error.LossPending,
+ else => return error.InvalidState,
+ }
+ },
+ .event_data_interaction_profile_changed, .event_data_reference_space_change_pending => {
+ std.debug.print("skipping event: {}\n", .{event.type});
+ },
+
+ .event_data_instance_loss_pending => break,
+ .event_data_events_lost => return error.EventsLost,
+
+ else => {
+ std.debug.print("unknown event: {}\n", .{event.type});
+ },
+ }
+ }
+
+ if (!try self.render_frame()) {
+ std.os.nanosleep(0, 250_000_000);
+ }
+ }
+ }
+
+ pub fn render_frame(self: *Session) !bool {
+ if (self.views) |views| {
+ var frame_state = xr.FrameState.empty();
+ _ = try self.xri.waitFrame(self.session, &xr.FrameWaitInfo{}, &frame_state);
+
+ _ = try self.xri.beginFrame(self.session, &xr.FrameBeginInfo{});
+
+ var layer_count: u32 = 0;
+
+ if (frame_state.should_render > 0) {
+ std.debug.print("renderin'\n", .{});
+ if (self.first_render) if (renderdoc.api) |api| api.StartFrameCapture(null, null);
+
+ var located_views = [_]xr.View{xr.View.empty()} ** 2;
+ var view_state = xr.ViewState.empty();
+
+ _ = try self.xri.locateViews(self.session, .{
+ .view_configuration_type = .primary_stereo,
+ .display_time = frame_state.predicted_display_time,
+ .space = self.scene_space,
+ }, &view_state, 2, &located_views);
+
+ if (!view_state.view_state_flags.contains(.{ .position_valid_bit = true, .orientation_valid_bit = true })) {
+ return error.InvalidPositionOrOrientation;
+ }
+
+ for (located_views) |located_view, i| {
+ const swapchain = views.swapchains[i];
+ const acquire_result = try self.xri.acquireSwapchainImage(swapchain.handle, &xr.SwapchainImageAcquireInfo.empty());
+
+ _ = try self.xri.waitSwapchainImage(swapchain.handle, .{ .timeout = -1 });
+
+ views.projections[i] = .{
+ .pose = located_view.pose,
+ .fov = located_view.fov,
+ .sub_image = .{
+ .swapchain = swapchain.handle,
+ .image_rect = swapchain.image_rect,
+ .image_array_index = 0,
+ },
+ };
+
+ std.debug.print("submitting view {}: {}\n", .{ i, views.projections[i].sub_image });
+
+ try self.graphics.render_view(views.projections[i], swapchain, acquire_result.index);
+
+ _ = try self.xri.releaseSwapchainImage(swapchain.handle, &xr.SwapchainImageReleaseInfo.empty());
+ }
+
+ _ = try self.xri.endFrame(self.session, .{
+ .display_time = frame_state.predicted_display_time,
+ .environment_blend_mode = .@"opaque",
+ .layer_count = @intCast(u32, self.layers.len),
+ .layers = self.layers.ptr,
+ });
+
+ if (self.first_render) {
+ if (renderdoc.api) |api| _ = api.EndFrameCapture(null, null);
+ self.first_render = false;
+ }
+
+ return true;
+ }
+
+ _ = try self.xri.endFrame(self.session, .{
+ .display_time = frame_state.predicted_display_time,
+ .environment_blend_mode = .@"opaque",
+ .layer_count = 0,
+ .layers = null,
+ });
+
+ return false;
+ }
+
+ unreachable;
+ }
+};