comp/client: Initial D3D11 client compositor

Still missing image synchronization/waiting for completion.
This commit is contained in:
Ryan Pavlik 2021-10-19 16:40:28 -05:00 committed by Jakob Bornecrantz
parent 9337ea375c
commit 945603a8be
4 changed files with 826 additions and 1 deletions

View file

@ -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
#

View file

@ -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 <ryan.pavlik@collabora.com>
* @author Jakob Bornecrantz <jakob@collabora.com>
* @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 <d3d11_1.h>
#include <wil/resource.h>
#include <wil/com.h>
#include <assert.h>
#include <inttypes.h>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <chrono>
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<ID3D11Device5> app_device;
//! Immediate context for @ref app_device
wil::com_ptr<ID3D11DeviceContext3> app_context;
//! A similar device we created on the same adapter
wil::com_ptr<ID3D11Device5> comp_device;
//! Immediate context for @ref comp_device
wil::com_ptr<ID3D11DeviceContext3> comp_context;
};
static_assert(std::is_standard_layout<client_d3d11_compositor>::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<wil::unique_handle> handles;
//! Images associated with client_d3d11_compositor::app_device
std::vector<wil::com_ptr<ID3D11Texture2D1>> app_images;
//! Images associated with client_d3d11_compositor::comp_device
std::vector<wil::com_ptr<ID3D11Texture2D1>> comp_images;
//! Keyed mutex per image associated with client_d3d11_compositor::app_device
std::vector<wil::com_ptr<IDXGIKeyedMutex>> app_keyed_mutex_collection;
std::vector<bool> 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<xrt_swapchain, xsc_deleter> xsc;
//! Non-owning reference to our parent compositor.
struct client_d3d11_compositor *c;
std::unique_ptr<client_d3d11_swapchain_data> data;
};
static_assert(std::is_standard_layout<client_d3d11_swapchain>::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<client_d3d11_swapchain *>(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<client_d3d11_swapchain> sc(as_client_d3d11_swapchain(xsc));
}
static wil::com_ptr<ID3D11Texture2D1>
import_image(ID3D11Device1 &device, HANDLE h)
{
wil::com_ptr<ID3D11Texture2D1> 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<struct client_d3d11_swapchain> sc = std::make_unique<struct client_d3d11_swapchain>();
sc->data = std::make_unique<client_d3d11_swapchain_data>();
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<IDXGIKeyedMutex>());
// Store the owning pointer for lifetime management
data->app_images.emplace_back(std::move(image));
}
// Populate for import
std::vector<xrt_image_native> xins;
xins.reserve(data->handles.size());
// Keep this around until after successful import, then detach all.
std::vector<wil::unique_handle> 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<struct client_d3d11_compositor> 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<struct client_d3d11_compositor> c = std::make_unique<struct client_d3d11_compositor>();
c->log_level = debug_get_log_option_log();
c->xcn = xcn;
wil::com_ptr<ID3D11Device> 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<IDXGIAdapter> adapter;
THROW_IF_FAILED(app_dev.query<IDXGIDevice>()->GetAdapter(adapter.put()));
{
// Now, try to get an equivalent device of our own
wil::com_ptr<ID3D11Device> our_dev;
wil::com_ptr<ID3D11DeviceContext> 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;
}

View file

@ -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 <ryan.pavlik@collabora.com>
* @ingroup comp_client
*/
#pragma once
#include "xrt/xrt_compositor.h"
#include "xrt/xrt_gfx_d3d11.h"
#include <d3d11_4.h>
#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

View file

@ -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 <ryan.pavlik@collabora.com>
* @ingroup comp_client
*/
#include "client/comp_d3d11_client.h"
#include <stdlib.h>
struct xrt_compositor_d3d11 *
xrt_gfx_d3d11_provider_create(struct xrt_compositor_native *xcn, ID3D11Device *device)
{
return client_d3d11_compositor_create(xcn, device);
}