mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-02-05 05:18:03 +00:00
sdl_test: Add SDL test framework
This commit is contained in:
parent
bea3569016
commit
0fedf6fe7d
|
@ -32,3 +32,7 @@ endif()
|
|||
if(XRT_FEATURE_STEAMVR_PLUGIN)
|
||||
add_subdirectory(steamvr_drv)
|
||||
endif()
|
||||
|
||||
if(XRT_FEATURE_SERVICE AND XRT_HAVE_SDL2 AND XRT_HAVE_VULKAN)
|
||||
add_subdirectory(sdl_test)
|
||||
endif()
|
||||
|
|
37
src/xrt/targets/sdl_test/CMakeLists.txt
Normal file
37
src/xrt/targets/sdl_test/CMakeLists.txt
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Copyright 2020-2022, Collabora, Ltd.
|
||||
# SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
add_executable(
|
||||
sdl-test
|
||||
sdl_compositor.c
|
||||
sdl_device.c
|
||||
sdl_hack_stubs.c
|
||||
sdl_instance.c
|
||||
sdl_internal.h
|
||||
sdl_internal.hpp
|
||||
sdl_main.c
|
||||
sdl_program.cpp
|
||||
sdl_swapchain.c
|
||||
)
|
||||
add_sanitizers(sdl-test)
|
||||
|
||||
target_link_libraries(
|
||||
sdl-test
|
||||
PRIVATE
|
||||
xrt-external-imgui-sdl2
|
||||
aux_os
|
||||
aux_ogl
|
||||
aux_util
|
||||
comp_util
|
||||
comp_multi
|
||||
ipc_server
|
||||
st_gui
|
||||
drv_includes
|
||||
drv_simulated
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(gui PRIVATE SDL2::SDL2main)
|
||||
endif()
|
||||
|
||||
install(TARGETS sdl-test RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
608
src/xrt/targets/sdl_test/sdl_compositor.c
Normal file
608
src/xrt/targets/sdl_test/sdl_compositor.c
Normal file
|
@ -0,0 +1,608 @@
|
|||
// Copyright 2019-2022, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief SDL compositor implementation.
|
||||
*
|
||||
* Based on src/xrt/compositor/null/null_compositor.c
|
||||
*
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
|
||||
#include "xrt/xrt_gfx_native.h"
|
||||
|
||||
#include "os/os_time.h"
|
||||
|
||||
#include "util/u_misc.h"
|
||||
#include "util/u_time.h"
|
||||
#include "util/u_debug.h"
|
||||
#include "util/u_verify.h"
|
||||
#include "util/u_handles.h"
|
||||
#include "util/u_trace_marker.h"
|
||||
|
||||
#include "util/comp_vulkan.h"
|
||||
|
||||
#include "multi/comp_multi_interface.h"
|
||||
|
||||
#include "sdl_internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Helper functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static struct vk_bundle *
|
||||
get_vk(struct sdl_compositor *c)
|
||||
{
|
||||
return &c->base.vk;
|
||||
}
|
||||
|
||||
#define SC_TRACE(c, ...) U_LOG_IFL_T(c->base.vk.log_level, __VA_ARGS__);
|
||||
#define SC_DEBUG(c, ...) U_LOG_IFL_D(c->base.vk.log_level, __VA_ARGS__);
|
||||
#define SC_INFO(c, ...) U_LOG_IFL_I(c->base.vk.log_level, __VA_ARGS__);
|
||||
#define SC_WARN(c, ...) U_LOG_IFL_W(c->base.vk.log_level, __VA_ARGS__);
|
||||
#define SC_ERROR(c, ...) U_LOG_IFL_E(c->base.vk.log_level, __VA_ARGS__);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Vulkan functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static const char *instance_extensions_common[] = {
|
||||
VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, //
|
||||
VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, //
|
||||
VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, //
|
||||
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, //
|
||||
};
|
||||
|
||||
static const char *required_device_extensions[] = {
|
||||
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, //
|
||||
VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME, //
|
||||
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, //
|
||||
VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, //
|
||||
VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, //
|
||||
|
||||
// Platform version of "external_memory"
|
||||
#if defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_FD)
|
||||
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
|
||||
|
||||
#elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER)
|
||||
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
|
||||
|
||||
#elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_WIN32_HANDLE)
|
||||
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
|
||||
|
||||
#else
|
||||
#error "Need port!"
|
||||
#endif
|
||||
|
||||
// Platform version of "external_fence" and "external_semaphore"
|
||||
#if defined(XRT_GRAPHICS_SYNC_HANDLE_IS_FD) // Optional
|
||||
|
||||
#elif defined(XRT_GRAPHICS_SYNC_HANDLE_IS_WIN32_HANDLE)
|
||||
VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, //
|
||||
VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME, //
|
||||
|
||||
#else
|
||||
#error "Need port!"
|
||||
#endif
|
||||
};
|
||||
|
||||
static const char *optional_device_extensions[] = {
|
||||
VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, //
|
||||
VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, //
|
||||
|
||||
// Platform version of "external_fence" and "external_semaphore"
|
||||
#if defined(XRT_GRAPHICS_SYNC_HANDLE_IS_FD) // Optional
|
||||
VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, //
|
||||
VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME, //
|
||||
|
||||
#elif defined(XRT_GRAPHICS_SYNC_HANDLE_IS_WIN32_HANDLE) // Not optional
|
||||
|
||||
#else
|
||||
#error "Need port!"
|
||||
#endif
|
||||
|
||||
#ifdef VK_KHR_image_format_list
|
||||
VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME,
|
||||
#endif
|
||||
#ifdef VK_KHR_timeline_semaphore
|
||||
VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
|
||||
#endif
|
||||
#ifdef VK_EXT_calibrated_timestamps
|
||||
VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME,
|
||||
#endif
|
||||
#ifdef VK_EXT_robustness2
|
||||
VK_EXT_ROBUSTNESS_2_EXTENSION_NAME,
|
||||
#endif
|
||||
};
|
||||
|
||||
static VkResult
|
||||
select_instances_extensions(struct sdl_compositor *c, struct u_string_list *required, struct u_string_list *optional)
|
||||
{
|
||||
#ifdef VK_EXT_display_surface_counter
|
||||
u_string_list_append(optional, VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME);
|
||||
#endif
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static bool
|
||||
compositor_init_vulkan(struct sdl_compositor *c, enum u_logging_level log_level)
|
||||
{
|
||||
struct vk_bundle *vk = get_vk(c);
|
||||
VkResult ret;
|
||||
|
||||
// every backend needs at least the common extensions
|
||||
struct u_string_list *required_instance_ext_list =
|
||||
u_string_list_create_from_array(instance_extensions_common, ARRAY_SIZE(instance_extensions_common));
|
||||
|
||||
struct u_string_list *optional_instance_ext_list = u_string_list_create();
|
||||
|
||||
ret = select_instances_extensions(c, required_instance_ext_list, optional_instance_ext_list);
|
||||
if (ret != VK_SUCCESS) {
|
||||
VK_ERROR(vk, "select_instances_extensions: %s\n\tFailed to select instance extensions.",
|
||||
vk_result_string(ret));
|
||||
u_string_list_destroy(&required_instance_ext_list);
|
||||
u_string_list_destroy(&optional_instance_ext_list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct u_string_list *required_device_extension_list =
|
||||
u_string_list_create_from_array(required_device_extensions, ARRAY_SIZE(required_device_extensions));
|
||||
|
||||
struct u_string_list *optional_device_extension_list =
|
||||
u_string_list_create_from_array(optional_device_extensions, ARRAY_SIZE(optional_device_extensions));
|
||||
|
||||
struct comp_vulkan_arguments vk_args = {
|
||||
.get_instance_proc_address = vkGetInstanceProcAddr,
|
||||
.required_instance_version = VK_MAKE_VERSION(1, 0, 0),
|
||||
.required_instance_extensions = required_instance_ext_list,
|
||||
.optional_instance_extensions = optional_instance_ext_list,
|
||||
.required_device_extensions = required_device_extension_list,
|
||||
.optional_device_extensions = optional_device_extension_list,
|
||||
.log_level = log_level,
|
||||
.only_compute_queue = false, // Regular GFX
|
||||
.selected_gpu_index = -1, // Auto
|
||||
.client_gpu_index = -1, // Auto
|
||||
.timeline_semaphore = true, // Flag is optional, not a hard requirement.
|
||||
};
|
||||
|
||||
struct comp_vulkan_results vk_res = {0};
|
||||
bool bundle_ret = comp_vulkan_init_bundle(vk, &vk_args, &vk_res);
|
||||
|
||||
u_string_list_destroy(&required_instance_ext_list);
|
||||
u_string_list_destroy(&optional_instance_ext_list);
|
||||
u_string_list_destroy(&required_device_extension_list);
|
||||
u_string_list_destroy(&optional_device_extension_list);
|
||||
|
||||
if (!bundle_ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
static_assert(ARRAY_SIZE(vk_res.client_gpu_deviceUUID.data) == XRT_UUID_SIZE, "array size mismatch");
|
||||
static_assert(ARRAY_SIZE(vk_res.selected_gpu_deviceUUID.data) == XRT_UUID_SIZE, "array size mismatch");
|
||||
static_assert(ARRAY_SIZE(vk_res.client_gpu_deviceUUID.data) == ARRAY_SIZE(c->sys_info.client_vk_deviceUUID.data), "array size mismatch");
|
||||
static_assert(ARRAY_SIZE(vk_res.selected_gpu_deviceUUID.data) == ARRAY_SIZE(c->sys_info.compositor_vk_deviceUUID.data), "array size mismatch");
|
||||
static_assert(ARRAY_SIZE(vk_res.client_gpu_deviceLUID.data) == XRT_LUID_SIZE, "array size mismatch");
|
||||
static_assert(ARRAY_SIZE(vk_res.client_gpu_deviceLUID.data) == ARRAY_SIZE(c->sys_info.client_d3d_deviceLUID.data), "array size mismatch");
|
||||
// clang-format on
|
||||
|
||||
c->sys_info.client_vk_deviceUUID = vk_res.client_gpu_deviceUUID;
|
||||
c->sys_info.compositor_vk_deviceUUID = vk_res.selected_gpu_deviceUUID;
|
||||
c->sys_info.client_d3d_deviceLUID = vk_res.client_gpu_deviceLUID;
|
||||
c->sys_info.client_d3d_deviceLUID_valid = vk_res.client_gpu_deviceLUID_valid;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Other init functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static bool
|
||||
compositor_init_pacing(struct sdl_compositor *c)
|
||||
{
|
||||
xrt_result_t xret = u_pc_fake_create(c->settings.frame_interval_ns, os_monotonic_get_ns(), &c->upc);
|
||||
if (xret != XRT_SUCCESS) {
|
||||
SC_ERROR(c, "Failed to create fake pacing helper!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
compositor_init_info(struct sdl_compositor *c)
|
||||
{
|
||||
struct vk_bundle *vk = get_vk(c);
|
||||
struct xrt_compositor_info *info = &c->base.base.base.info;
|
||||
|
||||
struct comp_vulkan_formats formats = {0};
|
||||
comp_vulkan_formats_check(vk, &formats);
|
||||
comp_vulkan_formats_copy_to_info(&formats, info);
|
||||
comp_vulkan_formats_log(c->base.vk.log_level, &formats);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
compositor_init_sys_info(struct sdl_compositor *c, struct sdl_program *sp, struct xrt_device *xdev)
|
||||
{
|
||||
struct xrt_system_compositor_info *sys_info = &c->sys_info;
|
||||
|
||||
// Required by OpenXR spec.
|
||||
sys_info->max_layers = 16;
|
||||
|
||||
// UUIDs and LUID already set in vk init.
|
||||
(void)sys_info->compositor_vk_deviceUUID;
|
||||
(void)sys_info->client_vk_deviceUUID;
|
||||
(void)sys_info->client_d3d_deviceLUID;
|
||||
(void)sys_info->client_d3d_deviceLUID_valid;
|
||||
|
||||
// Get window size and set recommended size to it.
|
||||
const int min = 128;
|
||||
const int max = 16 * 1024;
|
||||
int w = 0, h = 0;
|
||||
SDL_GetWindowSize(sp->win, &w, &h);
|
||||
if (w <= min || h <= min) {
|
||||
U_LOG_W("Window size is %ix%i which is smaller then %ix%i upping size.", w, h, min, min);
|
||||
w = min;
|
||||
h = min;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
sys_info->views[0].recommended.width_pixels = w;
|
||||
sys_info->views[0].recommended.height_pixels = h;
|
||||
sys_info->views[0].recommended.sample_count = 1;
|
||||
sys_info->views[0].max.width_pixels = max;
|
||||
sys_info->views[0].max.height_pixels = max;
|
||||
sys_info->views[0].max.sample_count = 1;
|
||||
|
||||
sys_info->views[1].recommended.width_pixels = min; // Second view is minimum
|
||||
sys_info->views[1].recommended.height_pixels = min; // Second view is minimum
|
||||
sys_info->views[1].recommended.sample_count = 1;
|
||||
sys_info->views[1].max.width_pixels = max;
|
||||
sys_info->views[1].max.height_pixels = max;
|
||||
sys_info->views[1].max.sample_count = 1;
|
||||
// clang-format on
|
||||
|
||||
// Copy the list directly.
|
||||
assert(xdev->hmd->blend_mode_count <= XRT_MAX_DEVICE_BLEND_MODES);
|
||||
assert(xdev->hmd->blend_mode_count != 0);
|
||||
assert(xdev->hmd->blend_mode_count <= ARRAY_SIZE(sys_info->supported_blend_modes));
|
||||
for (size_t i = 0; i < xdev->hmd->blend_mode_count; ++i) {
|
||||
assert(u_verify_blend_mode_valid(xdev->hmd->blend_modes[i]));
|
||||
sys_info->supported_blend_modes[i] = xdev->hmd->blend_modes[i];
|
||||
}
|
||||
sys_info->supported_blend_mode_count = (uint8_t)xdev->hmd->blend_mode_count;
|
||||
|
||||
// Refresh rates.
|
||||
sys_info->num_refresh_rates = 1;
|
||||
sys_info->refresh_rates[0] = (float)(1. / time_ns_to_s(c->settings.frame_interval_ns));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Member functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static xrt_result_t
|
||||
sdl_compositor_begin_session(struct xrt_compositor *xc, enum xrt_view_type type)
|
||||
{
|
||||
struct sdl_compositor *c = &from_comp(xc)->c;
|
||||
SC_DEBUG(c, "BEGIN_SESSION");
|
||||
|
||||
/*
|
||||
* No logic needed here for the null compositor, if using the null
|
||||
* compositor as a base for a new compositor put desired logic here.
|
||||
*/
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static xrt_result_t
|
||||
sdl_compositor_end_session(struct xrt_compositor *xc)
|
||||
{
|
||||
struct sdl_compositor *c = &from_comp(xc)->c;
|
||||
SC_DEBUG(c, "END_SESSION");
|
||||
|
||||
/*
|
||||
* No logic needed here for the null compositor, if using the null
|
||||
* compositor as a base for a new compositor put desired logic here.
|
||||
*/
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static xrt_result_t
|
||||
sdl_compositor_predict_frame(struct xrt_compositor *xc,
|
||||
int64_t *out_frame_id,
|
||||
uint64_t *out_wake_time_ns,
|
||||
uint64_t *out_predicted_gpu_time_ns,
|
||||
uint64_t *out_predicted_display_time_ns,
|
||||
uint64_t *out_predicted_display_period_ns)
|
||||
{
|
||||
COMP_TRACE_MARKER();
|
||||
|
||||
struct sdl_compositor *c = &from_comp(xc)->c;
|
||||
|
||||
SC_TRACE(c, "PREDICT_FRAME");
|
||||
|
||||
uint64_t now_ns = os_monotonic_get_ns();
|
||||
uint64_t null_desired_present_time_ns = 0;
|
||||
uint64_t null_present_slop_ns = 0;
|
||||
uint64_t null_min_display_period_ns = 0;
|
||||
|
||||
u_pc_predict( //
|
||||
c->upc, // upc
|
||||
now_ns, // now_ns
|
||||
out_frame_id, // out_frame_id
|
||||
out_wake_time_ns, // out_wake_up_time_ns
|
||||
&null_desired_present_time_ns, // out_desired_present_time_ns
|
||||
&null_present_slop_ns, // out_present_slop_ns
|
||||
out_predicted_display_time_ns, // out_predicted_display_time_ns
|
||||
out_predicted_display_period_ns, // out_predicted_display_period_ns
|
||||
&null_min_display_period_ns); // out_min_display_period_ns
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static xrt_result_t
|
||||
sdl_compositor_mark_frame(struct xrt_compositor *xc,
|
||||
int64_t frame_id,
|
||||
enum xrt_compositor_frame_point point,
|
||||
uint64_t when_ns)
|
||||
{
|
||||
COMP_TRACE_MARKER();
|
||||
|
||||
struct sdl_compositor *c = &from_comp(xc)->c;
|
||||
|
||||
SC_TRACE(c, "MARK_FRAME %i", point);
|
||||
|
||||
switch (point) {
|
||||
case XRT_COMPOSITOR_FRAME_POINT_WOKE:
|
||||
u_pc_mark_point(c->upc, U_TIMING_POINT_WAKE_UP, frame_id, when_ns);
|
||||
return XRT_SUCCESS;
|
||||
default: assert(false);
|
||||
}
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static xrt_result_t
|
||||
sdl_compositor_begin_frame(struct xrt_compositor *xc, int64_t frame_id)
|
||||
{
|
||||
struct sdl_compositor *c = &from_comp(xc)->c;
|
||||
|
||||
SC_TRACE(c, "BEGIN_FRAME");
|
||||
|
||||
/*
|
||||
* No logic needed here for the null compositor, if using the null
|
||||
* compositor as a base for a new compositor put desired logic here.
|
||||
*/
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static xrt_result_t
|
||||
sdl_compositor_discard_frame(struct xrt_compositor *xc, int64_t frame_id)
|
||||
{
|
||||
struct sdl_compositor *c = &from_comp(xc)->c;
|
||||
SC_TRACE(c, "DISCARD_FRAME");
|
||||
|
||||
// Shouldn't be called.
|
||||
assert(false);
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static xrt_result_t
|
||||
sdl_compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_graphics_sync_handle_t sync_handle)
|
||||
{
|
||||
COMP_TRACE_MARKER();
|
||||
|
||||
struct sdl_program *sp = from_comp(xc);
|
||||
struct sdl_compositor *c = &sp->c;
|
||||
|
||||
SC_TRACE(c, "LAYER_COMMIT");
|
||||
|
||||
/*
|
||||
* The null compositor doesn't render and frames, but needs to do
|
||||
* minimal bookkeeping and handling of arguments. If using the null
|
||||
* compositor as a base for a new compositor this is where you render
|
||||
* frames to be displayed to devices or remote clients.
|
||||
*/
|
||||
|
||||
u_graphics_sync_unref(&sync_handle);
|
||||
|
||||
/*
|
||||
* Time keeping needed to keep the pacer happy.
|
||||
*/
|
||||
|
||||
// When we begin rendering.
|
||||
{
|
||||
uint64_t now_ns = os_monotonic_get_ns();
|
||||
u_pc_mark_point(c->upc, U_TIMING_POINT_BEGIN, frame_id, now_ns);
|
||||
}
|
||||
|
||||
// Render with SDL.
|
||||
sdl_program_plus_render(sp->spp);
|
||||
|
||||
// When we are submitting to the GPU.
|
||||
{
|
||||
uint64_t now_ns = os_monotonic_get_ns();
|
||||
u_pc_mark_point(c->upc, U_TIMING_POINT_SUBMIT, frame_id, now_ns);
|
||||
}
|
||||
|
||||
// Now is a good point to garbage collect.
|
||||
comp_swapchain_garbage_collect(&c->base.cscgc);
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static xrt_result_t
|
||||
sdl_compositor_poll_events(struct xrt_compositor *xc, union xrt_compositor_event *out_xce)
|
||||
{
|
||||
struct sdl_compositor *c = &from_comp(xc)->c;
|
||||
|
||||
SC_TRACE(c, "POLL_EVENTS");
|
||||
|
||||
/*
|
||||
* The null compositor does only minimal state keeping. If using the
|
||||
* null compositor as a base for a new compositor this is where you can
|
||||
* improve the state tracking. Note this is very often consumed only
|
||||
* by the multi compositor.
|
||||
*/
|
||||
|
||||
U_ZERO(out_xce);
|
||||
|
||||
switch (c->state) {
|
||||
case SDL_COMP_STATE_UNINITIALIZED:
|
||||
SC_ERROR(c, "Polled uninitialized compositor");
|
||||
out_xce->state.type = XRT_COMPOSITOR_EVENT_NONE;
|
||||
break;
|
||||
case SDL_COMP_STATE_READY: out_xce->state.type = XRT_COMPOSITOR_EVENT_NONE; break;
|
||||
case SDL_COMP_STATE_PREPARED:
|
||||
SC_DEBUG(c, "PREPARED -> VISIBLE");
|
||||
out_xce->state.type = XRT_COMPOSITOR_EVENT_STATE_CHANGE;
|
||||
out_xce->state.visible = true;
|
||||
c->state = SDL_COMP_STATE_VISIBLE;
|
||||
break;
|
||||
case SDL_COMP_STATE_VISIBLE:
|
||||
SC_DEBUG(c, "VISIBLE -> FOCUSED");
|
||||
out_xce->state.type = XRT_COMPOSITOR_EVENT_STATE_CHANGE;
|
||||
out_xce->state.visible = true;
|
||||
out_xce->state.focused = true;
|
||||
c->state = SDL_COMP_STATE_FOCUSED;
|
||||
break;
|
||||
case SDL_COMP_STATE_FOCUSED:
|
||||
// No more transitions.
|
||||
out_xce->state.type = XRT_COMPOSITOR_EVENT_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
sdl_compositor_destroy(struct xrt_compositor *xc)
|
||||
{
|
||||
struct sdl_compositor *c = &from_comp(xc)->c;
|
||||
struct vk_bundle *vk = get_vk(c);
|
||||
|
||||
SC_DEBUG(c, "DESTROY");
|
||||
|
||||
// Make sure we don't have anything to destroy.
|
||||
comp_swapchain_garbage_collect(&c->base.cscgc);
|
||||
|
||||
|
||||
if (vk->cmd_pool != VK_NULL_HANDLE) {
|
||||
vk->vkDestroyCommandPool(vk->device, vk->cmd_pool, NULL);
|
||||
vk->cmd_pool = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (vk->device != VK_NULL_HANDLE) {
|
||||
vk->vkDestroyDevice(vk->device, NULL);
|
||||
vk->device = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
vk_deinit_mutex(vk);
|
||||
|
||||
if (vk->instance != VK_NULL_HANDLE) {
|
||||
vk->vkDestroyInstance(vk->instance, NULL);
|
||||
vk->instance = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
comp_base_fini(&c->base);
|
||||
|
||||
u_pc_destroy(&c->upc);
|
||||
|
||||
// Don't free as we are sub allocated.
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* 'Exported' functions.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
sdl_compositor_init(struct sdl_program *sp)
|
||||
{
|
||||
struct xrt_device *xdev = &sp->xdev_base;
|
||||
enum u_logging_level log_level = sp->log_level;
|
||||
|
||||
struct sdl_compositor *c = &sp->c;
|
||||
|
||||
c->base.base.base.begin_session = sdl_compositor_begin_session;
|
||||
c->base.base.base.end_session = sdl_compositor_end_session;
|
||||
c->base.base.base.predict_frame = sdl_compositor_predict_frame;
|
||||
c->base.base.base.mark_frame = sdl_compositor_mark_frame;
|
||||
c->base.base.base.begin_frame = sdl_compositor_begin_frame;
|
||||
c->base.base.base.discard_frame = sdl_compositor_discard_frame;
|
||||
c->base.base.base.layer_commit = sdl_compositor_layer_commit;
|
||||
c->base.base.base.poll_events = sdl_compositor_poll_events;
|
||||
c->base.base.base.destroy = sdl_compositor_destroy;
|
||||
c->base.vk.log_level = log_level;
|
||||
c->frame.waited.id = -1;
|
||||
c->frame.rendering.id = -1;
|
||||
c->state = SDL_COMP_STATE_READY;
|
||||
c->settings.frame_interval_ns = U_TIME_1S_IN_NS / 20; // 20 FPS
|
||||
|
||||
SC_DEBUG(c, "Doing init %p", (void *)c);
|
||||
|
||||
// Do this as early as possible
|
||||
comp_base_init(&c->base);
|
||||
|
||||
// Override some comp_base functions.
|
||||
c->base.base.base.create_swapchain = sdl_swapchain_create;
|
||||
c->base.base.base.import_swapchain = sdl_swapchain_import;
|
||||
|
||||
|
||||
/*
|
||||
* Main init sequence.
|
||||
*/
|
||||
|
||||
if (!compositor_init_pacing(c) || //
|
||||
!compositor_init_vulkan(c, log_level) || //
|
||||
!compositor_init_sys_info(c, sp, xdev) || //
|
||||
!compositor_init_info(c)) { //
|
||||
SC_DEBUG(c, "Failed to init compositor %p", (void *)c);
|
||||
c->base.base.base.destroy(&c->base.base.base);
|
||||
|
||||
assert(false);
|
||||
}
|
||||
|
||||
SC_DEBUG(c, "Done %p", (void *)c);
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
sdl_compositor_create_system(struct sdl_program *sp, struct xrt_system_compositor **out_xsysc)
|
||||
{
|
||||
// Standard app pacer.
|
||||
struct u_pacing_app_factory *upaf = NULL;
|
||||
xrt_result_t xret = u_pa_factory_create(&upaf);
|
||||
assert(xret == XRT_SUCCESS && upaf != NULL);
|
||||
|
||||
return comp_multi_create_system_compositor(&sp->c.base.base, upaf, &sp->c.sys_info, out_xsysc);
|
||||
}
|
149
src/xrt/targets/sdl_test/sdl_device.c
Normal file
149
src/xrt/targets/sdl_test/sdl_device.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
// Copyright 2020-2022, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Shared default implementation of the device with compositor.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
*/
|
||||
|
||||
#include "sdl_internal.h"
|
||||
|
||||
#include "util/u_device.h"
|
||||
#include "util/u_distortion_mesh.h"
|
||||
|
||||
|
||||
static void
|
||||
sdl_hmd_update_inputs(struct xrt_device *xdev)
|
||||
{
|
||||
// Empty, you should put code to update the attached inputs fields.
|
||||
}
|
||||
|
||||
static void
|
||||
sdl_hmd_get_tracked_pose(struct xrt_device *xdev,
|
||||
enum xrt_input_name name,
|
||||
uint64_t at_timestamp_ns,
|
||||
struct xrt_space_relation *out_relation)
|
||||
{
|
||||
struct sdl_program *sp = from_xdev(xdev);
|
||||
|
||||
if (name != XRT_INPUT_GENERIC_HEAD_POSE) {
|
||||
U_LOG_E("Unknown input name");
|
||||
return;
|
||||
}
|
||||
|
||||
struct xrt_space_relation relation = XRT_SPACE_RELATION_ZERO;
|
||||
|
||||
relation.pose = sp->state.head.pose;
|
||||
relation.relation_flags = //
|
||||
XRT_SPACE_RELATION_POSITION_TRACKED_BIT | //
|
||||
XRT_SPACE_RELATION_POSITION_VALID_BIT | //
|
||||
XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | //
|
||||
XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT; //
|
||||
|
||||
*out_relation = relation;
|
||||
}
|
||||
|
||||
static void
|
||||
sdl_hmd_get_view_poses(struct xrt_device *xdev,
|
||||
const struct xrt_vec3 *default_eye_relation,
|
||||
uint64_t at_timestamp_ns,
|
||||
uint32_t view_count,
|
||||
struct xrt_space_relation *out_head_relation,
|
||||
struct xrt_fov *out_fovs,
|
||||
struct xrt_pose *out_poses)
|
||||
{
|
||||
u_device_get_view_poses( //
|
||||
xdev, //
|
||||
default_eye_relation, //
|
||||
at_timestamp_ns, //
|
||||
view_count, //
|
||||
out_head_relation, //
|
||||
out_fovs, //
|
||||
out_poses); //
|
||||
}
|
||||
|
||||
static void
|
||||
sdl_hmd_destroy(struct xrt_device *xdev)
|
||||
{
|
||||
struct sdl_program *sp = from_xdev(xdev);
|
||||
|
||||
if (xdev->hmd->distortion.mesh.vertices) {
|
||||
free(xdev->hmd->distortion.mesh.vertices);
|
||||
xdev->hmd->distortion.mesh.vertices = NULL;
|
||||
}
|
||||
|
||||
if (xdev->hmd->distortion.mesh.indices) {
|
||||
free(xdev->hmd->distortion.mesh.indices);
|
||||
xdev->hmd->distortion.mesh.indices = NULL;
|
||||
}
|
||||
|
||||
(void)sp; // We are apart of sdl_program, do not free.
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* 'Exported' functions.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
sdl_device_init(struct sdl_program *sp)
|
||||
{
|
||||
struct xrt_device *xdev = &sp->xdev_base;
|
||||
|
||||
// Setup pointers.
|
||||
xdev->inputs = sp->inputs;
|
||||
xdev->input_count = ARRAY_SIZE(sp->inputs);
|
||||
xdev->tracking_origin = &sp->origin;
|
||||
xdev->hmd = &sp->hmd;
|
||||
|
||||
// Name and type.
|
||||
xdev->name = XRT_DEVICE_GENERIC_HMD;
|
||||
xdev->device_type = XRT_DEVICE_TYPE_HMD;
|
||||
|
||||
// Print name.
|
||||
snprintf(xdev->str, XRT_DEVICE_NAME_LEN, "SDL HMD");
|
||||
snprintf(xdev->serial, XRT_DEVICE_NAME_LEN, "SDL HMD");
|
||||
|
||||
// Input info.
|
||||
xdev->inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE;
|
||||
xdev->inputs[0].active = true;
|
||||
|
||||
// Function pointers.
|
||||
xdev->update_inputs = sdl_hmd_update_inputs;
|
||||
xdev->get_tracked_pose = sdl_hmd_get_tracked_pose;
|
||||
xdev->get_view_poses = sdl_hmd_get_view_poses;
|
||||
xdev->destroy = sdl_hmd_destroy;
|
||||
|
||||
// Minimum needed stuff.
|
||||
struct u_device_simple_info info;
|
||||
info.display.w_pixels = 1280;
|
||||
info.display.h_pixels = 720;
|
||||
info.display.w_meters = 0.13f;
|
||||
info.display.h_meters = 0.07f;
|
||||
info.lens_horizontal_separation_meters = 0.13f / 2.0f;
|
||||
info.lens_vertical_position_meters = 0.07f / 2.0f;
|
||||
info.fov[0] = 85.0f * ((float)(M_PI) / 180.0f);
|
||||
info.fov[1] = 85.0f * ((float)(M_PI) / 180.0f);
|
||||
|
||||
if (!u_device_setup_split_side_by_side(xdev, &info)) {
|
||||
U_LOG_E("Failed to setup basic device info");
|
||||
return;
|
||||
}
|
||||
|
||||
// Refresh rate.
|
||||
xdev->hmd->screens[0].nominal_frame_interval_ns = time_s_to_ns(1.0f / 60.0f);
|
||||
|
||||
// Blend mode(s), setup after u_device_setup_split_side_by_side.
|
||||
xdev->hmd->blend_modes[0] = XRT_BLEND_MODE_OPAQUE;
|
||||
xdev->hmd->blend_mode_count = 1;
|
||||
|
||||
// Distortion information, fills in xdev->compute_distortion().
|
||||
u_distortion_mesh_set_none(xdev);
|
||||
|
||||
// Tracking origin.
|
||||
xdev->tracking_origin->offset = (struct xrt_pose)XRT_POSE_IDENTITY;
|
||||
xdev->tracking_origin->type = XRT_TRACKING_TYPE_OTHER;
|
||||
snprintf(xdev->tracking_origin->name, XRT_TRACKING_NAME_LEN, "SDL Tracking");
|
||||
}
|
31
src/xrt/targets/sdl_test/sdl_hack_stubs.c
Normal file
31
src/xrt/targets/sdl_test/sdl_hack_stubs.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2019-2022, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Stubs needed to be able to link in the ipc layer.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
*/
|
||||
|
||||
#include "xrt/xrt_compiler.h"
|
||||
|
||||
struct xrt_instance;
|
||||
struct xrt_system_devices;
|
||||
|
||||
|
||||
int
|
||||
oxr_sdl2_hack_create(void **out_hack)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
oxr_sdl2_hack_start(void *hack, struct xrt_instance *xinst, struct xrt_system_devices *xsysd)
|
||||
{
|
||||
// Noop
|
||||
}
|
||||
|
||||
void
|
||||
oxr_sdl2_hack_stop(void **hack)
|
||||
{
|
||||
// Noop
|
||||
}
|
129
src/xrt/targets/sdl_test/sdl_instance.c
Normal file
129
src/xrt/targets/sdl_test/sdl_instance.c
Normal file
|
@ -0,0 +1,129 @@
|
|||
// Copyright 2020-2022, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Shared default implementation of the instance with compositor.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
*/
|
||||
|
||||
#include "xrt/xrt_system.h"
|
||||
#include "xrt/xrt_instance.h"
|
||||
#include "xrt/xrt_config_drivers.h"
|
||||
|
||||
#include "util/u_misc.h"
|
||||
#include "util/u_trace_marker.h"
|
||||
|
||||
#include "sdl_internal.h"
|
||||
|
||||
#if 0 && defined(XRT_BUILD_DRIVER_SIMULATED)
|
||||
#include "simulated/simulated_interface.h"
|
||||
#define USE_SIMULATED
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* System devices functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
sdl_system_devices_destroy(struct xrt_system_devices *xsysd)
|
||||
{
|
||||
struct sdl_program *sp = from_xsysd(xsysd);
|
||||
|
||||
for (size_t i = 0; i < xsysd->xdev_count; i++) {
|
||||
xrt_device_destroy(&xsysd->xdevs[i]);
|
||||
}
|
||||
|
||||
(void)sp; // We are apart of sdl_program, do not free.
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Instance functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static xrt_result_t
|
||||
sdl_instance_get_prober(struct xrt_instance *xinst, struct xrt_prober **out_xp)
|
||||
{
|
||||
return XRT_ERROR_PROBER_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static xrt_result_t
|
||||
sdl_instance_create_system(struct xrt_instance *xinst,
|
||||
struct xrt_system_devices **out_xsysd,
|
||||
struct xrt_system_compositor **out_xsysc)
|
||||
{
|
||||
assert(out_xsysd != NULL);
|
||||
assert(*out_xsysd == NULL);
|
||||
assert(out_xsysc == NULL || *out_xsysc == NULL);
|
||||
|
||||
struct sdl_program *sp = from_xinst(xinst);
|
||||
|
||||
*out_xsysd = &sp->xsysd_base;
|
||||
|
||||
// Early out if we only want devices.
|
||||
if (out_xsysc == NULL) {
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
sdl_compositor_create_system(sp, out_xsysc);
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
sdl_instance_destroy(struct xrt_instance *xinst)
|
||||
{
|
||||
struct sdl_program *sp = from_xinst(xinst);
|
||||
|
||||
// Frees struct.
|
||||
sdl_program_plus_destroy(sp->spp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Exported function(s).
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
sdl_system_devices_init(struct sdl_program *sp)
|
||||
{
|
||||
sp->xsysd_base.destroy = sdl_system_devices_destroy;
|
||||
|
||||
#ifdef USE_SIMULATED
|
||||
struct xrt_device *head = simulated_hmd_create();
|
||||
#else
|
||||
struct xrt_device *head = &sp->xdev_base;
|
||||
#endif
|
||||
|
||||
// Setup the device base as the only device.
|
||||
sp->xsysd_base.xdevs[0] = head;
|
||||
sp->xsysd_base.xdev_count = 1;
|
||||
sp->xsysd_base.roles.head = head;
|
||||
}
|
||||
|
||||
void
|
||||
sdl_instance_init(struct sdl_program *sp)
|
||||
{
|
||||
sp->xinst_base.create_system = sdl_instance_create_system;
|
||||
sp->xinst_base.get_prober = sdl_instance_get_prober;
|
||||
sp->xinst_base.destroy = sdl_instance_destroy;
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
xrt_instance_create(struct xrt_instance_info *ii, struct xrt_instance **out_xinst)
|
||||
{
|
||||
u_trace_marker_init();
|
||||
|
||||
struct sdl_program *sp = sdl_program_plus_create();
|
||||
|
||||
*out_xinst = &sp->xinst_base;
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
410
src/xrt/targets/sdl_test/sdl_internal.h
Normal file
410
src/xrt/targets/sdl_test/sdl_internal.h
Normal file
|
@ -0,0 +1,410 @@
|
|||
// Copyright 2020-2022, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Internal header for SDL XR system.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
|
||||
#include "xrt/xrt_system.h"
|
||||
#include "xrt/xrt_device.h"
|
||||
#include "xrt/xrt_instance.h"
|
||||
#include "xrt/xrt_tracking.h"
|
||||
#include "xrt/xrt_compositor.h"
|
||||
|
||||
#include "util/u_pacing.h"
|
||||
#include "util/u_logging.h"
|
||||
#include "util/comp_base.h"
|
||||
#include "util/comp_swapchain.h"
|
||||
|
||||
#include "SDL2/SDL.h"
|
||||
|
||||
#include "ogl/ogl_api.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct sdl_program;
|
||||
|
||||
/*!
|
||||
* Sub-class of @ref comp_swapchain, used to do OpenGL rendering.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
struct sdl_swapchain
|
||||
{
|
||||
struct comp_swapchain base;
|
||||
|
||||
//! Pointer back to main program.
|
||||
struct sdl_program *sp;
|
||||
|
||||
//! Cached width and height.
|
||||
int w, h;
|
||||
|
||||
//! Number of textures in base.base.base.image_count.
|
||||
GLuint textures[XRT_MAX_SWAPCHAIN_IMAGES];
|
||||
|
||||
//! Same number of images as textures.
|
||||
GLuint memory[XRT_MAX_SWAPCHAIN_IMAGES];
|
||||
};
|
||||
|
||||
/*!
|
||||
* State to emulate state transitions correctly.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
enum sdl_comp_state
|
||||
{
|
||||
SDL_COMP_STATE_UNINITIALIZED = 0,
|
||||
SDL_COMP_STATE_READY = 1,
|
||||
SDL_COMP_STATE_PREPARED = 2,
|
||||
SDL_COMP_STATE_VISIBLE = 3,
|
||||
SDL_COMP_STATE_FOCUSED = 4,
|
||||
};
|
||||
|
||||
/*!
|
||||
* Tracking frame state.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
struct sdl_comp_frame
|
||||
{
|
||||
int64_t id;
|
||||
uint64_t predicted_display_time_ns;
|
||||
uint64_t desired_present_time_ns;
|
||||
uint64_t present_slop_ns;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Split out for convinecne.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
struct sdl_compositor
|
||||
{
|
||||
//! Base native compositor.
|
||||
struct comp_base base;
|
||||
|
||||
//! Pacing helper to drive us forward.
|
||||
struct u_pacing_compositor *upc;
|
||||
|
||||
struct
|
||||
{
|
||||
//! Frame interval that we are using.
|
||||
uint64_t frame_interval_ns;
|
||||
} settings;
|
||||
|
||||
// Kept here for convenience.
|
||||
struct xrt_system_compositor_info sys_info;
|
||||
|
||||
//! State for generating the correct set of events.
|
||||
enum sdl_comp_state state;
|
||||
|
||||
//! @todo Insert your own required members here
|
||||
|
||||
struct
|
||||
{
|
||||
struct sdl_comp_frame waited;
|
||||
struct sdl_comp_frame rendering;
|
||||
} frame;
|
||||
};
|
||||
|
||||
struct sdl_program_plus;
|
||||
|
||||
/*!
|
||||
* C base class for the SDL program.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
struct sdl_program
|
||||
{
|
||||
//! Base class for devices.
|
||||
struct xrt_device xdev_base;
|
||||
|
||||
//! Instance base.
|
||||
struct xrt_instance xinst_base;
|
||||
|
||||
//! System devices base.
|
||||
struct xrt_system_devices xsysd_base;
|
||||
|
||||
//! SDL compositor struct.
|
||||
struct sdl_compositor c;
|
||||
|
||||
//! Created system compositor.
|
||||
struct xrt_system_compositor *xsysc;
|
||||
|
||||
//! Inputs exposed by the SDL device.
|
||||
struct xrt_input inputs[1];
|
||||
|
||||
//! HMD parts exposed by the SDL device to become a HMD.
|
||||
struct xrt_hmd_parts hmd;
|
||||
|
||||
//! Tracking origin that the device is located in.
|
||||
struct xrt_tracking_origin origin;
|
||||
|
||||
//! The current log level.
|
||||
enum u_logging_level log_level;
|
||||
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
//! The pose of the head, only used for view space.
|
||||
struct xrt_pose pose;
|
||||
} head;
|
||||
|
||||
struct
|
||||
{
|
||||
//! Pose of each individual eye.
|
||||
struct xrt_pose pose;
|
||||
|
||||
//! Fov of each individual eye.
|
||||
struct xrt_fov fov;
|
||||
} left, right;
|
||||
} state;
|
||||
|
||||
//! The main window.
|
||||
SDL_Window *win;
|
||||
|
||||
//! Main OpenGL context.
|
||||
SDL_GLContext ctx;
|
||||
|
||||
//! Protects the OpenGL context.
|
||||
struct os_mutex current_mutex;
|
||||
|
||||
//! Pointer back to the C++ part of the program.
|
||||
struct sdl_program_plus *spp;
|
||||
};
|
||||
|
||||
|
||||
static inline struct sdl_program *
|
||||
from_xinst(struct xrt_instance *xinst)
|
||||
{
|
||||
return container_of(xinst, struct sdl_program, xinst_base);
|
||||
}
|
||||
|
||||
static inline struct sdl_program *
|
||||
from_xsysd(struct xrt_system_devices *xsysd)
|
||||
{
|
||||
return container_of(xsysd, struct sdl_program, xsysd_base);
|
||||
}
|
||||
|
||||
static inline struct sdl_program *
|
||||
from_xdev(struct xrt_device *xdev)
|
||||
{
|
||||
return container_of(xdev, struct sdl_program, xdev_base);
|
||||
}
|
||||
|
||||
static inline struct sdl_program *
|
||||
from_comp(struct xrt_compositor *xc)
|
||||
{
|
||||
return container_of(xc, struct sdl_program, c.base.base);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Spew level logging.
|
||||
*
|
||||
* @relates sdl_program
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
#define SP_TRACE(sp, ...) U_LOG_IFL_T(sp->log_level, __VA_ARGS__);
|
||||
|
||||
/*!
|
||||
* Debug level logging.
|
||||
*
|
||||
* @relates sdl_program
|
||||
*/
|
||||
#define SP_DEBUG(sp, ...) U_LOG_IFL_D(sp->log_level, __VA_ARGS__);
|
||||
|
||||
/*!
|
||||
* Info level logging.
|
||||
*
|
||||
* @relates sdl_program
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
#define SP_INFO(sp, ...) U_LOG_IFL_I(sp->log_level, __VA_ARGS__);
|
||||
|
||||
/*!
|
||||
* Warn level logging.
|
||||
*
|
||||
* @relates sdl_program
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
#define SP_WARN(sp, ...) U_LOG_IFL_W(sp->log_level, __VA_ARGS__);
|
||||
|
||||
/*!
|
||||
* Error level logging.
|
||||
*
|
||||
* @relates sdl_program
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
#define SP_ERROR(sp, ...) U_LOG_IFL_E(sp->log_level, __VA_ARGS__);
|
||||
|
||||
/*!
|
||||
* Check for OpenGL errors, context needs to be current.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
#define CHECK_GL() \
|
||||
do { \
|
||||
GLint err = glGetError(); \
|
||||
if (err != 0) { \
|
||||
U_LOG_RAW("%s:%u: error: 0x%04x", __func__, __LINE__, err); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
/*!
|
||||
* Makes the OpenGL context current in this thread, takes lock.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
static inline void
|
||||
sdl_make_current(struct sdl_program *sp)
|
||||
{
|
||||
os_mutex_lock(&sp->current_mutex);
|
||||
SDL_GL_MakeCurrent(sp->win, sp->ctx);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Unmakes the any OpenGL context current in this thread, releases the lock.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
static inline void
|
||||
sdl_make_uncurrent(struct sdl_program *sp)
|
||||
{
|
||||
SDL_GL_MakeCurrent(NULL, NULL);
|
||||
os_mutex_unlock(&sp->current_mutex);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* sdl_device.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Init the @ref xrt_device sub struct.
|
||||
*
|
||||
* In sdl_device.c
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
void
|
||||
sdl_device_init(struct sdl_program *sp);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* sdl_swapchain.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Implementation of @ref xrt_compositor::create_swapchain.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
xrt_result_t
|
||||
sdl_swapchain_create(struct xrt_compositor *xc,
|
||||
const struct xrt_swapchain_create_info *info,
|
||||
struct xrt_swapchain **out_xsc);
|
||||
|
||||
/*!
|
||||
* Implementation of @ref xrt_compositor::import_swapchain.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
xrt_result_t
|
||||
sdl_swapchain_import(struct xrt_compositor *xc,
|
||||
const struct xrt_swapchain_create_info *info,
|
||||
struct xrt_image_native *native_images,
|
||||
uint32_t native_image_count,
|
||||
struct xrt_swapchain **out_xsc);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* sdl_compositor.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Initializes the compositor part of the SDL program.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
void
|
||||
sdl_compositor_init(struct sdl_program *sp);
|
||||
|
||||
/*!
|
||||
* Creates the system compositor that wraps the native compositor.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
xrt_result_t
|
||||
sdl_compositor_create_system(struct sdl_program *sp, struct xrt_system_compositor **out_xsysc);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* sdl_instance.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Init the @ref xrt_system_devices sub struct.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
void
|
||||
sdl_system_devices_init(struct sdl_program *sp);
|
||||
|
||||
/*!
|
||||
* Init the @ref xrt_instance sub struct.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
void
|
||||
sdl_instance_init(struct sdl_program *sp);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* sdl_program.cpp
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Create the SDL program.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
struct sdl_program *
|
||||
sdl_program_plus_create();
|
||||
|
||||
/*!
|
||||
* Render a frame, called by the compositor when layers have been committed.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
void
|
||||
sdl_program_plus_render(struct sdl_program_plus *spp);
|
||||
|
||||
/*!
|
||||
* Destroy the SDL program.
|
||||
*
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
void
|
||||
sdl_program_plus_destroy(struct sdl_program_plus *spp);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
21
src/xrt/targets/sdl_test/sdl_internal.hpp
Normal file
21
src/xrt/targets/sdl_test/sdl_internal.hpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2020-2022, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Internal C++ header for SDL XR system.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __cplusplus
|
||||
#error "This header is C++ only"
|
||||
#endif
|
||||
|
||||
#include "sdl_internal.h"
|
||||
|
||||
struct sdl_program_plus : sdl_program
|
||||
{
|
||||
// CPP only things
|
||||
};
|
28
src/xrt/targets/sdl_test/sdl_main.c
Normal file
28
src/xrt/targets/sdl_test/sdl_main.c
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2019-2022, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Main file for sdl compositor experiments.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
*/
|
||||
|
||||
#include "util/u_trace_marker.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_main.h>
|
||||
|
||||
|
||||
// Insert the on load constructor to init trace marker.
|
||||
U_TRACE_TARGET_SETUP(U_TRACE_WHICH_SERVICE)
|
||||
|
||||
int
|
||||
ipc_server_main(int argc, char *argv[]);
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
u_trace_marker_init();
|
||||
|
||||
return ipc_server_main(argc, argv);
|
||||
}
|
178
src/xrt/targets/sdl_test/sdl_program.cpp
Normal file
178
src/xrt/targets/sdl_test/sdl_program.cpp
Normal file
|
@ -0,0 +1,178 @@
|
|||
// Copyright 2020-2022, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief C++ program part for the SDL test.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
|
||||
#include "ogl/ogl_api.h"
|
||||
|
||||
#include "util/u_misc.h"
|
||||
|
||||
#include "sdl_internal.hpp"
|
||||
|
||||
|
||||
void
|
||||
sdl_create_window(struct sdl_program *sp)
|
||||
{
|
||||
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
char title[1024];
|
||||
snprintf(title, sizeof(title), "Monado! ☃");
|
||||
|
||||
int x = SDL_WINDOWPOS_UNDEFINED;
|
||||
int y = SDL_WINDOWPOS_UNDEFINED;
|
||||
int w = 1920;
|
||||
int h = 1080;
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||
|
||||
int window_flags = 0;
|
||||
window_flags |= SDL_WINDOW_SHOWN;
|
||||
window_flags |= SDL_WINDOW_OPENGL;
|
||||
window_flags |= SDL_WINDOW_RESIZABLE;
|
||||
window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
#if 0
|
||||
window_flags |= SDL_WINDOW_MAXIMIZED;
|
||||
#endif
|
||||
|
||||
|
||||
sp->win = SDL_CreateWindow(title, x, y, w, h, window_flags);
|
||||
|
||||
if (sp->win == NULL) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
sp->ctx = SDL_GL_CreateContext(sp->win);
|
||||
if (sp->ctx == NULL) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// Make the context current in this thread for loading OpenGL.
|
||||
sdl_make_current(sp);
|
||||
SDL_GL_SetSwapInterval(1); // Enable vsync
|
||||
|
||||
// Setup OpenGL bindings.
|
||||
bool err = gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress) == 0;
|
||||
if (err) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// We are going to render on a different thread, make sure to unbind it.
|
||||
sdl_make_uncurrent(sp);
|
||||
}
|
||||
|
||||
extern "C" struct sdl_program *
|
||||
sdl_program_plus_create()
|
||||
{
|
||||
sdl_program_plus &spp = *new sdl_program_plus();
|
||||
spp.spp = &spp;
|
||||
|
||||
os_mutex_init(&spp.current_mutex);
|
||||
|
||||
// Initial state.
|
||||
spp.log_level = U_LOGGING_INFO;
|
||||
spp.state.head.pose = XRT_POSE_IDENTITY;
|
||||
|
||||
// Create the window, init before sub components.
|
||||
sdl_create_window(&spp);
|
||||
|
||||
// Init sub components.
|
||||
sdl_instance_init(&spp);
|
||||
sdl_system_devices_init(&spp);
|
||||
sdl_device_init(&spp);
|
||||
sdl_compositor_init(&spp); // Needs the window.
|
||||
|
||||
return &spp;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
sdl_program_plus_render(struct sdl_program_plus *spp_ptr)
|
||||
{
|
||||
auto &spp = *spp_ptr;
|
||||
|
||||
// Make context current
|
||||
sdl_make_current(&spp);
|
||||
|
||||
// Flush the events.
|
||||
SDL_Event e = {0};
|
||||
while (SDL_PollEvent(&e)) {
|
||||
// Nothing for now.
|
||||
}
|
||||
|
||||
if (spp.c.base.slot.layer_count == 0) {
|
||||
glClearColor(0.2f, 0.2f, 0.2f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
} else if (spp.c.base.slot.layers[0].data.type == XRT_LAYER_STEREO_PROJECTION ||
|
||||
spp.c.base.slot.layers[0].data.type == XRT_LAYER_STEREO_PROJECTION_DEPTH) {
|
||||
|
||||
auto &l = spp.c.base.slot.layers[0];
|
||||
auto &ssc = *(sdl_swapchain *)l.sc_array[0];
|
||||
GLuint tex = ssc.textures[l.data.stereo.l.sub.image_index];
|
||||
|
||||
glClearColor(0.2f, 0.0f, 0.0f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
GLuint fbo = 0;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
CHECK_GL();
|
||||
|
||||
glFramebufferTexture2D( //
|
||||
GL_READ_FRAMEBUFFER, // GLenum target
|
||||
GL_COLOR_ATTACHMENT0, // GLenum attachment
|
||||
GL_TEXTURE_2D, // GLenum textarget
|
||||
tex, // GLuint texture
|
||||
0); // GLint level
|
||||
CHECK_GL();
|
||||
|
||||
int w, h;
|
||||
SDL_GetWindowSize(spp.win, &w, &h);
|
||||
glBlitFramebuffer( //
|
||||
0, // GLint srcX0
|
||||
0, // GLint srcY0
|
||||
ssc.w, // GLint srcX1
|
||||
ssc.h, // GLint srcY1
|
||||
0, // GLint dstX0
|
||||
0, // GLint dstY0
|
||||
w, // GLint dstX1
|
||||
h, // GLint dstY1
|
||||
GL_COLOR_BUFFER_BIT, // GLbitfield mask
|
||||
GL_NEAREST); // GLenum filter
|
||||
CHECK_GL();
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
CHECK_GL();
|
||||
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
} else {
|
||||
glClearColor(1.0f, 0.0f, 1.0f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
// Display what we rendered.
|
||||
SDL_GL_SwapWindow(spp.win);
|
||||
|
||||
// Will be used when creating swapchains, unbind it.
|
||||
sdl_make_uncurrent(&spp);
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
sdl_program_plus_destroy(struct sdl_program_plus *spp)
|
||||
{
|
||||
os_mutex_destroy(&spp->current_mutex);
|
||||
|
||||
delete spp;
|
||||
}
|
214
src/xrt/targets/sdl_test/sdl_swapchain.c
Normal file
214
src/xrt/targets/sdl_test/sdl_swapchain.c
Normal file
|
@ -0,0 +1,214 @@
|
|||
// Copyright 2022, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Swapchain code for the sdl code.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup sdl_test
|
||||
*/
|
||||
|
||||
#include "sdl_internal.h"
|
||||
|
||||
#include "util/u_handles.h"
|
||||
#include "ogl/ogl_helpers.h"
|
||||
|
||||
|
||||
static int64_t
|
||||
vk_format_to_gl(int64_t format)
|
||||
{
|
||||
switch (format) {
|
||||
case 4 /* VK_FORMAT_R5G6B5_UNORM_PACK16 */: return 0; // GL_RGB565?
|
||||
case 23 /* VK_FORMAT_R8G8B8_UNORM */: return GL_RGB8; // Should not be used, colour precision.
|
||||
case 29 /* VK_FORMAT_R8G8B8_SRGB */: return GL_SRGB8;
|
||||
case 30 /* VK_FORMAT_B8G8R8_UNORM */: return 0;
|
||||
case 37 /* VK_FORMAT_R8G8B8A8_UNORM */: return GL_RGBA8; // Should not be used, colour precision.
|
||||
case 43 /* VK_FORMAT_R8G8B8A8_SRGB */: return GL_SRGB8_ALPHA8;
|
||||
case 44 /* VK_FORMAT_B8G8R8A8_UNORM */: return 0;
|
||||
case 50 /* VK_FORMAT_B8G8R8A8_SRGB */: return 0;
|
||||
case 64 /* VK_FORMAT_A2B10G10R10_UNORM_PACK32 */: return GL_RGB10_A2;
|
||||
case 84 /* VK_FORMAT_R16G16B16_UNORM */: return GL_RGB16;
|
||||
case 90 /* VK_FORMAT_R16G16B16_SFLOAT */: return GL_RGB16F;
|
||||
case 91 /* VK_FORMAT_R16G16B16A16_UNORM */: return GL_RGBA16;
|
||||
case 97 /* VK_FORMAT_R16G16B16A16_SFLOAT */: return GL_RGBA16F;
|
||||
case 124 /* VK_FORMAT_D16_UNORM */: return GL_DEPTH_COMPONENT16;
|
||||
case 125 /* VK_FORMAT_X8_D24_UNORM_PACK32 */: return 0; // GL_DEPTH_COMPONENT24?
|
||||
case 126 /* VK_FORMAT_D32_SFLOAT */: return GL_DEPTH_COMPONENT32F;
|
||||
case 127 /* VK_FORMAT_S8_UINT */: return 0; // GL_STENCIL_INDEX8?
|
||||
case 129 /* VK_FORMAT_D24_UNORM_S8_UINT */: return GL_DEPTH24_STENCIL8;
|
||||
case 130 /* VK_FORMAT_D32_SFLOAT_S8_UINT */: return GL_DEPTH32F_STENCIL8;
|
||||
default: U_LOG_W("Cannot convert VK format %" PRIu64 " to GL format!", format); return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
post_init_setup(struct sdl_swapchain *ssc, struct sdl_program *sp, const struct xrt_swapchain_create_info *info)
|
||||
{
|
||||
SP_DEBUG(sp, "CREATE");
|
||||
|
||||
// Setup fields
|
||||
ssc->sp = sp;
|
||||
ssc->w = (int)info->width;
|
||||
ssc->h = (int)info->height;
|
||||
|
||||
|
||||
sdl_make_current(sp);
|
||||
|
||||
GLuint binding_enum = 0;
|
||||
GLuint tex_target = 0;
|
||||
ogl_texture_target_for_swapchain_info(info, &tex_target, &binding_enum);
|
||||
|
||||
uint32_t image_count = ssc->base.base.base.image_count;
|
||||
GLuint gl_format = vk_format_to_gl(info->format);
|
||||
|
||||
glCreateTextures(tex_target, image_count, ssc->textures);
|
||||
CHECK_GL();
|
||||
glCreateMemoryObjectsEXT(image_count, ssc->memory);
|
||||
CHECK_GL();
|
||||
|
||||
for (uint32_t i = 0; i < image_count; i++) {
|
||||
GLint dedicated = ssc->base.base.images[i].use_dedicated_allocation ? GL_TRUE : GL_FALSE;
|
||||
glMemoryObjectParameterivEXT(ssc->memory[i], GL_DEDICATED_MEMORY_OBJECT_EXT, &dedicated);
|
||||
CHECK_GL();
|
||||
|
||||
// The below function consumes the handle, need to reference it.
|
||||
xrt_graphics_buffer_handle_t handle = u_graphics_buffer_ref(ssc->base.base.images[i].handle);
|
||||
|
||||
glImportMemoryFdEXT( //
|
||||
ssc->memory[i], //
|
||||
ssc->base.base.images[i].size, //
|
||||
GL_HANDLE_TYPE_OPAQUE_FD_EXT, //
|
||||
handle); //
|
||||
CHECK_GL();
|
||||
|
||||
if (info->array_size == 1) {
|
||||
glTextureStorageMem2DEXT( //
|
||||
ssc->textures[i], //
|
||||
info->mip_count, //
|
||||
gl_format, //
|
||||
info->width, //
|
||||
info->height, //
|
||||
ssc->memory[i], //
|
||||
0); //
|
||||
} else {
|
||||
glTextureStorageMem3DEXT( //
|
||||
ssc->textures[i], //
|
||||
info->mip_count, //
|
||||
gl_format, //
|
||||
info->width, //
|
||||
info->height, //
|
||||
info->array_size, //
|
||||
ssc->memory[i], //
|
||||
0); //
|
||||
}
|
||||
CHECK_GL();
|
||||
}
|
||||
|
||||
sdl_make_uncurrent(sp);
|
||||
}
|
||||
|
||||
static void
|
||||
really_destroy(struct comp_swapchain *sc)
|
||||
{
|
||||
struct sdl_swapchain *ssc = (struct sdl_swapchain *)sc;
|
||||
struct sdl_program *sp = ssc->sp;
|
||||
|
||||
SP_DEBUG(sp, "DESTROY");
|
||||
|
||||
sdl_make_current(sp);
|
||||
|
||||
uint32_t image_count = ssc->base.base.base.image_count;
|
||||
if (image_count > 0) {
|
||||
glDeleteTextures(image_count, ssc->textures);
|
||||
glDeleteMemoryObjectsEXT(image_count, ssc->memory);
|
||||
|
||||
U_ZERO_ARRAY(ssc->textures);
|
||||
U_ZERO_ARRAY(ssc->memory);
|
||||
}
|
||||
|
||||
sdl_make_uncurrent(sp);
|
||||
|
||||
// Teardown the base swapchain, freeing all Vulkan resources.
|
||||
comp_swapchain_teardown(sc);
|
||||
|
||||
// Teardown does not free the struct itself.
|
||||
free(ssc);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* 'Exported' functions.
|
||||
*
|
||||
*/
|
||||
|
||||
xrt_result_t
|
||||
sdl_swapchain_create(struct xrt_compositor *xc,
|
||||
const struct xrt_swapchain_create_info *info,
|
||||
struct xrt_swapchain **out_xsc)
|
||||
{
|
||||
struct sdl_program *sp = from_comp(xc);
|
||||
xrt_result_t xret;
|
||||
|
||||
/*
|
||||
* In case the default get properties function have been overridden
|
||||
* make sure to correctly dispatch the call to get the properties.
|
||||
*/
|
||||
struct xrt_swapchain_create_properties xsccp = {0};
|
||||
xrt_comp_get_swapchain_create_properties(xc, info, &xsccp);
|
||||
|
||||
struct sdl_swapchain *ssc = U_TYPED_CALLOC(struct sdl_swapchain);
|
||||
|
||||
xret = comp_swapchain_create_init( //
|
||||
&ssc->base, //
|
||||
really_destroy, //
|
||||
&sp->c.base.vk, //
|
||||
&sp->c.base.cscgc, //
|
||||
info, //
|
||||
&xsccp); //
|
||||
if (xret != XRT_SUCCESS) {
|
||||
free(ssc);
|
||||
return xret;
|
||||
}
|
||||
|
||||
// Init SDL fields and create OpenGL resources.
|
||||
post_init_setup(ssc, sp, info);
|
||||
|
||||
// Correctly setup refcounts, init sets refcount to zero.
|
||||
xrt_swapchain_reference(out_xsc, &ssc->base.base.base);
|
||||
|
||||
return xret;
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
sdl_swapchain_import(struct xrt_compositor *xc,
|
||||
const struct xrt_swapchain_create_info *info,
|
||||
struct xrt_image_native *native_images,
|
||||
uint32_t native_image_count,
|
||||
struct xrt_swapchain **out_xsc)
|
||||
{
|
||||
struct sdl_program *sp = from_comp(xc);
|
||||
xrt_result_t xret;
|
||||
|
||||
struct sdl_swapchain *ssc = U_TYPED_CALLOC(struct sdl_swapchain);
|
||||
|
||||
xret = comp_swapchain_import_init( //
|
||||
&ssc->base, //
|
||||
really_destroy, //
|
||||
&sp->c.base.vk, //
|
||||
&sp->c.base.cscgc, //
|
||||
info, //
|
||||
native_images, //
|
||||
native_image_count); //
|
||||
if (xret != XRT_SUCCESS) {
|
||||
free(ssc);
|
||||
return xret;
|
||||
}
|
||||
|
||||
// Init SDL fields and create OpenGL resources.
|
||||
post_init_setup(ssc, sp, info);
|
||||
|
||||
// Correctly setup refcounts, init sets refcount to zero.
|
||||
xrt_swapchain_reference(out_xsc, &ssc->base.base.base);
|
||||
|
||||
return xret;
|
||||
}
|
Loading…
Reference in a new issue