wined3d: Don't use separate GL contexts for different swapchains.

This avoids triggering a Mesa slowpath introduced
by Mesa commit e7f3a8d6959c74f63c877dd8776fe519d54f946f.

Additionally, it helps applications using multiple swapchains and
queries (e.g. the one in bug 43773) by not requiring extra context
switches when polling queries. For the records, the actual issue from
bug 43773 was probably fixed a long time ago, maybe already by
7b62a970e9 or thereabouts.

The downside of this change is that we'll now end up calling
glFinish() when there are multiple threads using the same device when
CSMT is disabled. That's a non-default setting and one that should
only be used for troubleshooting purposes at this point, so it
shouldn't be too bad of an issue. It might also make sense to just get
rid of that glFinish() entirely, it's never going to be a complete
fix.
This commit is contained in:
Matteo Bruni 2020-08-05 20:09:38 +02:00 committed by Alexandre Julliard
parent ee349306e2
commit 72597b170e
5 changed files with 26 additions and 88 deletions

View file

@ -4567,7 +4567,7 @@ static HRESULT adapter_gl_init_3d(struct wined3d_device *device)
wined3d_cs_init_object(device->cs, wined3d_device_gl_create_primary_opengl_context_cs, wined3d_device_gl(device));
wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
if (!wined3d_swapchain_gl(device->swapchains[0])->context_count)
if (!device->context_count)
return E_FAIL;
return WINED3D_OK;

View file

@ -1261,6 +1261,8 @@ static BOOL wined3d_context_gl_set_gl_context(struct wined3d_context_gl *context
struct wined3d_device_gl *device_gl = wined3d_device_gl(context_gl->c.device);
BOOL backup = FALSE;
TRACE("context_gl %p.\n", context_gl);
if (!wined3d_context_gl_set_pixel_format(context_gl))
{
WARN("Failed to set pixel format %d on device context %p.\n",
@ -1366,6 +1368,8 @@ static void wined3d_context_gl_cleanup(struct wined3d_context_gl *context_gl)
HDC restore_dc;
unsigned int i;
TRACE("context_gl %p.\n", context_gl);
restore_ctx = wglGetCurrentContext();
restore_dc = wglGetCurrentDC();
@ -4481,6 +4485,12 @@ static void wined3d_context_gl_activate(struct wined3d_context_gl *context_gl,
struct wined3d_texture *texture, unsigned int sub_resource_idx)
{
wined3d_context_gl_enter(context_gl);
if (texture && texture->swapchain && texture->swapchain != context_gl->c.swapchain)
{
TRACE("Switching context_gl %p from swapchain %p to swapchain %p.\n",
context_gl, context_gl->c.swapchain, texture->swapchain);
context_gl->c.swapchain = texture->swapchain;
}
wined3d_context_gl_update_window(context_gl);
wined3d_context_gl_setup_target(context_gl, texture, sub_resource_idx);
if (!context_gl->valid)

View file

@ -1187,7 +1187,6 @@ bool wined3d_device_gl_create_bo(struct wined3d_device_gl *device_gl, struct win
void wined3d_device_gl_delete_opengl_contexts_cs(void *object)
{
struct wined3d_device_gl *device_gl = object;
struct wined3d_swapchain_gl *swapchain_gl;
struct wined3d_context_gl *context_gl;
struct wined3d_context *context;
struct wined3d_device *device;
@ -1219,12 +1218,7 @@ void wined3d_device_gl_delete_opengl_contexts_cs(void *object)
context_release(context);
while (device->context_count)
{
if ((swapchain_gl = wined3d_swapchain_gl(device->contexts[0]->swapchain)))
wined3d_swapchain_gl_destroy_contexts(swapchain_gl);
else
wined3d_context_gl_destroy(wined3d_context_gl(device->contexts[0]));
}
wined3d_context_gl_destroy(wined3d_context_gl(device->contexts[0]));
if (device_gl->backup_dc)
{
@ -1262,7 +1256,7 @@ void wined3d_device_gl_create_primary_opengl_context_cs(void *object)
{
WARN("Failed to initialise allocator.\n");
context_release(context);
wined3d_swapchain_gl_context_destroy(wined3d_swapchain_gl(swapchain), context_gl);
wined3d_context_gl_destroy(wined3d_context_gl(device->contexts[0]));
return;
}
@ -1272,7 +1266,7 @@ void wined3d_device_gl_create_primary_opengl_context_cs(void *object)
ERR("Failed to allocate shader private data, hr %#x.\n", hr);
wined3d_allocator_cleanup(&device_gl->allocator);
context_release(context);
wined3d_swapchain_gl_context_destroy(wined3d_swapchain_gl(swapchain), context_gl);
wined3d_context_gl_destroy(wined3d_context_gl(device->contexts[0]));
return;
}
@ -1282,7 +1276,7 @@ void wined3d_device_gl_create_primary_opengl_context_cs(void *object)
device->shader_backend->shader_free_private(device, NULL);
wined3d_allocator_cleanup(&device_gl->allocator);
context_release(context);
wined3d_swapchain_gl_context_destroy(wined3d_swapchain_gl(swapchain), context_gl);
wined3d_context_gl_destroy(wined3d_context_gl(device->contexts[0]));
return;
}

View file

@ -23,6 +23,7 @@
#include "wined3d_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
void wined3d_swapchain_cleanup(struct wined3d_swapchain *swapchain)
{
@ -85,19 +86,9 @@ void wined3d_swapchain_cleanup(struct wined3d_swapchain *swapchain)
}
}
static void wined3d_swapchain_gl_destroy_object(void *object)
{
wined3d_swapchain_gl_destroy_contexts(object);
}
void wined3d_swapchain_gl_cleanup(struct wined3d_swapchain_gl *swapchain_gl)
{
struct wined3d_cs *cs = swapchain_gl->s.device->cs;
wined3d_swapchain_cleanup(&swapchain_gl->s);
wined3d_cs_destroy_object(cs, wined3d_swapchain_gl_destroy_object, swapchain_gl);
wined3d_cs_finish(cs, WINED3D_CS_QUEUE_DEFAULT);
}
static void wined3d_swapchain_vk_destroy_vulkan_swapchain(struct wined3d_swapchain_vk *swapchain_vk)
@ -583,7 +574,6 @@ static bool swapchain_present_is_partial_copy(struct wined3d_swapchain *swapchai
static void swapchain_gl_present(struct wined3d_swapchain *swapchain,
const RECT *src_rect, const RECT *dst_rect, unsigned int swap_interval, uint32_t flags)
{
struct wined3d_swapchain_gl *swapchain_gl = wined3d_swapchain_gl(swapchain);
struct wined3d_texture *back_buffer = swapchain->back_buffers[0];
const struct wined3d_pixel_format *pixel_format;
const struct wined3d_gl_info *gl_info;
@ -619,8 +609,11 @@ static void swapchain_gl_present(struct wined3d_swapchain *swapchain,
if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
swapchain_blit(swapchain, context, src_rect, dst_rect);
if (swapchain_gl->context_count > 1)
if (swapchain->device->context_count > 1)
{
WARN_(d3d_perf)("Multiple contexts, calling glFinish() to enforce ordering.\n");
gl_info->gl_ops.gl.p_glFinish();
}
/* call wglSwapBuffers through the gl table to avoid confusing the Steam overlay */
gl_info->gl_ops.wgl.p_wglSwapBuffers(context_gl->dc);
@ -1688,20 +1681,11 @@ HRESULT wined3d_swapchain_gl_init(struct wined3d_swapchain_gl *swapchain_gl, str
struct wined3d_swapchain_desc *desc, struct wined3d_swapchain_state_parent *state_parent,
void *parent, const struct wined3d_parent_ops *parent_ops)
{
HRESULT hr;
TRACE("swapchain_gl %p, device %p, desc %p, state_parent %p, parent %p, parent_ops %p.\n",
swapchain_gl, device, desc, state_parent, parent, parent_ops);
if (FAILED(hr = wined3d_swapchain_init(&swapchain_gl->s, device, desc, state_parent, parent,
parent_ops, &swapchain_gl_ops)))
{
/* Cleanup any context that may have been created for the swapchain. */
wined3d_cs_destroy_object(device->cs, wined3d_swapchain_gl_destroy_object, swapchain_gl);
wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
}
return hr;
return wined3d_swapchain_init(&swapchain_gl->s, device, desc, state_parent, parent,
parent_ops, &swapchain_gl_ops);
}
HRESULT wined3d_swapchain_vk_init(struct wined3d_swapchain_vk *swapchain_vk, struct wined3d_device *device,
@ -1792,62 +1776,19 @@ static struct wined3d_context_gl *wined3d_swapchain_gl_create_context(struct win
context_release(&context_gl->c);
if (!wined3d_array_reserve((void **)&swapchain_gl->contexts, &swapchain_gl->contexts_size,
swapchain_gl->context_count + 1, sizeof(*swapchain_gl->contexts)))
{
ERR("Failed to allocate new context array memory.\n");
wined3d_context_gl_destroy(context_gl);
return NULL;
}
swapchain_gl->contexts[swapchain_gl->context_count++] = context_gl;
return context_gl;
}
void wined3d_swapchain_gl_context_destroy(struct wined3d_swapchain_gl *swapchain_gl, struct wined3d_context_gl *context_gl)
{
unsigned int i, j;
TRACE("swapchain_gl %p, context_gl %p.\n", swapchain_gl, context_gl);
for (i = 0; i < swapchain_gl->context_count; ++i)
{
if (swapchain_gl->contexts[i] == context_gl)
{
wined3d_context_gl_destroy(swapchain_gl->contexts[i]);
for (j = i; j < --swapchain_gl->context_count; ++j)
swapchain_gl->contexts[j] = swapchain_gl->contexts[j + 1];
return;
}
}
ERR("context_gl %p not found in the swapchain list.\n", context_gl);
}
void wined3d_swapchain_gl_destroy_contexts(struct wined3d_swapchain_gl *swapchain_gl)
{
unsigned int i;
TRACE("swapchain_gl %p.\n", swapchain_gl);
for (i = 0; i < swapchain_gl->context_count; ++i)
{
wined3d_context_gl_destroy(swapchain_gl->contexts[i]);
}
heap_free(swapchain_gl->contexts);
swapchain_gl->contexts_size = 0;
swapchain_gl->context_count = 0;
swapchain_gl->contexts = NULL;
}
struct wined3d_context_gl *wined3d_swapchain_gl_get_context(struct wined3d_swapchain_gl *swapchain_gl)
{
struct wined3d_device *device = swapchain_gl->s.device;
DWORD tid = GetCurrentThreadId();
unsigned int i;
for (i = 0; i < swapchain_gl->context_count; ++i)
for (i = 0; i < device->context_count; ++i)
{
if (swapchain_gl->contexts[i]->tid == tid)
return swapchain_gl->contexts[i];
if (wined3d_context_gl(device->contexts[i])->tid == tid)
return wined3d_context_gl(device->contexts[i]);
}
/* Create a new context for the thread. */

View file

@ -5708,10 +5708,6 @@ HRESULT wined3d_swapchain_no3d_init(struct wined3d_swapchain *swapchain_no3d,
struct wined3d_swapchain_gl
{
struct wined3d_swapchain s;
struct wined3d_context_gl **contexts;
SIZE_T contexts_size;
SIZE_T context_count;
};
static inline struct wined3d_swapchain_gl *wined3d_swapchain_gl(struct wined3d_swapchain *swapchain)
@ -5720,9 +5716,6 @@ static inline struct wined3d_swapchain_gl *wined3d_swapchain_gl(struct wined3d_s
}
void wined3d_swapchain_gl_cleanup(struct wined3d_swapchain_gl *swapchain_gl) DECLSPEC_HIDDEN;
void wined3d_swapchain_gl_context_destroy(struct wined3d_swapchain_gl *swapchain_gl,
struct wined3d_context_gl *context_gl) DECLSPEC_HIDDEN;
void wined3d_swapchain_gl_destroy_contexts(struct wined3d_swapchain_gl *swapchain_gl) DECLSPEC_HIDDEN;
struct wined3d_context_gl *wined3d_swapchain_gl_get_context(struct wined3d_swapchain_gl *swapchain_gl) DECLSPEC_HIDDEN;
HRESULT wined3d_swapchain_gl_init(struct wined3d_swapchain_gl *swapchain_gl,
struct wined3d_device *device, struct wined3d_swapchain_desc *desc,