From 602c82bce86db8fff427b146176490db8bf7529d Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Fri, 27 Sep 2013 00:15:13 +0200 Subject: [PATCH] wined3d: Send present operations through a command stream. The eventual goal is to have a multithreaded implementation of wined3d_cs_ops and offload some processing to a different thread. --- dlls/wined3d/Makefile.in | 1 + dlls/wined3d/cs.c | 128 +++++++++++++++++++++++++++++++++ dlls/wined3d/device.c | 25 +++++-- dlls/wined3d/swapchain.c | 5 +- dlls/wined3d/wined3d_private.h | 24 +++++++ 5 files changed, 174 insertions(+), 9 deletions(-) create mode 100644 dlls/wined3d/cs.c diff --git a/dlls/wined3d/Makefile.in b/dlls/wined3d/Makefile.in index b1051c27116..f77f35d2553 100644 --- a/dlls/wined3d/Makefile.in +++ b/dlls/wined3d/Makefile.in @@ -7,6 +7,7 @@ C_SRCS = \ ati_fragment_shader.c \ buffer.c \ context.c \ + cs.c \ device.c \ directx.c \ drawprim.c \ diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c new file mode 100644 index 00000000000..5f9bb565108 --- /dev/null +++ b/dlls/wined3d/cs.c @@ -0,0 +1,128 @@ +/* + * Copyright 2013 Henri Verbeet for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); + +#define WINED3D_INITIAL_CS_SIZE 4096 + +enum wined3d_cs_op +{ + WINED3D_CS_OP_PRESENT, +}; + +struct wined3d_cs_present +{ + enum wined3d_cs_op opcode; + HWND dst_window_override; + struct wined3d_swapchain *swapchain; + const RECT *src_rect; + const RECT *dst_rect; + const RGNDATA *dirty_region; + DWORD flags; +}; + +static void wined3d_cs_exec_present(const void *data) +{ + const struct wined3d_cs_present *op = data; + struct wined3d_swapchain *swapchain; + + swapchain = op->swapchain; + wined3d_swapchain_set_window(swapchain, op->dst_window_override); + + swapchain->swapchain_ops->swapchain_present(swapchain, + op->src_rect, op->dst_rect, op->dirty_region, op->flags); +} + +void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain, + const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override, + const RGNDATA *dirty_region, DWORD flags) +{ + struct wined3d_cs_present *op; + + op = cs->ops->require_space(cs, sizeof(*op)); + op->opcode = WINED3D_CS_OP_PRESENT; + op->dst_window_override = dst_window_override; + op->swapchain = swapchain; + op->src_rect = src_rect; + op->dst_rect = dst_rect; + op->dirty_region = dirty_region; + op->flags = flags; + + cs->ops->submit(cs); +} + +static void (* const wined3d_cs_op_handlers[])(const void *data) = +{ + /* WINED3D_CS_OP_PRESENT */ wined3d_cs_exec_present, +}; + +static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size) +{ + if (size > cs->data_size) + { + void *new_data; + + if (!(new_data = HeapReAlloc(GetProcessHeap(), 0, cs->data, cs->data_size * 2))) + return NULL; + + cs->data_size *= 2; + cs->data = new_data; + } + + return cs->data; +} + +static void wined3d_cs_st_submit(struct wined3d_cs *cs) +{ + enum wined3d_cs_op opcode = *(const enum wined3d_cs_op *)cs->data; + + wined3d_cs_op_handlers[opcode](cs->data); +} + +static const struct wined3d_cs_ops wined3d_cs_st_ops = +{ + wined3d_cs_st_require_space, + wined3d_cs_st_submit, +}; + +struct wined3d_cs *wined3d_cs_create(void) +{ + struct wined3d_cs *cs; + + if (!(cs = HeapAlloc(GetProcessHeap(), 0, sizeof(*cs)))) + return NULL; + + cs->ops = &wined3d_cs_st_ops; + + cs->data_size = WINED3D_INITIAL_CS_SIZE; + if (!(cs->data = HeapAlloc(GetProcessHeap(), 0, cs->data_size))) + { + HeapFree(GetProcessHeap(), 0, cs); + return NULL; + } + + return cs; +} + +void wined3d_cs_destroy(struct wined3d_cs *cs) +{ + HeapFree(GetProcessHeap(), 0, cs); +} diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 34ceaa77c0b..ff23770a4b7 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -485,6 +485,8 @@ ULONG CDECL wined3d_device_decref(struct wined3d_device *device) { UINT i; + wined3d_cs_destroy(device->cs); + if (device->recording && wined3d_stateblock_decref(device->recording)) FIXME("Something's still holding the recording stateblock.\n"); device->recording = NULL; @@ -4975,17 +4977,28 @@ HRESULT device_init(struct wined3d_device *device, struct wined3d *wined3d, if (FAILED(hr = state_init(&device->state, &device->fb, &adapter->d3d_info))) { ERR("Failed to initialize device state, hr %#x.\n", hr); - for (i = 0; i < sizeof(device->multistate_funcs) / sizeof(device->multistate_funcs[0]); ++i) - { - HeapFree(GetProcessHeap(), 0, device->multistate_funcs[i]); - } - wined3d_decref(device->wined3d); - return hr; + goto err; } state_init_default(&device->state, &adapter->gl_info); device->update_state = &device->state; + if (!(device->cs = wined3d_cs_create())) + { + WARN("Failed to create command stream.\n"); + state_cleanup(&device->state); + hr = E_FAIL; + goto err; + } + return WINED3D_OK; + +err: + for (i = 0; i < sizeof(device->multistate_funcs) / sizeof(device->multistate_funcs[0]); ++i) + { + HeapFree(GetProcessHeap(), 0, device->multistate_funcs[i]); + } + wined3d_decref(device->wined3d); + return hr; } diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 62827c92cf0..2bab9ed9961 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -149,9 +149,8 @@ HRESULT CDECL wined3d_swapchain_present(struct wined3d_swapchain *swapchain, return WINED3DERR_INVALIDCALL; } - wined3d_swapchain_set_window(swapchain, dst_window_override); - - swapchain->swapchain_ops->swapchain_present(swapchain, src_rect, dst_rect, dirty_region, flags); + wined3d_cs_emit_present(swapchain->device->cs, swapchain, src_rect, + dst_rect, dst_window_override, dirty_region, flags); return WINED3D_OK; } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 9b979dc21d8..251de34fe3d 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1939,6 +1939,9 @@ struct wined3d_device UINT dummy_texture_3d[MAX_COMBINED_SAMPLERS]; UINT dummy_texture_cube[MAX_COMBINED_SAMPLERS]; + /* Command stream */ + struct wined3d_cs *cs; + /* Context management */ struct wined3d_context **contexts; UINT context_count; @@ -2452,6 +2455,27 @@ HRESULT state_init(struct wined3d_state *state, struct wined3d_fb_state *fb, void state_init_default(struct wined3d_state *state, const struct wined3d_gl_info *gl_info) DECLSPEC_HIDDEN; void state_unbind_resources(struct wined3d_state *state) DECLSPEC_HIDDEN; +struct wined3d_cs_ops +{ + void *(*require_space)(struct wined3d_cs *cs, size_t size); + void (*submit)(struct wined3d_cs *cs); +}; + +struct wined3d_cs +{ + const struct wined3d_cs_ops *ops; + + size_t data_size; + void *data; +}; + +struct wined3d_cs *wined3d_cs_create(void) DECLSPEC_HIDDEN; +void wined3d_cs_destroy(struct wined3d_cs *cs) DECLSPEC_HIDDEN; + +void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain, + const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override, + const RGNDATA *dirty_region, DWORD flags) DECLSPEC_HIDDEN; + /* Direct3D terminology with little modifications. We do not have an issued state * because only the driver knows about it, but we have a created state because d3d * allows GetData on a created issue, but opengl doesn't