#include <xf86drm.h>
#include "drm-uapi/drm_fourcc.h"
#include "util/hash_table.h"
+#include "util/xmlconfig.h"
#include "vk_util.h"
+#include "vk_enum_to_str.h"
#include "wsi_common_private.h"
#include "wsi_common_x11.h"
#include "wsi_common_queue.h"
return VK_SUCCESS;
}
+static uint32_t
+x11_get_min_image_count(struct wsi_device *wsi_device)
+{
+ if (wsi_device->x11.override_minImageCount)
+ return wsi_device->x11.override_minImageCount;
+
+ /* For IMMEDIATE and FIFO, most games work in a pipelined manner where the
+ * can produce frames at a rate of 1/MAX(CPU duration, GPU duration), but
+ * the render latency is CPU duration + GPU duration.
+ *
+ * This means that with scanout from pageflipping we need 3 frames to run
+ * full speed:
+ * 1) CPU rendering work
+ * 2) GPU rendering work
+ * 3) scanout
+ *
+ * Once we have a nonblocking acquire that returns a semaphore we can merge
+ * 1 and 3. Hence the ideal implementation needs only 2 images, but games
+ * cannot tellwe currently do not have an ideal implementation and that
+ * hence they need to allocate 3 images. So let us do it for them.
+ *
+ * This is a tradeoff as it uses more memory than needed for non-fullscreen
+ * and non-performance intensive applications.
+ */
+ return 3;
+}
+
static VkResult
x11_surface_get_capabilities(VkIcdSurfaceBase *icd_surface,
struct wsi_device *wsi_device,
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
}
- /* For IMMEDIATE and FIFO, most games work in a pipelined manner where the
- * can produce frames at a rate of 1/MAX(CPU duration, GPU duration), but
- * the render latency is CPU duration + GPU duration.
- *
- * This means that with scanout from pageflipping we need 3 frames to run
- * full speed:
- * 1) CPU rendering work
- * 2) GPU rendering work
- * 3) scanout
- *
- * Once we have a nonblocking acquire that returns a semaphore we can merge
- * 1 and 3. Hence the ideal implementation needs only 2 images, but games
- * cannot tellwe currently do not have an ideal implementation and that
- * hence they need to allocate 3 images. So let us do it for them.
- *
- * This is a tradeoff as it uses more memory than needed for non-fullscreen
- * and non-performance intensive applications.
- */
- caps->minImageCount = 3;
+ caps->minImageCount = x11_get_min_image_count(wsi_device);
/* There is no real maximum */
caps->maxImageCount = 0;
return result;
}
+static void
+get_sorted_vk_formats(struct wsi_device *wsi_device, VkFormat *sorted_formats)
+{
+ memcpy(sorted_formats, formats, sizeof(formats));
+
+ if (wsi_device->force_bgra8_unorm_first) {
+ for (unsigned i = 0; i < ARRAY_SIZE(formats); i++) {
+ if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) {
+ sorted_formats[i] = sorted_formats[0];
+ sorted_formats[0] = VK_FORMAT_B8G8R8A8_UNORM;
+ break;
+ }
+ }
+ }
+}
+
static VkResult
x11_surface_get_formats(VkIcdSurfaceBase *surface,
struct wsi_device *wsi_device,
{
VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount);
- for (unsigned i = 0; i < ARRAY_SIZE(formats); i++) {
+ VkFormat sorted_formats[ARRAY_SIZE(formats)];
+ get_sorted_vk_formats(wsi_device, sorted_formats);
+
+ for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
vk_outarray_append(&out, f) {
- f->format = formats[i];
+ f->format = sorted_formats[i];
f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
}
}
{
VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount);
- for (unsigned i = 0; i < ARRAY_SIZE(formats); i++) {
+ VkFormat sorted_formats[ARRAY_SIZE(formats)];
+ get_sorted_vk_formats(wsi_device, sorted_formats);
+
+ for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
vk_outarray_append(&out, f) {
assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
- f->surfaceFormat.format = formats[i];
+ f->surfaceFormat.format = sorted_formats[i];
f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
}
}
VK_INCOMPLETE : VK_SUCCESS;
}
-static bool
-x11_surface_is_local_to_gpu(struct wsi_device *wsi_dev,
- xcb_connection_t *conn)
-{
- struct wsi_x11_connection *wsi_conn =
- wsi_x11_get_connection(wsi_dev, conn);
-
- if (!wsi_conn)
- return false;
-
- if (!wsi_x11_check_for_dri3(wsi_conn))
- return false;
-
- if (!wsi_x11_check_dri3_compatible(wsi_dev, conn))
- return false;
-
- return true;
-}
-
static VkResult
x11_surface_get_present_rectangles(VkIcdSurfaceBase *icd_surface,
struct wsi_device *wsi_device,
xcb_window_t window = x11_surface_get_window(icd_surface);
VK_OUTARRAY_MAKE(out, pRects, pRectCount);
- if (x11_surface_is_local_to_gpu(wsi_device, conn)) {
- vk_outarray_append(&out, rect) {
- xcb_generic_error_t *err = NULL;
- xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(conn, window);
- xcb_get_geometry_reply_t *geom =
- xcb_get_geometry_reply(conn, geom_cookie, &err);
- free(err);
- if (geom) {
- *rect = (VkRect2D) {
- .offset = { 0, 0 },
- .extent = { geom->width, geom->height },
- };
- } else {
- /* This can happen if the client didn't wait for the configure event
- * to come back from the compositor. In that case, we don't know the
- * size of the window so we just return valid "I don't know" stuff.
- */
- *rect = (VkRect2D) {
- .offset = { 0, 0 },
- .extent = { -1, -1 },
- };
- }
- free(geom);
+ vk_outarray_append(&out, rect) {
+ xcb_generic_error_t *err = NULL;
+ xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(conn, window);
+ xcb_get_geometry_reply_t *geom =
+ xcb_get_geometry_reply(conn, geom_cookie, &err);
+ free(err);
+ if (geom) {
+ *rect = (VkRect2D) {
+ .offset = { 0, 0 },
+ .extent = { geom->width, geom->height },
+ };
+ } else {
+ /* This can happen if the client didn't wait for the configure event
+ * to come back from the compositor. In that case, we don't know the
+ * size of the window so we just return valid "I don't know" stuff.
+ */
+ *rect = (VkRect2D) {
+ .offset = { 0, 0 },
+ .extent = { -1, -1 },
+ };
}
+ free(geom);
}
return vk_outarray_status(&out);
struct x11_image images[0];
};
-WSI_DEFINE_NONDISP_HANDLE_CASTS(x11_swapchain, VkSwapchainKHR)
+VK_DEFINE_NONDISP_HANDLE_CASTS(x11_swapchain, base.base, VkSwapchainKHR,
+ VK_OBJECT_TYPE_SWAPCHAIN_KHR)
/**
* Update the swapchain status with the result of an operation, and return
* this has not been seen, success will be returned.
*/
static VkResult
-x11_swapchain_result(struct x11_swapchain *chain, VkResult result)
+_x11_swapchain_result(struct x11_swapchain *chain, VkResult result,
+ const char *file, int line)
{
/* Prioritise returning existing errors for consistency. */
if (chain->status < 0)
/* If we have a new error, mark it as permanent on the chain and return. */
if (result < 0) {
+#ifndef NDEBUG
+ fprintf(stderr, "%s:%d: Swapchain status changed to %s\n",
+ file, line, vk_Result_to_str(result));
+#endif
chain->status = result;
return result;
}
* and is always returned rather than success.
*/
if (result == VK_SUBOPTIMAL_KHR) {
+#ifndef NDEBUG
+ if (chain->status != VK_SUBOPTIMAL_KHR) {
+ fprintf(stderr, "%s:%d: Swapchain status changed to %s\n",
+ file, line, vk_Result_to_str(result));
+ }
+#endif
chain->status = result;
return result;
}
/* No changes, so return the last status. */
return chain->status;
}
+#define x11_swapchain_result(chain, result) \
+ _x11_swapchain_result(chain, result, __FILE__, __LINE__)
static struct wsi_image *
x11_get_wsi_image(struct wsi_swapchain *wsi_chain, uint32_t image_index)
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
unsigned num_images = pCreateInfo->minImageCount;
- if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR)
+ if (wsi_device->x11.strict_imageCount)
+ num_images = pCreateInfo->minImageCount;
+ else if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR)
num_images = MAX2(num_images, 5);
+ else if (wsi_device->x11.ensure_minImageCount)
+ num_images = MAX2(num_images, x11_get_min_image_count(wsi_device));
xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
struct wsi_x11_connection *wsi_conn =
* mode which provokes reallocation when anything changes, to make
* sure we have the most optimal allocation.
*/
- WSI_FROM_HANDLE(x11_swapchain, old_chain, pCreateInfo->oldSwapchain);
+ VK_FROM_HANDLE(x11_swapchain, old_chain, pCreateInfo->oldSwapchain);
if (old_chain)
chain->last_present_mode = old_chain->last_present_mode;
else
VkResult
wsi_x11_init_wsi(struct wsi_device *wsi_device,
- const VkAllocationCallbacks *alloc)
+ const VkAllocationCallbacks *alloc,
+ const struct driOptionCache *dri_options)
{
struct wsi_x11 *wsi;
VkResult result;
goto fail_mutex;
}
+ if (dri_options) {
+ if (driCheckOption(dri_options, "vk_x11_override_min_image_count", DRI_INT)) {
+ wsi_device->x11.override_minImageCount =
+ driQueryOptioni(dri_options, "vk_x11_override_min_image_count");
+ }
+ if (driCheckOption(dri_options, "vk_x11_strict_image_count", DRI_BOOL)) {
+ wsi_device->x11.strict_imageCount =
+ driQueryOptionb(dri_options, "vk_x11_strict_image_count");
+ }
+ if (driCheckOption(dri_options, "vk_x11_ensure_min_image_count", DRI_BOOL)) {
+ wsi_device->x11.ensure_minImageCount =
+ driQueryOptionb(dri_options, "vk_x11_ensure_min_image_count");
+ }
+
+ }
+
wsi->base.get_support = x11_surface_get_support;
wsi->base.get_capabilities2 = x11_surface_get_capabilities2;
wsi->base.get_formats = x11_surface_get_formats;