diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt index 26bcbad60..0113e44eb 100644 --- a/src/xrt/compositor/CMakeLists.txt +++ b/src/xrt/compositor/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2019-2021, Collabora, Ltd. +# Copyright 2019-2022, Collabora, Ltd. # SPDX-License-Identifier: BSL-1.0 ### @@ -58,6 +58,13 @@ if(XRT_HAVE_EGL) target_sources(comp_client PRIVATE client/comp_egl_client.c client/comp_egl_client.h) endif() +if(XRT_HAVE_D3D11) + target_sources( + comp_client PRIVATE client/comp_d3d11_client.cpp client/comp_d3d11_client.h + client/comp_d3d11_glue.c + ) + target_link_libraries(comp_client PRIVATE aux_d3d) +endif() ## # Util library # diff --git a/src/xrt/compositor/client/comp_d3d11_client.cpp b/src/xrt/compositor/client/comp_d3d11_client.cpp new file mode 100644 index 000000000..0908526fe --- /dev/null +++ b/src/xrt/compositor/client/comp_d3d11_client.cpp @@ -0,0 +1,755 @@ +// Copyright 2019-2022, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief D3D11 client side glue to compositor implementation. + * @author Ryan Pavlik + * @author Jakob Bornecrantz + * @ingroup comp_client + */ + +#include "comp_d3d11_client.h" + +#include "xrt/xrt_config_os.h" +#include "xrt/xrt_vulkan_includes.h" +#include "d3d/d3d_dxgi_formats.h" +#include "d3d/d3d_helpers.hpp" +#include "d3d/d3d_d3d11_allocator.hpp" +#include "util/u_misc.h" +#include "util/u_logging.h" +#include "util/u_debug.h" +#include "util/u_handles.h" +#include "util/u_win32_com_guard.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace std::chrono_literals; +using namespace std::chrono; + +DEBUG_GET_ONCE_LOG_OPTION(log, "D3D_COMPOSITOR_LOG", U_LOGGING_INFO) + +/*! + * Spew level logging. + * + * @relates client_d3d11_compositor + */ +#define D3D_SPEW(c, ...) U_LOG_IFL_T(c->log_level, __VA_ARGS__); + +/*! + * Debug level logging. + * + * @relates client_d3d11_compositor + */ +#define D3D_DEBUG(c, ...) U_LOG_IFL_D(c->log_level, __VA_ARGS__); + +/*! + * Info level logging. + * + * @relates client_d3d11_compositor + */ +#define D3D_INFO(c, ...) U_LOG_IFL_I(c->log_level, __VA_ARGS__); + +/*! + * Warn level logging. + * + * @relates client_d3d11_compositor + */ +#define D3D_WARN(c, ...) U_LOG_IFL_W(c->log_level, __VA_ARGS__); + +/*! + * Error level logging. + * + * @relates client_d3d11_compositor + */ +#define D3D_ERROR(c, ...) U_LOG_IFL_E(c->log_level, __VA_ARGS__); + +namespace { + +/// Deleter for xrt_swapchain +struct xsc_deleter +{ + void + operator()(struct xrt_swapchain *xsc) const noexcept + { + + xrt_swapchain_reference(&xsc, NULL); + } +}; +} // namespace + +// 0 is special +static constexpr uint64_t kKeyedMutexKey = 0; + +/*! + * @class client_d3d11_compositor + * + * Wraps the real compositor providing a D3D11 based interface. + * + * @ingroup comp_client + * @implements xrt_compositor_d3d11 + */ +struct client_d3d11_compositor +{ + struct xrt_compositor_d3d11 base; + + //! Owning reference to the backing native compositor + struct xrt_compositor_native *xcn; + + //! Just keeps COM alive while we keep references to COM things. + xrt::auxiliary::util::ComGuard com_guard; + + //! Logging level. + enum u_logging_level log_level; + + //! Device we got from the app + wil::com_ptr app_device; + + //! Immediate context for @ref app_device + wil::com_ptr app_context; + + //! A similar device we created on the same adapter + wil::com_ptr comp_device; + + //! Immediate context for @ref comp_device + wil::com_ptr comp_context; +}; + +static_assert(std::is_standard_layout::value); + +struct client_d3d11_swapchain; + +static inline DWORD +convertTimeoutToWindowsMilliseconds(uint64_t timeout_ns) +{ + return (timeout_ns == XRT_INFINITE_DURATION) ? INFINITE : (DWORD)(timeout_ns / (uint64_t)U_TIME_1MS_IN_NS); +} + +/*! + * Split out from @ref client_d3d11_swapchain to ensure that it is standard + * layout, std::vector for instance is not standard layout. + */ +struct client_d3d11_swapchain_data +{ + //! The shared handles for all our images + std::vector handles; + + //! Images associated with client_d3d11_compositor::app_device + std::vector> app_images; + + //! Images associated with client_d3d11_compositor::comp_device + std::vector> comp_images; + + //! Keyed mutex per image associated with client_d3d11_compositor::app_device + std::vector> app_keyed_mutex_collection; + + std::vector keyed_mutex_acquired; + + xrt_result_t + waitImage(client_d3d11_swapchain *sc, uint32_t index, uint64_t timeout_ns); + xrt_result_t + releaseImage(client_d3d11_swapchain *sc, uint32_t index); +}; + +/*! + * Wraps the real compositor swapchain providing a D3D11 based interface. + * + * Almost a one to one mapping to a OpenXR swapchain. + * + * @ingroup comp_client + * @implements xrt_swapchain_d3d11 + */ +struct client_d3d11_swapchain +{ + struct xrt_swapchain_d3d11 base; + + //! Owning reference to the imported swapchain. + std::unique_ptr xsc; + + //! Non-owning reference to our parent compositor. + struct client_d3d11_compositor *c; + + std::unique_ptr data; +}; + +static_assert(std::is_standard_layout::value); + +/*! + * Down-cast helper. + * @private @memberof client_d3d11_swapchain + */ +static inline struct client_d3d11_swapchain * +as_client_d3d11_swapchain(struct xrt_swapchain *xsc) +{ + return reinterpret_cast(xsc); +} + +/*! + * Down-cast helper. + * @private @memberof client_d3d11_compositor + */ +static inline struct client_d3d11_compositor * +as_client_d3d11_compositor(struct xrt_compositor *xc) +{ + return (struct client_d3d11_compositor *)xc; +} + +/* + * + * Helpers for Swapchain + * + */ + +inline xrt_result_t +client_d3d11_swapchain_data::waitImage(client_d3d11_swapchain *sc, uint32_t index, uint64_t timeout_ns) +{ + if (keyed_mutex_acquired[index]) { + + D3D_WARN(sc->c, "Will not acquire the keyed mutex for image %" PRId32 " - it was already acquired!", + index); + return XRT_ERROR_NO_IMAGE_AVAILABLE; + } + + auto hr = app_keyed_mutex_collection[index]->AcquireSync(kKeyedMutexKey, + convertTimeoutToWindowsMilliseconds(timeout_ns)); + if (hr == WAIT_ABANDONED) { + D3D_ERROR(sc->c, + "Could not acquire the keyed mutex for image %" PRId32 + " due to it being in an inconsistent state", + index); + return XRT_ERROR_D3D11; + } + if (hr == WAIT_TIMEOUT) { + return XRT_TIMEOUT; + } + if (FAILED(hr)) { + D3D_ERROR(sc->c, "Could not acquire the keyed mutex for image %" PRId32, index); + return XRT_ERROR_D3D11; + } + keyed_mutex_acquired[index] = true; + sc->c->app_context->Flush(); + //! @todo this causes an error in the debug layer + // Discard old contents + // sc->c->app_context->DiscardResource(wil::com_raw_ptr(app_images[index])); + return XRT_SUCCESS; +} + +inline xrt_result_t +client_d3d11_swapchain_data::releaseImage(client_d3d11_swapchain *sc, uint32_t index) +{ + if (!keyed_mutex_acquired[index]) { + + D3D_WARN(sc->c, "Will not release the keyed mutex for image %" PRId32 " - it was not acquired!", index); + return XRT_ERROR_D3D11; + } + auto hr = LOG_IF_FAILED(app_keyed_mutex_collection[index]->ReleaseSync(kKeyedMutexKey)); + if (FAILED(hr)) { + D3D_ERROR(sc->c, "Could not release the keyed mutex for image %" PRId32, index); + return XRT_ERROR_D3D11; + } + sc->data->keyed_mutex_acquired[index] = false; + return XRT_SUCCESS; +} + +/* + * + * Swapchain functions. + * + */ + +static xrt_result_t +client_d3d11_swapchain_acquire_image(struct xrt_swapchain *xsc, uint32_t *out_index) +{ + struct client_d3d11_swapchain *sc = as_client_d3d11_swapchain(xsc); + + // Pipe down call into imported swapchain in native compositor. + return xrt_swapchain_acquire_image(sc->xsc.get(), out_index); +} + +static xrt_result_t +client_d3d11_swapchain_wait_image(struct xrt_swapchain *xsc, uint64_t timeout_ns, uint32_t index) +{ + struct client_d3d11_swapchain *sc = as_client_d3d11_swapchain(xsc); + + // Pipe down call into imported swapchain in native compositor. + xrt_result_t xret = xrt_swapchain_wait_image(sc->xsc.get(), timeout_ns, index); + + if (xret == XRT_SUCCESS) { + // OK, we got the image in the native compositor, now need the keyed mutex in d3d11. + return sc->data->waitImage(sc, index, timeout_ns); + } + return xret; +} + +static xrt_result_t +client_d3d11_swapchain_release_image(struct xrt_swapchain *xsc, uint32_t index) +{ + struct client_d3d11_swapchain *sc = as_client_d3d11_swapchain(xsc); + + // Pipe down call into imported swapchain in native compositor. + xrt_result_t xret = xrt_swapchain_release_image(sc->xsc.get(), index); + + if (xret == XRT_SUCCESS) { + return sc->data->releaseImage(sc, index); + } + return xret; +} +static void +client_d3d11_swapchain_destroy(struct xrt_swapchain *xsc) +{ + // letting destruction do it all + std::unique_ptr sc(as_client_d3d11_swapchain(xsc)); +} + + +static wil::com_ptr +import_image(ID3D11Device1 &device, HANDLE h) +{ + wil::com_ptr tex; + + if (h == nullptr) { + return {}; + } + THROW_IF_FAILED(device.OpenSharedResource1(h, __uuidof(ID3D11Texture2D1), tex.put_void())); + return tex; +} + +xrt_result_t +client_d3d11_create_swapchain(struct xrt_compositor *xc, + const struct xrt_swapchain_create_info *info, + struct xrt_swapchain **out_xsc) +try { + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + xrt_result_t xret = XRT_SUCCESS; + xrt_swapchain_create_properties xsccp{}; + xret = xrt_comp_get_swapchain_create_properties(xc, info, &xsccp); + + if (xret != XRT_SUCCESS) { + D3D_ERROR(c, "Could not get properties for creating swapchain"); + return xret; + } + uint32_t image_count = xsccp.image_count; + + + if ((info->create & XRT_SWAPCHAIN_CREATE_PROTECTED_CONTENT) != 0) { + D3D_WARN(c, + "Swapchain info is valid but this compositor doesn't support creating protected content " + "swapchains!"); + return XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED; + } + + int64_t vk_format = d3d_dxgi_format_to_vk((DXGI_FORMAT)info->format); + if (vk_format == 0) { + D3D_ERROR(c, "Invalid format!"); + return XRT_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED; + } + + struct xrt_swapchain_create_info xinfo = *info; + struct xrt_swapchain_create_info vkinfo = *info; + vkinfo.format = vk_format; + + std::unique_ptr sc = std::make_unique(); + sc->data = std::make_unique(); + auto &data = sc->data; + xret = xrt::auxiliary::d3d::allocateSharedImages(*(c->comp_device), xinfo, image_count, true, data->comp_images, + data->handles); + if (xret != XRT_SUCCESS) { + return xret; + } + data->keyed_mutex_acquired.resize(image_count); + sc->data->app_keyed_mutex_collection.reserve(image_count); + data->app_images.reserve(image_count); + + // Import from the handle for the app. + for (uint32_t i = 0; i < image_count; ++i) { + const auto &handle = data->handles[i]; + wil::unique_handle dupedForApp{u_graphics_buffer_ref(handle.get())}; + auto image = import_image(*(c->app_device), dupedForApp.get()); + // Put the image where the OpenXR state tracker can get it + sc->base.images[i] = image.get(); + + // Cache the keyed mutex interface too + sc->data->app_keyed_mutex_collection.emplace_back(image.query()); + + // Store the owning pointer for lifetime management + data->app_images.emplace_back(std::move(image)); + } + + // Populate for import + std::vector xins; + xins.reserve(data->handles.size()); + // Keep this around until after successful import, then detach all. + std::vector handlesForImport; + handlesForImport.reserve(data->handles.size()); + + for (const wil::unique_handle &handle : data->handles) { + wil::unique_handle duped{u_graphics_buffer_ref(handle.get())}; + xrt_image_native xin; + xin.handle = duped.get(); + xin.size = 0; + xin.use_dedicated_allocation = false; //! @todo not sure + + handlesForImport.emplace_back(std::move(duped)); + xins.emplace_back(xin); + } + + xrt_swapchain *xsc = nullptr; + xret = xrt_comp_import_swapchain(&(c->xcn->base), &vkinfo, xins.data(), image_count, &xsc); + if (xret != XRT_SUCCESS) { + D3D_ERROR(c, "Error importing D3D11 swapchain into native compositor"); + return xret; + } + // The imported swapchain took ownership of them now, release them from ownership here. + for (auto &h : handlesForImport) { + h.release(); + } + + sc->xsc.reset(xsc); + + sc->base.base.destroy = client_d3d11_swapchain_destroy; + sc->base.base.acquire_image = client_d3d11_swapchain_acquire_image; + sc->base.base.wait_image = client_d3d11_swapchain_wait_image; + sc->base.base.release_image = client_d3d11_swapchain_release_image; + sc->base.base.reference.count = 1; + sc->c = c; + sc->base.base.image_count = image_count; + + xrt_swapchain_reference(out_xsc, &sc->base.base); + (void)sc.release(); + return XRT_SUCCESS; +} catch (wil::ResultException const &e) { + U_LOG_E("Error creating D3D11 swapchain: %s", e.what()); + return XRT_ERROR_ALLOCATION; +} catch (std::exception const &e) { + U_LOG_E("Error creating D3D11 swapchain: %s", e.what()); + return XRT_ERROR_ALLOCATION; +} catch (...) { + U_LOG_E("Error creating D3D11 swapchain"); + return XRT_ERROR_ALLOCATION; +} + +/* + * + * Compositor functions. + * + */ + + +static xrt_result_t +client_d3d11_compositor_begin_session(struct xrt_compositor *xc, enum xrt_view_type type) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + + // Pipe down call into native compositor. + return xrt_comp_begin_session(&c->xcn->base, type); +} + +static xrt_result_t +client_d3d11_compositor_end_session(struct xrt_compositor *xc) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + + // Pipe down call into native compositor. + return xrt_comp_end_session(&c->xcn->base); +} + +static xrt_result_t +client_d3d11_compositor_wait_frame(struct xrt_compositor *xc, + int64_t *out_frame_id, + uint64_t *predicted_display_time, + uint64_t *predicted_display_period) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + + // Pipe down call into native compositor. + return xrt_comp_wait_frame(&c->xcn->base, out_frame_id, predicted_display_time, predicted_display_period); +} + +static xrt_result_t +client_d3d11_compositor_begin_frame(struct xrt_compositor *xc, int64_t frame_id) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + + // Pipe down call into native compositor. + return xrt_comp_begin_frame(&c->xcn->base, frame_id); +} + +static xrt_result_t +client_d3d11_compositor_discard_frame(struct xrt_compositor *xc, int64_t frame_id) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + + // Pipe down call into native compositor. + return xrt_comp_discard_frame(&c->xcn->base, frame_id); +} + +static xrt_result_t +client_d3d11_compositor_layer_begin(struct xrt_compositor *xc, + int64_t frame_id, + uint64_t display_time_ns, + enum xrt_blend_mode env_blend_mode) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + + return xrt_comp_layer_begin(&c->xcn->base, frame_id, display_time_ns, env_blend_mode); +} + +static xrt_result_t +client_d3d11_compositor_layer_stereo_projection(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *l_xsc, + struct xrt_swapchain *r_xsc, + const struct xrt_layer_data *data) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + struct xrt_swapchain *l_xscn, *r_xscn; + + assert(data->type == XRT_LAYER_STEREO_PROJECTION); + + l_xscn = as_client_d3d11_swapchain(l_xsc)->xsc.get(); + r_xscn = as_client_d3d11_swapchain(r_xsc)->xsc.get(); + + struct xrt_layer_data d = *data; + d.flip_y = !d.flip_y; + + return xrt_comp_layer_stereo_projection(&c->xcn->base, xdev, l_xscn, r_xscn, &d); +} + +static xrt_result_t +client_d3d11_compositor_layer_stereo_projection_depth(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *l_xsc, + struct xrt_swapchain *r_xsc, + struct xrt_swapchain *l_d_xsc, + struct xrt_swapchain *r_d_xsc, + const struct xrt_layer_data *data) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + + assert(data->type == XRT_LAYER_STEREO_PROJECTION_DEPTH); + + struct xrt_swapchain *l_xscn = as_client_d3d11_swapchain(l_xsc)->xsc.get(); + struct xrt_swapchain *r_xscn = as_client_d3d11_swapchain(r_xsc)->xsc.get(); + struct xrt_swapchain *l_d_xscn = as_client_d3d11_swapchain(l_d_xsc)->xsc.get(); + struct xrt_swapchain *r_d_xscn = as_client_d3d11_swapchain(r_d_xsc)->xsc.get(); + + struct xrt_layer_data d = *data; + d.flip_y = !d.flip_y; + + return xrt_comp_layer_stereo_projection_depth(&c->xcn->base, xdev, l_xscn, r_xscn, l_d_xscn, r_d_xscn, &d); +} + +static xrt_result_t +client_d3d11_compositor_layer_quad(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *xsc, + const struct xrt_layer_data *data) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + struct xrt_swapchain *xscfb; + + assert(data->type == XRT_LAYER_QUAD); + + xscfb = as_client_d3d11_swapchain(xsc)->xsc.get(); + + // no flip required: D3D11 swapchain image convention matches Vulkan + return xrt_comp_layer_quad(&c->xcn->base, xdev, xscfb, data); +} + +static xrt_result_t +client_d3d11_compositor_layer_cube(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *xsc, + const struct xrt_layer_data *data) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + struct xrt_swapchain *xscfb; + + assert(data->type == XRT_LAYER_CUBE); + + xscfb = as_client_d3d11_swapchain(xsc)->xsc.get(); + + // no flip required: D3D11 swapchain image convention matches Vulkan + return xrt_comp_layer_cube(&c->xcn->base, xdev, xscfb, data); +} + +static xrt_result_t +client_d3d11_compositor_layer_cylinder(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *xsc, + const struct xrt_layer_data *data) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + struct xrt_swapchain *xscfb; + + assert(data->type == XRT_LAYER_CYLINDER); + + xscfb = as_client_d3d11_swapchain(xsc)->xsc.get(); + + // no flip required: D3D11 swapchain image convention matches Vulkan + return xrt_comp_layer_cylinder(&c->xcn->base, xdev, xscfb, data); +} + +static xrt_result_t +client_d3d11_compositor_layer_equirect1(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *xsc, + const struct xrt_layer_data *data) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + struct xrt_swapchain *xscfb; + + assert(data->type == XRT_LAYER_EQUIRECT1); + + xscfb = as_client_d3d11_swapchain(xsc)->xsc.get(); + + // no flip required: D3D11 swapchain image convention matches Vulkan + return xrt_comp_layer_equirect1(&c->xcn->base, xdev, xscfb, data); +} + +static xrt_result_t +client_d3d11_compositor_layer_equirect2(struct xrt_compositor *xc, + struct xrt_device *xdev, + struct xrt_swapchain *xsc, + const struct xrt_layer_data *data) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + struct xrt_swapchain *xscfb; + + assert(data->type == XRT_LAYER_EQUIRECT2); + + xscfb = as_client_d3d11_swapchain(xsc)->xsc.get(); + + // no flip required: D3D11 swapchain image convention matches Vulkan + return xrt_comp_layer_equirect2(&c->xcn->base, xdev, xscfb, data); +} + +static xrt_result_t +client_d3d11_compositor_layer_commit(struct xrt_compositor *xc, + int64_t frame_id, + xrt_graphics_sync_handle_t sync_handle) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + + // We make the sync object, not st/oxr which is our user. + assert(!xrt_graphics_sync_handle_is_valid(sync_handle)); + + xrt_result_t xret = XRT_SUCCESS; + sync_handle = XRT_GRAPHICS_SYNC_HANDLE_INVALID; + + /*! + * @todo The swapchain images should have been externally synchronized? actually probably sync here + */ + + if (xret != XRT_SUCCESS) { + return XRT_SUCCESS; + } + + return xrt_comp_layer_commit(&c->xcn->base, frame_id, sync_handle); +} + + +static xrt_result_t +client_d3d11_compositor_get_swapchain_create_properties(struct xrt_compositor *xc, + const struct xrt_swapchain_create_info *info, + struct xrt_swapchain_create_properties *xsccp) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + + return xrt_comp_get_swapchain_create_properties(&c->xcn->base, info, xsccp); +} + +static xrt_result_t +client_d3d11_compositor_poll_events(struct xrt_compositor *xc, union xrt_compositor_event *out_xce) +{ + struct client_d3d11_compositor *c = as_client_d3d11_compositor(xc); + + // Pipe down call into native compositor. + return xrt_comp_poll_events(&c->xcn->base, out_xce); +} + +static void +client_d3d11_compositor_destroy(struct xrt_compositor *xc) +{ + std::unique_ptr c{as_client_d3d11_compositor(xc)}; +} + +struct xrt_compositor_d3d11 * +client_d3d11_compositor_create(struct xrt_compositor_native *xcn, ID3D11Device *device) +try { + std::unique_ptr c = std::make_unique(); + c->log_level = debug_get_log_option_log(); + c->xcn = xcn; + + wil::com_ptr app_dev{device}; + if (!app_dev.try_query_to(c->app_device.put())) { + U_LOG_E("Could not get d3d11 device!"); + return nullptr; + } + c->app_device->GetImmediateContext3(c->app_context.put()); + + wil::com_ptr adapter; + + THROW_IF_FAILED(app_dev.query()->GetAdapter(adapter.put())); + + { + // Now, try to get an equivalent device of our own + wil::com_ptr our_dev; + wil::com_ptr our_context; + std::tie(our_dev, our_context) = xrt::auxiliary::d3d::createD3D11Device(adapter, c->log_level); + our_dev.query_to(c->comp_device.put()); + our_context.query_to(c->comp_context.put()); + } + + c->base.base.get_swapchain_create_properties = client_d3d11_compositor_get_swapchain_create_properties; + c->base.base.create_swapchain = client_d3d11_create_swapchain; + c->base.base.begin_session = client_d3d11_compositor_begin_session; + c->base.base.end_session = client_d3d11_compositor_end_session; + c->base.base.wait_frame = client_d3d11_compositor_wait_frame; + c->base.base.begin_frame = client_d3d11_compositor_begin_frame; + c->base.base.discard_frame = client_d3d11_compositor_discard_frame; + c->base.base.layer_begin = client_d3d11_compositor_layer_begin; + c->base.base.layer_stereo_projection = client_d3d11_compositor_layer_stereo_projection; + c->base.base.layer_stereo_projection_depth = client_d3d11_compositor_layer_stereo_projection_depth; + c->base.base.layer_quad = client_d3d11_compositor_layer_quad; + c->base.base.layer_cube = client_d3d11_compositor_layer_cube; + c->base.base.layer_cylinder = client_d3d11_compositor_layer_cylinder; + c->base.base.layer_equirect1 = client_d3d11_compositor_layer_equirect1; + c->base.base.layer_equirect2 = client_d3d11_compositor_layer_equirect2; + c->base.base.layer_commit = client_d3d11_compositor_layer_commit; + c->base.base.destroy = client_d3d11_compositor_destroy; + c->base.base.poll_events = client_d3d11_compositor_poll_events; + + + // Passthrough our formats from the native compositor to the client. + uint32_t count = 0; + for (uint32_t i = 0; i < xcn->base.info.format_count; i++) { + DXGI_FORMAT f = d3d_vk_format_to_dxgi(xcn->base.info.formats[i]); + if (f == 0) { + continue; + } + + c->base.base.info.formats[count++] = f; + } + c->base.base.info.format_count = count; + + return &(c.release()->base); +} catch (wil::ResultException const &e) { + U_LOG_E("Error creating D3D11 client compositor: %s", e.what()); + return nullptr; +} catch (std::exception const &e) { + U_LOG_E("Error creating D3D11 client compositor: %s", e.what()); + return nullptr; +} catch (...) { + U_LOG_E("Error creating D3D11 client compositor"); + return nullptr; +} diff --git a/src/xrt/compositor/client/comp_d3d11_client.h b/src/xrt/compositor/client/comp_d3d11_client.h new file mode 100644 index 000000000..1927f34cb --- /dev/null +++ b/src/xrt/compositor/client/comp_d3d11_client.h @@ -0,0 +1,44 @@ +// Copyright 2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Interface for D3D11 client-side code. + * @author Ryan Pavlik + * @ingroup comp_client + */ + +#pragma once + +#include "xrt/xrt_compositor.h" +#include "xrt/xrt_gfx_d3d11.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * + * Structs + * + */ + +struct client_d3d11_compositor; + +/*! + * Create a new client_d3d11_compositor. + * + * Takes ownership of provided xcn. + * + * @public @memberof client_d3d11_compositor + * @see xrt_compositor_native + */ +struct xrt_compositor_d3d11 * +client_d3d11_compositor_create(struct xrt_compositor_native *xcn, ID3D11Device *device); + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/compositor/client/comp_d3d11_glue.c b/src/xrt/compositor/client/comp_d3d11_glue.c new file mode 100644 index 000000000..1dc467ddb --- /dev/null +++ b/src/xrt/compositor/client/comp_d3d11_glue.c @@ -0,0 +1,19 @@ +// Copyright 2021, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Glue code to D3D11 client side code: expressing requirements and connecting `comp_` APIs to `xrt_gfx_` + * interfaces. + * @author Ryan Pavlik + * @ingroup comp_client + */ + +#include "client/comp_d3d11_client.h" + +#include + +struct xrt_compositor_d3d11 * +xrt_gfx_d3d11_provider_create(struct xrt_compositor_native *xcn, ID3D11Device *device) +{ + return client_d3d11_compositor_create(xcn, device); +}