summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@collabora.com>2022-04-27 19:32:34 +0200
committerMarge Bot <emma+marge@anholt.net>2023-01-11 09:31:02 +0000
commit2f462105face258c3e57a9558b8615d5919cc261 (patch)
tree93852c305f630c2a45f44bb73669e055a98b1225
parente4d81c05ea41f3c85075768b34ead18214604a45 (diff)
downloadmesa-2f462105face258c3e57a9558b8615d5919cc261.tar.gz
vulkan/wsi: Hook-up DXGI swapchains and DComp
The CPU copy is horribly slow, so let's hook-up DXGI swapchains. Note that we're still limited in term of features. For instance, we can't support more than 2 images per swapchain because of the DXGI present ordering constraint. We also have to do an extra copy, because DXGI only allows rendering to a resource on the queue that the swapchain was created against, but swapchains in Vulkan don't have a queue. The swapchain is bound to the window using DirectComposition aka DComp. The DComp infrastructure is set up in the surface, and is transitioned from one swapchain to the next when the new swapchain begins presenting. Unlike Wayland and X, there's no requirement that the compositor has to release a surface before you can start rendering against it. However, since we're now supporting the non-sw path, we do need to prevent apps from rendering to a resource *while* the blit is occurring. We do this by blocking for a fence while acquiring an image. Co-authored-by: Jesse Natalie <jenatali@microsoft.com> Acked-by: Daniel Stone <daniels@collabora.com> Acked-by: Jason Ekstrand <jason.ekstrand@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16200>
-rw-r--r--src/vulkan/wsi/meson.build1
-rw-r--r--src/vulkan/wsi/wsi_common.c27
-rw-r--r--src/vulkan/wsi/wsi_common.h10
-rw-r--r--src/vulkan/wsi/wsi_common_private.h22
-rw-r--r--src/vulkan/wsi/wsi_common_win32.cpp459
5 files changed, 483 insertions, 36 deletions
diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build
index 6286fa5d6e6..d6b0ed9fa8f 100644
--- a/src/vulkan/wsi/meson.build
+++ b/src/vulkan/wsi/meson.build
@@ -39,6 +39,7 @@ endif
if with_platform_windows
files_vulkan_wsi += files('wsi_common_win32.cpp')
+ platform_deps += dep_dxheaders
endif
if system_has_kms_drm and not with_platform_android
diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c
index fecc51784dd..4e443631ca4 100644
--- a/src/vulkan/wsi/wsi_common.c
+++ b/src/vulkan/wsi/wsi_common.c
@@ -54,6 +54,7 @@ static const struct debug_control debug_control[] = {
{ "sw", WSI_DEBUG_SW },
{ "noshm", WSI_DEBUG_NOSHM },
{ "linear", WSI_DEBUG_LINEAR },
+ { "dxgi", WSI_DEBUG_DXGI },
{ NULL, },
};
@@ -162,6 +163,7 @@ wsi_device_init(struct wsi_device *wsi,
WSI_GET_CB(FreeMemory);
WSI_GET_CB(FreeCommandBuffers);
WSI_GET_CB(GetBufferMemoryRequirements);
+ WSI_GET_CB(GetFenceStatus);
WSI_GET_CB(GetImageDrmFormatModifierPropertiesEXT);
WSI_GET_CB(GetImageMemoryRequirements);
WSI_GET_CB(GetImageSubresourceLayout);
@@ -276,6 +278,12 @@ wsi_DestroySurfaceKHR(VkInstance _instance,
return;
}
#endif
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+ if (surface->platform == VK_ICD_WSI_PLATFORM_WIN32) {
+ wsi_win32_surface_destroy(surface, _instance, pAllocator);
+ return;
+ }
+#endif
vk_free2(&instance->alloc, pAllocator, surface);
}
@@ -291,7 +299,8 @@ wsi_device_setup_syncobj_fd(struct wsi_device *wsi_device,
static enum wsi_swapchain_blit_type
get_blit_type(const struct wsi_device *wsi,
- const struct wsi_base_image_params *params)
+ const struct wsi_base_image_params *params,
+ VkDevice device)
{
switch (params->image_type) {
case WSI_IMAGE_TYPE_CPU: {
@@ -308,6 +317,13 @@ get_blit_type(const struct wsi_device *wsi,
WSI_SWAPCHAIN_BUFFER_BLIT : WSI_SWAPCHAIN_NO_BLIT;
}
#endif
+#ifdef _WIN32
+ case WSI_IMAGE_TYPE_DXGI: {
+ const struct wsi_dxgi_image_params *dxgi_params =
+ container_of(params, const struct wsi_dxgi_image_params, base);
+ return wsi_dxgi_image_needs_blit(wsi, dxgi_params, device);
+ }
+#endif
default:
unreachable("Invalid image type");
}
@@ -332,6 +348,13 @@ configure_image(const struct wsi_swapchain *chain,
return wsi_drm_configure_image(chain, pCreateInfo, drm_params, info);
}
#endif
+#ifdef _WIN32
+ case WSI_IMAGE_TYPE_DXGI: {
+ const struct wsi_dxgi_image_params *dxgi_params =
+ container_of(params, const struct wsi_dxgi_image_params, base);
+ return wsi_dxgi_configure_image(chain, pCreateInfo, dxgi_params, info);
+ }
+#endif
default:
unreachable("Invalid image type");
}
@@ -381,7 +404,7 @@ wsi_swapchain_init(const struct wsi_device *wsi,
chain->wsi = wsi;
chain->device = _device;
chain->alloc = *pAllocator;
- chain->blit.type = get_blit_type(wsi, image_params);
+ chain->blit.type = get_blit_type(wsi, image_params, _device);
chain->blit.queue = VK_NULL_HANDLE;
if (chain->blit.type != WSI_SWAPCHAIN_NO_BLIT && wsi->get_blit_queue)
diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h
index 22e4313d09c..bea1bcd3dbc 100644
--- a/src/vulkan/wsi/wsi_common.h
+++ b/src/vulkan/wsi/wsi_common.h
@@ -147,6 +147,15 @@ struct wsi_device {
bool xwaylandWaitReady;
} x11;
+ struct {
+ void *(*get_d3d12_command_queue)(VkDevice device);
+ /* Needs to be per VkDevice, not VkPhysicalDevice, depends on queue config */
+ bool (*requires_blits)(VkDevice device);
+ VkResult (*create_image_memory)(VkDevice device, void *resource,
+ const VkAllocationCallbacks *alloc,
+ VkDeviceMemory *out);
+ } win32;
+
bool sw;
/* Set to true if the implementation is ok with linear WSI images. */
@@ -224,6 +233,7 @@ struct wsi_device {
WSI_CB(FreeMemory);
WSI_CB(FreeCommandBuffers);
WSI_CB(GetBufferMemoryRequirements);
+ WSI_CB(GetFenceStatus);
WSI_CB(GetImageDrmFormatModifierPropertiesEXT);
WSI_CB(GetImageMemoryRequirements);
WSI_CB(GetImageSubresourceLayout);
diff --git a/src/vulkan/wsi/wsi_common_private.h b/src/vulkan/wsi/wsi_common_private.h
index d589732cd76..8df14f33a8c 100644
--- a/src/vulkan/wsi/wsi_common_private.h
+++ b/src/vulkan/wsi/wsi_common_private.h
@@ -39,12 +39,14 @@ struct wsi_swapchain;
#define WSI_DEBUG_SW (1ull << 1)
#define WSI_DEBUG_NOSHM (1ull << 2)
#define WSI_DEBUG_LINEAR (1ull << 3)
+#define WSI_DEBUG_DXGI (1ull << 4)
extern uint64_t WSI_DEBUG;
enum wsi_image_type {
WSI_IMAGE_TYPE_CPU,
WSI_IMAGE_TYPE_DRM,
+ WSI_IMAGE_TYPE_DXGI,
};
struct wsi_base_image_params {
@@ -67,6 +69,11 @@ struct wsi_drm_image_params {
const uint64_t *const *modifiers;
};
+struct wsi_dxgi_image_params {
+ struct wsi_base_image_params base;
+ bool storage_image;
+};
+
typedef uint32_t (*wsi_memory_type_select_cb)(const struct wsi_device *wsi,
uint32_t type_bits);
@@ -190,6 +197,10 @@ void
wsi_wl_surface_destroy(VkIcdSurfaceBase *icd_surface, VkInstance _instance,
const VkAllocationCallbacks *pAllocator);
+void
+wsi_win32_surface_destroy(VkIcdSurfaceBase *icd_surface, VkInstance _instance,
+ const VkAllocationCallbacks *pAllocator);
+
VkResult
wsi_swapchain_init(const struct wsi_device *wsi,
struct wsi_swapchain *chain,
@@ -217,12 +228,23 @@ bool
wsi_drm_image_needs_buffer_blit(const struct wsi_device *wsi,
const struct wsi_drm_image_params *params);
+enum wsi_swapchain_blit_type
+wsi_dxgi_image_needs_blit(const struct wsi_device *wsi,
+ const struct wsi_dxgi_image_params *params,
+ VkDevice device);
+
VkResult
wsi_drm_configure_image(const struct wsi_swapchain *chain,
const VkSwapchainCreateInfoKHR *pCreateInfo,
const struct wsi_drm_image_params *params,
struct wsi_image_info *info);
+VkResult
+wsi_dxgi_configure_image(const struct wsi_swapchain *chain,
+ const VkSwapchainCreateInfoKHR *pCreateInfo,
+ const struct wsi_dxgi_image_params *params,
+ struct wsi_image_info *info);
+
bool
wsi_cpu_image_needs_buffer_blit(const struct wsi_device *wsi,
const struct wsi_cpu_image_params *params);
diff --git a/src/vulkan/wsi/wsi_common_win32.cpp b/src/vulkan/wsi/wsi_common_win32.cpp
index 5da7eedbcb5..16899b622b0 100644
--- a/src/vulkan/wsi/wsi_common_win32.cpp
+++ b/src/vulkan/wsi/wsi_common_win32.cpp
@@ -33,6 +33,13 @@
#include "wsi_common_entrypoints.h"
#include "wsi_common_private.h"
+#define D3D12_IGNORE_SDK_LAYERS
+#include <dxgi1_4.h>
+#include <directx/d3d12.h>
+#include <dxguids/dxguids.h>
+
+#include <dcomp.h>
+
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
#endif
@@ -46,22 +53,53 @@ struct wsi_win32 {
const VkAllocationCallbacks *alloc;
VkPhysicalDevice physical_device;
+ struct {
+ IDXGIFactory4 *factory;
+ IDCompositionDevice *dcomp;
+ } dxgi;
+};
+
+enum wsi_win32_image_state {
+ WSI_IMAGE_IDLE,
+ WSI_IMAGE_DRAWING,
+ WSI_IMAGE_QUEUED,
};
struct wsi_win32_image {
struct wsi_image base;
+ enum wsi_win32_image_state state;
struct wsi_win32_swapchain *chain;
- HDC dc;
- HBITMAP bmp;
- int bmp_row_pitch;
- void *ppvBits;
+ struct {
+ ID3D12Resource *swapchain_res;
+ } dxgi;
+ struct {
+ HDC dc;
+ HBITMAP bmp;
+ int bmp_row_pitch;
+ void *ppvBits;
+ } sw;
};
+struct wsi_win32_surface {
+ VkIcdSurfaceWin32 base;
+
+ /* The first time a swapchain is created against this surface, a DComp
+ * target/visual will be created for it and that swapchain will be bound.
+ * When a new swapchain is created, we delay changing the visual's content
+ * until that swapchain has completed its first present once, otherwise the
+ * window will flash white. When the currently-bound swapchain is destroyed,
+ * the visual's content is unset.
+ */
+ IDCompositionTarget *target;
+ IDCompositionVisual *visual;
+ struct wsi_win32_swapchain *current_swapchain;
+};
struct wsi_win32_swapchain {
struct wsi_swapchain base;
+ IDXGISwapChain3 *dxgi;
struct wsi_win32 *wsi;
- VkIcdSurfaceWin32 *surface;
+ wsi_win32_surface *surface;
uint64_t flip_sequence;
VkResult status;
VkExtent2D extent;
@@ -84,26 +122,39 @@ wsi_CreateWin32SurfaceKHR(VkInstance _instance,
VkSurfaceKHR *pSurface)
{
VK_FROM_HANDLE(vk_instance, instance, _instance);
- VkIcdSurfaceWin32 *surface;
+ wsi_win32_surface *surface;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR);
- surface = (VkIcdSurfaceWin32 *)vk_zalloc2(&instance->alloc, pAllocator, sizeof(*surface), 8,
+ surface = (wsi_win32_surface *)vk_zalloc2(&instance->alloc, pAllocator, sizeof(*surface), 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (surface == NULL)
return VK_ERROR_OUT_OF_HOST_MEMORY;
- surface->base.platform = VK_ICD_WSI_PLATFORM_WIN32;
+ surface->base.base.platform = VK_ICD_WSI_PLATFORM_WIN32;
- surface->hinstance = pCreateInfo->hinstance;
- surface->hwnd = pCreateInfo->hwnd;
+ surface->base.hinstance = pCreateInfo->hinstance;
+ surface->base.hwnd = pCreateInfo->hwnd;
- *pSurface = VkIcdSurfaceBase_to_handle(&surface->base);
+ *pSurface = VkIcdSurfaceBase_to_handle(&surface->base.base);
return VK_SUCCESS;
}
+void
+wsi_win32_surface_destroy(VkIcdSurfaceBase *icd_surface, VkInstance _instance,
+ const VkAllocationCallbacks *pAllocator)
+{
+ VK_FROM_HANDLE(vk_instance, instance, _instance);
+ wsi_win32_surface *surface = (wsi_win32_surface *)icd_surface;
+ if (surface->visual)
+ surface->visual->Release();
+ if (surface->target)
+ surface->target->Release();
+ vk_free2(&instance->alloc, pAllocator, icd_surface);
+}
+
static VkResult
wsi_win32_surface_get_support(VkIcdSurfaceBase *surface,
struct wsi_device *wsi_device,
@@ -127,8 +178,18 @@ wsi_win32_surface_get_capabilities(VkIcdSurfaceBase *surf,
return VK_ERROR_SURFACE_LOST_KHR;
caps->minImageCount = 1;
- /* There is no real maximum */
- caps->maxImageCount = 0;
+
+ if (!wsi_device->sw && wsi_device->win32.get_d3d12_command_queue) {
+ /* DXGI doesn't support random presenting order (images need to
+ * be presented in the order they were acquired), so we can't
+ * expose more than two image per swapchain.
+ */
+ caps->minImageCount = caps->maxImageCount = 2;
+ } else {
+ caps->minImageCount = 1;
+ /* Software callbacke, there is no real maximum */
+ caps->maxImageCount = 0;
+ }
caps->currentExtent = {
(uint32_t)win_rect.right - (uint32_t)win_rect.left,
@@ -302,13 +363,112 @@ wsi_win32_surface_get_present_rectangles(VkIcdSurfaceBase *surface,
}
static VkResult
+wsi_create_dxgi_image_mem(const struct wsi_swapchain *drv_chain,
+ const struct wsi_image_info *info,
+ struct wsi_image *image)
+{
+ struct wsi_win32_swapchain *chain = (struct wsi_win32_swapchain *)drv_chain;
+ const struct wsi_device *wsi = chain->base.wsi;
+
+ assert(chain->base.blit.type != WSI_SWAPCHAIN_BUFFER_BLIT);
+
+ struct wsi_win32_image *win32_image =
+ container_of(image, struct wsi_win32_image, base);
+ uint32_t image_idx =
+ ((uintptr_t)win32_image - (uintptr_t)chain->images) /
+ sizeof(*win32_image);
+ if (FAILED(chain->dxgi->GetBuffer(image_idx,
+ IID_PPV_ARGS(&win32_image->dxgi.swapchain_res))))
+ return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+
+ VkResult result =
+ wsi->win32.create_image_memory(chain->base.device,
+ win32_image->dxgi.swapchain_res,
+ &chain->base.alloc,
+ chain->base.blit.type == WSI_SWAPCHAIN_NO_BLIT ?
+ &image->memory : &image->blit.memory);
+ if (result != VK_SUCCESS)
+ return result;
+
+ if (chain->base.blit.type == WSI_SWAPCHAIN_NO_BLIT)
+ return VK_SUCCESS;
+
+ VkImageCreateInfo create = info->create;
+
+ create.usage &= ~VK_IMAGE_USAGE_STORAGE_BIT;
+ create.initialLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+
+ result = wsi->CreateImage(chain->base.device, &create,
+ &chain->base.alloc, &image->blit.image);
+ if (result != VK_SUCCESS)
+ return result;
+
+ result = wsi->BindImageMemory(chain->base.device, image->blit.image,
+ image->blit.memory, 0);
+ if (result != VK_SUCCESS)
+ return result;
+
+ VkMemoryRequirements reqs;
+ wsi->GetImageMemoryRequirements(chain->base.device, image->image, &reqs);
+
+ const VkMemoryDedicatedAllocateInfo memory_dedicated_info = {
+ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
+ nullptr,
+ image->blit.image,
+ VK_NULL_HANDLE,
+ };
+ const VkMemoryAllocateInfo memory_info = {
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ &memory_dedicated_info,
+ reqs.size,
+ info->select_image_memory_type(wsi, reqs.memoryTypeBits),
+ };
+
+ return wsi->AllocateMemory(chain->base.device, &memory_info,
+ &chain->base.alloc, &image->memory);
+}
+
+enum wsi_swapchain_blit_type
+wsi_dxgi_image_needs_blit(const struct wsi_device *wsi,
+ const struct wsi_dxgi_image_params *params,
+ VkDevice device)
+{
+ if (wsi->win32.requires_blits && wsi->win32.requires_blits(device))
+ return WSI_SWAPCHAIN_IMAGE_BLIT;
+ else if (params->storage_image)
+ return WSI_SWAPCHAIN_IMAGE_BLIT;
+ return WSI_SWAPCHAIN_NO_BLIT;
+}
+
+VkResult
+wsi_dxgi_configure_image(const struct wsi_swapchain *chain,
+ const VkSwapchainCreateInfoKHR *pCreateInfo,
+ const struct wsi_dxgi_image_params *params,
+ struct wsi_image_info *info)
+{
+ VkResult result =
+ wsi_configure_image(chain, pCreateInfo, 0, info);
+ if (result != VK_SUCCESS)
+ return result;
+
+ info->create_mem = wsi_create_dxgi_image_mem;
+
+ if (chain->blit.type != WSI_SWAPCHAIN_NO_BLIT) {
+ wsi_configure_image_blit_image(chain, info);
+ info->select_image_memory_type = wsi_select_device_memory_type;
+ info->select_blit_dst_memory_type = wsi_select_device_memory_type;
+ }
+
+ return VK_SUCCESS;
+}
+
+static VkResult
wsi_win32_image_init(VkDevice device_h,
struct wsi_win32_swapchain *chain,
const VkSwapchainCreateInfoKHR *create_info,
const VkAllocationCallbacks *allocator,
struct wsi_win32_image *image)
{
- assert(chain->base.blit.type == WSI_SWAPCHAIN_BUFFER_BLIT);
VkResult result = wsi_create_image(&chain->base, &chain->base.image_info,
&image->base);
if (result != VK_SUCCESS)
@@ -317,8 +477,12 @@ wsi_win32_image_init(VkDevice device_h,
VkIcdSurfaceWin32 *win32_surface = (VkIcdSurfaceWin32 *)create_info->surface;
chain->wnd = win32_surface->hwnd;
chain->chain_dc = GetDC(chain->wnd);
+ image->chain = chain;
- image->dc = CreateCompatibleDC(chain->chain_dc);
+ if (chain->base.blit.type != WSI_SWAPCHAIN_BUFFER_BLIT)
+ return VK_SUCCESS;
+
+ image->sw.dc = CreateCompatibleDC(chain->chain_dc);
HBITMAP bmp = NULL;
BITMAPINFO info = { 0 };
@@ -329,17 +493,16 @@ wsi_win32_image_init(VkDevice device_h,
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biCompression = BI_RGB;
- bmp = CreateDIBSection(image->dc, &info, DIB_RGB_COLORS, &image->ppvBits, NULL, 0);
- assert(bmp && image->ppvBits);
+ bmp = CreateDIBSection(image->sw.dc, &info, DIB_RGB_COLORS, &image->sw.ppvBits, NULL, 0);
+ assert(bmp && image->sw.ppvBits);
- SelectObject(image->dc, bmp);
+ SelectObject(image->sw.dc, bmp);
BITMAP header;
int status = GetObject(bmp, sizeof(BITMAP), &header);
(void)status;
- image->bmp_row_pitch = header.bmWidthBytes;
- image->bmp = bmp;
- image->chain = chain;
+ image->sw.bmp_row_pitch = header.bmWidthBytes;
+ image->sw.bmp = bmp;
return VK_SUCCESS;
}
@@ -349,9 +512,13 @@ wsi_win32_image_finish(struct wsi_win32_swapchain *chain,
const VkAllocationCallbacks *allocator,
struct wsi_win32_image *image)
{
- DeleteDC(image->dc);
- if(image->bmp)
- DeleteObject(image->bmp);
+ if (image->dxgi.swapchain_res)
+ image->dxgi.swapchain_res->Release();
+
+ if (image->sw.dc)
+ DeleteDC(image->sw.dc);
+ if(image->sw.bmp)
+ DeleteObject(image->sw.bmp);
wsi_destroy_image(&chain->base, &image->base);
}
@@ -367,6 +534,12 @@ wsi_win32_swapchain_destroy(struct wsi_swapchain *drv_chain,
DeleteDC(chain->chain_dc);
+ if (chain->surface->current_swapchain == chain)
+ chain->surface->current_swapchain = NULL;
+
+ if (chain->dxgi)
+ chain->dxgi->Release();
+
wsi_swapchain_finish(&chain->base);
vk_free(allocator, chain);
return VK_SUCCESS;
@@ -394,7 +567,66 @@ wsi_win32_acquire_next_image(struct wsi_swapchain *drv_chain,
if (chain->status != VK_SUCCESS)
return chain->status;
- *image_index = 0;
+ for (uint32_t i = 0; i < chain->base.image_count; i++) {
+ if (chain->images[i].state == WSI_IMAGE_IDLE) {
+ *image_index = i;
+ chain->images[i].state = WSI_IMAGE_DRAWING;
+ return VK_SUCCESS;
+ }
+ }
+
+ assert(chain->dxgi);
+ uint32_t index = chain->dxgi->GetCurrentBackBufferIndex();
+ if (chain->wsi->wsi->WaitForFences(chain->base.device, 1,
+ &chain->base.fences[index],
+ false, 2000) != VK_SUCCESS)
+ return VK_TIMEOUT;
+
+ *image_index = index;
+ chain->images[index].state = WSI_IMAGE_DRAWING;
+ return VK_SUCCESS;
+}
+
+static VkResult
+wsi_win32_queue_present_dxgi(struct wsi_win32_swapchain *chain,
+ struct wsi_win32_image *image,
+ const VkPresentRegionKHR *damage)
+{
+ uint32_t rect_count = damage ? damage->rectangleCount : 0;
+ STACK_ARRAY(RECT, rects, rect_count);
+
+ for (uint32_t r = 0; r < rect_count; r++) {
+ rects[r].left = damage->pRectangles[r].offset.x;
+ rects[r].top = damage->pRectangles[r].offset.y;
+ rects[r].right = damage->pRectangles[r].offset.x + damage->pRectangles[r].extent.width;
+ rects[r].bottom = damage->pRectangles[r].offset.y + damage->pRectangles[r].extent.height;
+ }
+
+ DXGI_PRESENT_PARAMETERS params = {
+ rect_count,
+ rects,
+ };
+
+ image->state = WSI_IMAGE_QUEUED;
+
+ HRESULT hres = chain->dxgi->Present1(0, 0, &params);
+ switch (hres) {
+ case DXGI_ERROR_DEVICE_REMOVED: return VK_ERROR_DEVICE_LOST;
+ case E_OUTOFMEMORY: return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+ default:
+ if (FAILED(hres))
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ break;
+ }
+
+ if (chain->surface->current_swapchain != chain) {
+ chain->surface->visual->SetContent(chain->dxgi);
+ chain->wsi->dxgi.dcomp->Commit();
+ chain->surface->current_swapchain = chain;
+ }
+
+ /* Mark the other image idle */
+ chain->status = VK_SUCCESS;
return VK_SUCCESS;
}
@@ -408,23 +640,88 @@ wsi_win32_queue_present(struct wsi_swapchain *drv_chain,
assert(image_index < chain->base.image_count);
struct wsi_win32_image *image = &chain->images[image_index];
+ assert(image->state == WSI_IMAGE_DRAWING);
+
+ if (chain->dxgi)
+ return wsi_win32_queue_present_dxgi(chain, image, damage);
+
assert(chain->base.blit.type == WSI_SWAPCHAIN_BUFFER_BLIT);
char *ptr = (char *)image->base.cpu_map;
- char *dptr = (char *)image->ppvBits;
+ char *dptr = (char *)image->sw.ppvBits;
for (unsigned h = 0; h < chain->extent.height; h++) {
memcpy(dptr, ptr, chain->extent.width * 4);
- dptr += image->bmp_row_pitch;
+ dptr += image->sw.bmp_row_pitch;
ptr += image->base.row_pitches[0];
}
- if (!StretchBlt(chain->chain_dc, 0, 0, chain->extent.width, chain->extent.height, image->dc, 0, 0, chain->extent.width, chain->extent.height, SRCCOPY))
+ if (!StretchBlt(chain->chain_dc, 0, 0, chain->extent.width, chain->extent.height, image->sw.dc, 0, 0, chain->extent.width, chain->extent.height, SRCCOPY))
chain->status = VK_ERROR_MEMORY_MAP_FAILED;
+ image->state = WSI_IMAGE_IDLE;
+
return chain->status;
}
static VkResult
+wsi_win32_surface_create_swapchain_dxgi(
+ wsi_win32_surface *surface,
+ VkDevice device,
+ struct wsi_win32 *wsi,
+ const VkSwapchainCreateInfoKHR *create_info,
+ struct wsi_win32_swapchain *chain)
+{
+ IDXGIFactory4 *factory = wsi->dxgi.factory;
+ ID3D12CommandQueue *queue =
+ (ID3D12CommandQueue *)wsi->wsi->win32.get_d3d12_command_queue(device);
+
+ DXGI_SWAP_CHAIN_DESC1 desc = {
+ create_info->imageExtent.width,
+ create_info->imageExtent.height,
+ create_info->imageFormat == VK_FORMAT_B8G8R8A8_SRGB ?
+ DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM,
+ create_info->imageArrayLayers > 1, // Stereo
+ { 1 }, // SampleDesc
+ 0, // Usage (filled in below)
+ create_info->minImageCount,
+ DXGI_SCALING_STRETCH,
+ DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
+ DXGI_ALPHA_MODE_UNSPECIFIED,
+ 0, // Flags
+ };
+
+ if (create_info->imageUsage &
+ (VK_IMAGE_USAGE_SAMPLED_BIT |
+ VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))
+ desc.BufferUsage |= DXGI_USAGE_SHADER_INPUT;
+
+ if (create_info->imageUsage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
+ desc.BufferUsage |= DXGI_USAGE_RENDER_TARGET_OUTPUT;
+
+ IDXGISwapChain1 *swapchain1;
+ if (FAILED(factory->CreateSwapChainForComposition(queue, &desc, NULL, &swapchain1)) ||
+ FAILED(swapchain1->QueryInterface(&chain->dxgi)))
+ return VK_ERROR_INITIALIZATION_FAILED;
+
+ swapchain1->Release();
+
+ if (!surface->target &&
+ FAILED(wsi->dxgi.dcomp->CreateTargetForHwnd(surface->base.hwnd, false, &surface->target)))
+ return VK_ERROR_INITIALIZATION_FAILED;
+
+ if (!surface->visual) {
+ if (FAILED(wsi->dxgi.dcomp->CreateVisual(&surface->visual)) ||
+ FAILED(surface->target->SetRoot(surface->visual)) ||
+ FAILED(surface->visual->SetContent(chain->dxgi)) ||
+ FAILED(wsi->dxgi.dcomp->Commit()))
+ return VK_ERROR_INITIALIZATION_FAILED;
+
+ surface->current_swapchain = chain;
+ }
+ return VK_SUCCESS;
+}
+
+static VkResult
wsi_win32_surface_create_swapchain(
VkIcdSurfaceBase *icd_surface,
VkDevice device,
@@ -433,7 +730,7 @@ wsi_win32_surface_create_swapchain(
const VkAllocationCallbacks *allocator,
struct wsi_swapchain **swapchain_out)
{
- VkIcdSurfaceWin32 *surface = (VkIcdSurfaceWin32 *)icd_surface;
+ wsi_win32_surface *surface = (wsi_win32_surface *)icd_surface;
struct wsi_win32 *wsi =
(struct wsi_win32 *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32];
@@ -449,12 +746,23 @@ wsi_win32_surface_create_swapchain(
if (chain == NULL)
return VK_ERROR_OUT_OF_HOST_MEMORY;
- struct wsi_cpu_image_params image_params = {
+ struct wsi_dxgi_image_params dxgi_image_params = {
+ { WSI_IMAGE_TYPE_DXGI },
+ };
+ dxgi_image_params.storage_image = (create_info->imageUsage & VK_IMAGE_USAGE_STORAGE_BIT) != 0;
+
+ struct wsi_cpu_image_params cpu_image_params = {
{ WSI_IMAGE_TYPE_CPU },
};
+ bool supports_dxgi = wsi->dxgi.factory &&
+ wsi->dxgi.dcomp &&
+ wsi->wsi->win32.get_d3d12_command_queue;
+ struct wsi_base_image_params *image_params = supports_dxgi ?
+ &dxgi_image_params.base : &cpu_image_params.base;
+
VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
- create_info, &image_params.base,
+ create_info, image_params,
allocator);
if (result != VK_SUCCESS) {
vk_free(allocator, chain);
@@ -473,7 +781,11 @@ wsi_win32_surface_create_swapchain(
chain->surface = surface;
- assert(wsi_device->sw);
+ if (image_params->image_type == WSI_IMAGE_TYPE_DXGI) {
+ result = wsi_win32_surface_create_swapchain_dxgi(surface, device, wsi, create_info, chain);
+ if (result != VK_SUCCESS)
+ goto fail;
+ }
for (uint32_t image = 0; image < num_images; image++) {
result = wsi_win32_image_init(device, chain,
@@ -490,10 +802,68 @@ wsi_win32_surface_create_swapchain(
return VK_SUCCESS;
fail:
+ if (surface->visual) {
+ surface->visual->SetContent(NULL);
+ surface->current_swapchain = NULL;
+ wsi->dxgi.dcomp->Commit();
+ }
wsi_win32_swapchain_destroy(&chain->base, allocator);
return result;
}
+static IDXGIFactory4 *
+dxgi_get_factory(bool debug)
+{
+ HMODULE dxgi_mod = LoadLibraryA("DXGI.DLL");
+ if (!dxgi_mod) {
+ return NULL;
+ }
+
+ typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY2)(UINT flags, REFIID riid, void **ppFactory);
+ PFN_CREATE_DXGI_FACTORY2 CreateDXGIFactory2;
+
+ CreateDXGIFactory2 = (PFN_CREATE_DXGI_FACTORY2)GetProcAddress(dxgi_mod, "CreateDXGIFactory2");
+ if (!CreateDXGIFactory2) {
+ return NULL;
+ }
+
+ UINT flags = 0;
+ if (debug)
+ flags |= DXGI_CREATE_FACTORY_DEBUG;
+
+ IDXGIFactory4 *factory;
+ HRESULT hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(&factory));
+ if (FAILED(hr)) {
+ return NULL;
+ }
+
+ return factory;
+}
+
+static IDCompositionDevice *
+dcomp_get_device()
+{
+ HMODULE dcomp_mod = LoadLibraryA("DComp.DLL");
+ if (!dcomp_mod) {
+ return NULL;
+ }
+
+ typedef HRESULT (STDAPICALLTYPE *PFN_DCOMP_CREATE_DEVICE)(IDXGIDevice *, REFIID, void **);
+ PFN_DCOMP_CREATE_DEVICE DCompositionCreateDevice;
+
+ DCompositionCreateDevice = (PFN_DCOMP_CREATE_DEVICE)GetProcAddress(dcomp_mod, "DCompositionCreateDevice");
+ if (!DCompositionCreateDevice) {
+ return NULL;
+ }
+
+ IDCompositionDevice *device;
+ HRESULT hr = DCompositionCreateDevice(NULL, IID_PPV_ARGS(&device));
+ if (FAILED(hr)) {
+ return NULL;
+ }
+
+ return device;
+}
VkResult
wsi_win32_init_wsi(struct wsi_device *wsi_device,
@@ -503,8 +873,8 @@ wsi_win32_init_wsi(struct wsi_device *wsi_device,
struct wsi_win32 *wsi;
VkResult result;
- wsi = (wsi_win32 *)vk_alloc(alloc, sizeof(*wsi), 8,
- VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ wsi = (wsi_win32 *)vk_zalloc(alloc, sizeof(*wsi), 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (!wsi) {
result = VK_ERROR_OUT_OF_HOST_MEMORY;
goto fail;
@@ -514,6 +884,22 @@ wsi_win32_init_wsi(struct wsi_device *wsi_device,
wsi->alloc = alloc;
wsi->wsi = wsi_device;
+ if (!wsi_device->sw) {
+ wsi->dxgi.factory = dxgi_get_factory(WSI_DEBUG & WSI_DEBUG_DXGI);
+ if (!wsi->dxgi.factory) {
+ vk_free(alloc, wsi);
+ result = VK_ERROR_INITIALIZATION_FAILED;
+ goto fail;
+ }
+ wsi->dxgi.dcomp = dcomp_get_device();
+ if (!wsi->dxgi.dcomp) {
+ wsi->dxgi.factory->Release();
+ vk_free(alloc, wsi);
+ result = VK_ERROR_INITIALIZATION_FAILED;
+ goto fail;
+ }
+ }
+
wsi->base.get_support = wsi_win32_surface_get_support;
wsi->base.get_capabilities2 = wsi_win32_surface_get_capabilities2;
wsi->base.get_formats = wsi_win32_surface_get_formats;
@@ -541,5 +927,10 @@ wsi_win32_finish_wsi(struct wsi_device *wsi_device,
if (!wsi)
return;
+ if (wsi->dxgi.factory)
+ wsi->dxgi.factory->Release();
+ if (wsi->dxgi.dcomp)
+ wsi->dxgi.dcomp->Release();
+
vk_free(alloc, wsi);
}