mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-01 04:36:07 +00:00
comp/client: Initial D3D11 client compositor
Still missing image synchronization/waiting for completion.
This commit is contained in:
parent
9337ea375c
commit
945603a8be
|
@ -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
|
||||
#
|
||||
|
|
755
src/xrt/compositor/client/comp_d3d11_client.cpp
Normal file
755
src/xrt/compositor/client/comp_d3d11_client.cpp
Normal 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;
|
||||
}
|
44
src/xrt/compositor/client/comp_d3d11_client.h
Normal file
44
src/xrt/compositor/client/comp_d3d11_client.h
Normal 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
|
19
src/xrt/compositor/client/comp_d3d11_glue.c
Normal file
19
src/xrt/compositor/client/comp_d3d11_glue.c
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue