diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2021-03-09 17:40:29 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2021-03-09 17:40:29 +0000 |
| commit | 40c7bc1f0f58d3e19d9b4d610454745cfbb005aa (patch) | |
| tree | 709c7e99854d92988ca5d296afd539559a13761c /src/main.zig | |
| parent | intial commit (diff) | |
| download | openxPriments-40c7bc1f0f58d3e19d9b4d610454745cfbb005aa.tar.gz openxPriments-40c7bc1f0f58d3e19d9b4d610454745cfbb005aa.zip | |
Vulkan wip
Diffstat (limited to 'src/main.zig')
| -rw-r--r-- | src/main.zig | 434 |
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; + } +}; |
