mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-01 04:36:07 +00:00
a/d3d: Add native d3d12 allocator and copy helpers.
Add a D3D12 allocator and helper code to copy from shadow images, the copy is needed to work around a interop issue on NVIDIA hardware. Co-authored-by: Ryan Pavlik <ryan.pavlik@collabora.com>
This commit is contained in:
parent
84ac7b14be
commit
6342c72665
|
@ -28,8 +28,9 @@ if(XRT_HAVE_D3D12)
|
|||
aux_d3d
|
||||
PRIVATE
|
||||
d3d_d3d12_bits.h
|
||||
# d3d_d3d12_allocator.cpp
|
||||
# d3d_d3d12_allocator.hpp
|
||||
d3d_d3d12_allocator.cpp
|
||||
d3d_d3d12_allocator.h
|
||||
d3d_d3d12_allocator.hpp
|
||||
d3d_d3d12_fence.cpp
|
||||
d3d_d3d12_fence.hpp
|
||||
d3d_d3d12_helpers.cpp
|
||||
|
|
230
src/xrt/auxiliary/d3d/d3d_d3d12_allocator.cpp
Normal file
230
src/xrt/auxiliary/d3d/d3d_d3d12_allocator.cpp
Normal file
|
@ -0,0 +1,230 @@
|
|||
// Copyright 2020-2022, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief D3D12 backed image buffer allocator.
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
* @author Fernando Velazquez Innella <finnella@magicleap.com>
|
||||
* @ingroup aux_d3d
|
||||
*/
|
||||
|
||||
#include "d3d_d3d12_allocator.h"
|
||||
#include "d3d_d3d12_allocator.hpp"
|
||||
|
||||
#include "d3d_d3d12_bits.h"
|
||||
#include "d3d_dxgi_formats.h"
|
||||
|
||||
#include "util/u_misc.h"
|
||||
#include "util/u_logging.h"
|
||||
#include "util/u_debug.h"
|
||||
#include "util/u_handles.h"
|
||||
|
||||
#include "xrt/xrt_windows.h"
|
||||
|
||||
#include <Unknwn.h>
|
||||
#include <d3d12.h>
|
||||
#include <wil/com.h>
|
||||
#include <wil/result.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <memory>
|
||||
|
||||
#define DEFAULT_CATCH(...) \
|
||||
catch (wil::ResultException const &e) \
|
||||
{ \
|
||||
U_LOG_E("Caught exception: %s", e.what()); \
|
||||
return __VA_ARGS__; \
|
||||
} \
|
||||
catch (std::exception const &e) \
|
||||
{ \
|
||||
U_LOG_E("Caught exception: %s", e.what()); \
|
||||
return __VA_ARGS__; \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
U_LOG_E("Caught exception"); \
|
||||
return __VA_ARGS__; \
|
||||
}
|
||||
|
||||
|
||||
DEBUG_GET_ONCE_LOG_OPTION(d3d12_log, "D3D12_LOG", U_LOGGING_WARN)
|
||||
#define D3DA_TRACE(...) U_LOG_IFL_T(debug_get_log_option_d3d12_log(), __VA_ARGS__)
|
||||
#define D3DA_DEBUG(...) U_LOG_IFL_D(debug_get_log_option_d3d12_log(), __VA_ARGS__)
|
||||
#define D3DA_INFO(...) U_LOG_IFL_I(debug_get_log_option_d3d12_log(), __VA_ARGS__)
|
||||
#define D3DA_WARN(...) U_LOG_IFL_W(debug_get_log_option_d3d12_log(), __VA_ARGS__)
|
||||
#define D3DA_ERROR(...) U_LOG_IFL_E(debug_get_log_option_d3d12_log(), __VA_ARGS__)
|
||||
|
||||
namespace xrt::auxiliary::d3d::d3d12 {
|
||||
|
||||
static wil::unique_handle
|
||||
createSharedHandle(ID3D12Device &device, const wil::com_ptr<ID3D12Resource> &image)
|
||||
{
|
||||
wil::unique_handle h;
|
||||
THROW_IF_FAILED(device.CreateSharedHandle( //
|
||||
image.get(), // pObject
|
||||
nullptr, // pAttributes
|
||||
GENERIC_ALL, // Access
|
||||
nullptr, // Name
|
||||
h.put())); // pHandle
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
xrt_result_t
|
||||
allocateSharedImages(ID3D12Device &device,
|
||||
const xrt_swapchain_create_info &xsci,
|
||||
size_t image_count,
|
||||
std::vector<wil::com_ptr<ID3D12Resource>> &out_images,
|
||||
std::vector<wil::unique_handle> &out_handles)
|
||||
try {
|
||||
if (0 != (xsci.create & XRT_SWAPCHAIN_CREATE_PROTECTED_CONTENT)) {
|
||||
return XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (0 != (xsci.create & XRT_SWAPCHAIN_CREATE_STATIC_IMAGE) && image_count > 1) {
|
||||
D3DA_ERROR("Got XRT_SWAPCHAIN_CREATE_STATIC_IMAGE but an image count greater than 1!");
|
||||
return XRT_ERROR_ALLOCATION;
|
||||
}
|
||||
if (xsci.array_size == 0) {
|
||||
D3DA_ERROR("Array size must not be 0");
|
||||
return XRT_ERROR_ALLOCATION;
|
||||
}
|
||||
|
||||
// TODO: See if this is still necessary
|
||||
DXGI_FORMAT typeless_format = d3d_dxgi_format_to_typeless_dxgi((DXGI_FORMAT)xsci.format);
|
||||
if (typeless_format == 0) {
|
||||
D3DA_ERROR("Invalid format %04" PRIx64 "!", (uint64_t)xsci.format);
|
||||
return XRT_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED;
|
||||
}
|
||||
|
||||
DXGI_SAMPLE_DESC sample_desc{
|
||||
xsci.sample_count, // Count
|
||||
0, // Quality
|
||||
};
|
||||
|
||||
// Note:
|
||||
// To use a cross-adapter heap the following flag must be passed:
|
||||
// resource_flags |= D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER;
|
||||
// Additionally, only copy operations are allowed with the resource.
|
||||
D3D12_RESOURCE_FLAGS resource_flags = d3d_convert_usage_bits_to_d3d12_resource_flags(xsci.bits);
|
||||
|
||||
D3D12_RESOURCE_DESC desc{
|
||||
D3D12_RESOURCE_DIMENSION_TEXTURE2D, // Dimension
|
||||
0, // Alignment
|
||||
xsci.width, // Width
|
||||
xsci.height, // Height
|
||||
(UINT16)xsci.array_size, // DepthOrArraySize
|
||||
(UINT16)xsci.mip_count, // MipLevels
|
||||
typeless_format, // Format
|
||||
sample_desc, // SampleDesc
|
||||
D3D12_TEXTURE_LAYOUT_UNKNOWN, // Layout
|
||||
resource_flags // Flags;
|
||||
};
|
||||
|
||||
// Cubemap
|
||||
if (xsci.face_count == 6) {
|
||||
desc.DepthOrArraySize *= 6;
|
||||
}
|
||||
|
||||
// Create resources and let the driver manage memory
|
||||
std::vector<wil::com_ptr<ID3D12Resource>> images;
|
||||
D3D12_HEAP_PROPERTIES heap{};
|
||||
heap.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
D3D12_HEAP_FLAGS heap_flags = D3D12_HEAP_FLAG_SHARED;
|
||||
D3D12_RESOURCE_STATES initial_resource_state = d3d_convert_usage_bits_to_d3d12_app_resource_state(xsci.bits);
|
||||
|
||||
for (size_t i = 0; i < image_count; ++i) {
|
||||
wil::com_ptr<ID3D12Resource> tex;
|
||||
HRESULT res = device.CreateCommittedResource( //
|
||||
&heap, // pHeapProperties
|
||||
heap_flags, // HeapFlags
|
||||
&desc, // pDesc
|
||||
initial_resource_state, // InitialResourceState
|
||||
nullptr, // pOptimizedClearValue
|
||||
IID_PPV_ARGS(tex.put())); // riidResource, ppvResource
|
||||
|
||||
if (FAILED(LOG_IF_FAILED(res))) {
|
||||
return XRT_ERROR_ALLOCATION;
|
||||
}
|
||||
images.emplace_back(std::move(tex));
|
||||
}
|
||||
|
||||
std::vector<wil::unique_handle> handles;
|
||||
handles.reserve(image_count);
|
||||
for (const auto &tex : images) {
|
||||
handles.emplace_back(createSharedHandle(device, tex));
|
||||
}
|
||||
out_images = std::move(images);
|
||||
out_handles = std::move(handles);
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
DEFAULT_CATCH(XRT_ERROR_ALLOCATION)
|
||||
|
||||
} // namespace xrt::auxiliary::d3d::d3d12
|
||||
|
||||
struct d3d12_allocator
|
||||
{
|
||||
struct xrt_image_native_allocator base;
|
||||
wil::com_ptr<ID3D12Device> device;
|
||||
};
|
||||
|
||||
|
||||
static xrt_result_t
|
||||
d3d12_images_allocate(struct xrt_image_native_allocator *xina,
|
||||
const struct xrt_swapchain_create_info *xsci,
|
||||
size_t image_count,
|
||||
struct xrt_image_native *out_images)
|
||||
{
|
||||
try {
|
||||
d3d12_allocator *d3da = reinterpret_cast<d3d12_allocator *>(xina);
|
||||
|
||||
std::vector<wil::com_ptr<ID3D12Resource>> images;
|
||||
std::vector<wil::unique_handle> handles;
|
||||
auto result = xrt::auxiliary::d3d::d3d12::allocateSharedImages( //
|
||||
*(d3da->device), // device
|
||||
*xsci, // xsci
|
||||
image_count, // image_count
|
||||
images, // out_images
|
||||
handles); // out_handles
|
||||
|
||||
if (result != XRT_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < image_count; ++i) {
|
||||
out_images[i].handle = handles[i].release();
|
||||
out_images[i].is_dxgi_handle = false;
|
||||
}
|
||||
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
DEFAULT_CATCH(XRT_ERROR_ALLOCATION)
|
||||
}
|
||||
|
||||
static xrt_result_t
|
||||
d3d12_images_free(struct xrt_image_native_allocator *xina, size_t image_count, struct xrt_image_native *images)
|
||||
{
|
||||
for (size_t i = 0; i < image_count; ++i) {
|
||||
u_graphics_buffer_unref(&(images[i].handle));
|
||||
}
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
d3d12_destroy(struct xrt_image_native_allocator *xina)
|
||||
{
|
||||
d3d12_allocator *d3da = reinterpret_cast<d3d12_allocator *>(xina);
|
||||
delete d3da;
|
||||
}
|
||||
|
||||
struct xrt_image_native_allocator *
|
||||
d3d12_allocator_create(ID3D11Device *device)
|
||||
try {
|
||||
auto ret = std::make_unique<d3d12_allocator>();
|
||||
U_ZERO(&(ret->base));
|
||||
ret->base.images_allocate = d3d12_images_allocate;
|
||||
ret->base.images_free = d3d12_images_free;
|
||||
ret->base.destroy = d3d12_destroy;
|
||||
return &(ret.release()->base);
|
||||
}
|
||||
DEFAULT_CATCH(nullptr)
|
35
src/xrt/auxiliary/d3d/d3d_d3d12_allocator.h
Normal file
35
src/xrt/auxiliary/d3d/d3d_d3d12_allocator.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2020-2023, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Header for D3D12-backed image buffer allocator factory function.
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
* @author Fernando Velazquez Innella <finnella@magicleap.com>
|
||||
* @ingroup aux_d3d
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xrt/xrt_compositor.h"
|
||||
|
||||
#include <d3d12.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Create a XINA that allocates D3D12 textures.
|
||||
*
|
||||
* @param device A device to allocate the textures with. Be sure it will not be used from other threads while this
|
||||
* allocator allocates.
|
||||
*
|
||||
* @return struct xrt_image_native_allocator*
|
||||
*/
|
||||
struct xrt_image_native_allocator *
|
||||
d3d12_allocator_create(ID3D12Device *device);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
50
src/xrt/auxiliary/d3d/d3d_d3d12_allocator.hpp
Normal file
50
src/xrt/auxiliary/d3d/d3d_d3d12_allocator.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2020-2023, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Higher-level D3D12-backed image buffer allocation routine.
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
* @author Fernando Velazquez Innella <finnella@magicleap.com>
|
||||
* @ingroup aux_d3d
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xrt/xrt_compositor.h"
|
||||
|
||||
#include <Unknwn.h>
|
||||
#include <d3d12.h>
|
||||
#include <wil/com.h>
|
||||
#include <wil/resource.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace xrt::auxiliary::d3d::d3d12 {
|
||||
|
||||
/**
|
||||
* Allocate images (ID3D12Resource) that have a corresponding native handle.
|
||||
*
|
||||
* @param device A D3D12 device to allocate with.
|
||||
* @param xsci Swapchain create info: note that the format is assumed to be a DXGI_FORMAT (conversion to typeless is
|
||||
* automatic)
|
||||
* @param image_count The number of images to create.
|
||||
* @param keyed_mutex Whether to create images with a shared "keyed mutex" as well
|
||||
* @param[out] out_images A vector that will be cleared and populated with the images.
|
||||
* @param[out] out_handles A vector that will be cleared and populated with the corresponding native handles.
|
||||
*
|
||||
* @return xrt_result_t, one of:
|
||||
* - @ref XRT_SUCCESS
|
||||
* - @ref XRT_ERROR_ALLOCATION
|
||||
* - @ref XRT_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED
|
||||
* - @ref XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED
|
||||
* - @ref XRT_ERROR_D3D12
|
||||
*/
|
||||
xrt_result_t
|
||||
allocateSharedImages(ID3D12Device &device,
|
||||
const xrt_swapchain_create_info &xsci,
|
||||
size_t image_count,
|
||||
std::vector<wil::com_ptr<ID3D12Resource>> &out_images,
|
||||
std::vector<wil::unique_handle> &out_handles);
|
||||
|
||||
}; // namespace xrt::auxiliary::d3d::d3d12
|
|
@ -79,6 +79,70 @@ createCommandLists(ID3D12Device &device,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
createCommandListImageCopy(ID3D12Device &device,
|
||||
ID3D12CommandAllocator &command_allocator,
|
||||
ID3D12Resource &resource_src,
|
||||
ID3D12Resource &resource_dst,
|
||||
D3D12_RESOURCE_STATES src_resource_state,
|
||||
D3D12_RESOURCE_STATES dst_resource_state,
|
||||
wil::com_ptr<ID3D12CommandList> &out_copy_command_list)
|
||||
{
|
||||
wil::com_ptr<ID3D12GraphicsCommandList> copyCommandList;
|
||||
RETURN_IF_FAILED(device.CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, &command_allocator, nullptr,
|
||||
IID_PPV_ARGS(copyCommandList.put())));
|
||||
|
||||
// Transition images into copy state
|
||||
D3D12_RESOURCE_BARRIER preCopyBarriers[2]{};
|
||||
preCopyBarriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
preCopyBarriers[0].Transition.pResource = &resource_src;
|
||||
preCopyBarriers[0].Transition.StateBefore = src_resource_state;
|
||||
preCopyBarriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||
preCopyBarriers[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
preCopyBarriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
preCopyBarriers[1].Transition.pResource = &resource_dst;
|
||||
preCopyBarriers[1].Transition.StateBefore = dst_resource_state;
|
||||
preCopyBarriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
preCopyBarriers[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
copyCommandList->ResourceBarrier(2, preCopyBarriers);
|
||||
|
||||
// Insert texture copy command
|
||||
D3D12_TEXTURE_COPY_LOCATION srcCopyLocation;
|
||||
srcCopyLocation.pResource = &resource_src;
|
||||
srcCopyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
srcCopyLocation.SubresourceIndex = 0;
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION dstCopyLocation;
|
||||
dstCopyLocation.pResource = &resource_dst;
|
||||
dstCopyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
dstCopyLocation.SubresourceIndex = 0;
|
||||
|
||||
copyCommandList->CopyTextureRegion(&dstCopyLocation, 0, 0, 0, &srcCopyLocation, nullptr);
|
||||
|
||||
// Transition images back from copy state
|
||||
D3D12_RESOURCE_BARRIER postCopyBarriers[2]{};
|
||||
postCopyBarriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
postCopyBarriers[0].Transition.pResource = &resource_src;
|
||||
postCopyBarriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||
postCopyBarriers[0].Transition.StateAfter = src_resource_state;
|
||||
postCopyBarriers[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
postCopyBarriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
postCopyBarriers[1].Transition.pResource = &resource_dst;
|
||||
postCopyBarriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
postCopyBarriers[1].Transition.StateAfter = dst_resource_state;
|
||||
postCopyBarriers[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
copyCommandList->ResourceBarrier(2, postCopyBarriers);
|
||||
|
||||
RETURN_IF_FAILED(copyCommandList->Close());
|
||||
|
||||
out_copy_command_list = std::move(copyCommandList);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
wil::com_ptr<ID3D12Resource>
|
||||
importImage(ID3D12Device &device, HANDLE h)
|
||||
|
|
|
@ -57,6 +57,27 @@ createCommandLists(ID3D12Device &device,
|
|||
wil::com_ptr<ID3D12CommandList> out_acquire_command_list,
|
||||
wil::com_ptr<ID3D12CommandList> out_release_command_list);
|
||||
|
||||
/**
|
||||
* @brief Create a command list for image resource copying
|
||||
*
|
||||
* @param device D3D12 device
|
||||
* @param command_allocator
|
||||
* @param resource_src Source image
|
||||
* @param resource_dst Destination image
|
||||
* @param src_resource_state
|
||||
* @param dst_resource_state
|
||||
* @param[out] out_copy_command_list Command list output
|
||||
* @return HRESULT
|
||||
*/
|
||||
HRESULT
|
||||
createCommandListImageCopy(ID3D12Device &device,
|
||||
ID3D12CommandAllocator &command_allocator,
|
||||
ID3D12Resource &resource_src,
|
||||
ID3D12Resource &resource_dst,
|
||||
D3D12_RESOURCE_STATES src_resource_state,
|
||||
D3D12_RESOURCE_STATES dst_resource_state,
|
||||
wil::com_ptr<ID3D12CommandList> &out_copy_command_list);
|
||||
|
||||
/**
|
||||
* Imports an image into D3D12 from a handle.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue