d3dx9: Introduce separate functions for restoring and capturing device state.

This commit is contained in:
Józef Kucia 2012-07-31 15:26:38 +02:00 committed by Alexandre Julliard
parent c51bf7b082
commit 8c4adc0617
1 changed files with 92 additions and 64 deletions

View File

@ -22,6 +22,89 @@
WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
struct device_state
{
DWORD num_render_targets;
IDirect3DSurface9 **render_targets;
IDirect3DSurface9 *depth_stencil;
D3DVIEWPORT9 viewport;
};
static HRESULT device_state_init(IDirect3DDevice9 *device, struct device_state *state)
{
HRESULT hr;
D3DCAPS9 caps;
unsigned int i;
hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
if (FAILED(hr)) return hr;
state->num_render_targets = caps.NumSimultaneousRTs;
state->render_targets = HeapAlloc(GetProcessHeap(), 0,
state->num_render_targets * sizeof(IDirect3DSurface9 *));
if (!state->render_targets)
return E_OUTOFMEMORY;
for (i = 0; i < state->num_render_targets; i++)
state->render_targets[i] = NULL;
state->depth_stencil = NULL;
return D3D_OK;
}
static void device_state_capture(IDirect3DDevice9 *device, struct device_state *state)
{
HRESULT hr;
unsigned int i;
IDirect3DDevice9_GetViewport(device, &state->viewport);
for (i = 0; i < state->num_render_targets; i++)
{
hr = IDirect3DDevice9_GetRenderTarget(device, i, &state->render_targets[i]);
if (FAILED(hr)) state->render_targets[i] = NULL;
}
hr = IDirect3DDevice9_GetDepthStencilSurface(device, &state->depth_stencil);
if (FAILED(hr)) state->depth_stencil = NULL;
}
static void device_state_restore(IDirect3DDevice9 *device, struct device_state *state)
{
unsigned int i;
for (i = 0; i < state->num_render_targets; i++)
{
IDirect3DDevice9_SetRenderTarget(device, i, state->render_targets[i]);
if (state->render_targets[i])
IDirect3DSurface9_Release(state->render_targets[i]);
state->render_targets[i] = NULL;
}
IDirect3DDevice9_SetDepthStencilSurface(device, state->depth_stencil);
if (state->depth_stencil)
{
IDirect3DSurface9_Release(state->depth_stencil);
state->depth_stencil = NULL;
}
IDirect3DDevice9_SetViewport(device, &state->viewport);
}
static void device_state_release(struct device_state *state)
{
unsigned int i;
for (i = 0; i < state->num_render_targets; i++)
{
if (state->render_targets[i])
IDirect3DSurface9_Release(state->render_targets[i]);
}
HeapFree(GetProcessHeap(), 0, state->render_targets);
if (state->depth_stencil) IDirect3DSurface9_Release(state->depth_stencil);
}
struct render_to_surface
{
ID3DXRenderToSurface ID3DXRenderToSurface_iface;
@ -35,10 +118,7 @@ struct render_to_surface
IDirect3DSurface9 *render_target;
IDirect3DSurface9 *depth_stencil;
DWORD num_render_targets;
D3DVIEWPORT9 previous_viewport;
IDirect3DSurface9 **previous_render_targets;
IDirect3DSurface9 *previous_depth_stencil;
struct device_state previous_state;
};
static inline struct render_to_surface *impl_from_ID3DXRenderToSurface(ID3DXRenderToSurface *iface)
@ -46,28 +126,6 @@ static inline struct render_to_surface *impl_from_ID3DXRenderToSurface(ID3DXRend
return CONTAINING_RECORD(iface, struct render_to_surface, ID3DXRenderToSurface_iface);
}
static void restore_previous_device_state(struct render_to_surface *render)
{
unsigned int i;
for (i = 0; i < render->num_render_targets; i++)
{
IDirect3DDevice9_SetRenderTarget(render->device, i, render->previous_render_targets[i]);
if (render->previous_render_targets[i])
IDirect3DSurface9_Release(render->previous_render_targets[i]);
render->previous_render_targets[i] = NULL;
}
IDirect3DDevice9_SetDepthStencilSurface(render->device, render->previous_depth_stencil);
if (render->previous_depth_stencil)
{
IDirect3DSurface9_Release(render->previous_depth_stencil);
render->previous_depth_stencil = NULL;
}
IDirect3DDevice9_SetViewport(render->device, &render->previous_viewport);
}
static HRESULT WINAPI D3DXRenderToSurface_QueryInterface(ID3DXRenderToSurface *iface,
REFIID riid,
void **out)
@ -102,7 +160,6 @@ static ULONG WINAPI D3DXRenderToSurface_Release(ID3DXRenderToSurface *iface)
{
struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
ULONG ref = InterlockedDecrement(&render->ref);
unsigned int i;
TRACE("%p decreasing refcount to %u\n", iface, ref);
@ -113,15 +170,7 @@ static ULONG WINAPI D3DXRenderToSurface_Release(ID3DXRenderToSurface *iface)
if (render->render_target) IDirect3DSurface9_Release(render->render_target);
if (render->depth_stencil) IDirect3DSurface9_Release(render->depth_stencil);
for (i = 0; i < render->num_render_targets; i++)
{
if (render->previous_render_targets[i])
IDirect3DSurface9_Release(render->previous_render_targets[i]);
}
HeapFree(GetProcessHeap(), 0, render->previous_render_targets);
if (render->previous_depth_stencil) IDirect3DSurface9_Release(render->previous_depth_stencil);
device_state_release(&render->previous_state);
IDirect3DDevice9_Release(render->device);
@ -196,20 +245,10 @@ static HRESULT WINAPI D3DXRenderToSurface_BeginScene(ID3DXRenderToSurface *iface
device = render->device;
/* save device state */
IDirect3DDevice9_GetViewport(device, &render->previous_viewport);
for (i = 0; i < render->num_render_targets; i++)
{
hr = IDirect3DDevice9_GetRenderTarget(device, i, &render->previous_render_targets[i]);
if (FAILED(hr)) render->previous_render_targets[i] = NULL;
}
hr = IDirect3DDevice9_GetDepthStencilSurface(device, &render->previous_depth_stencil);
if (FAILED(hr)) render->previous_depth_stencil = NULL;
device_state_capture(device, &render->previous_state);
/* prepare for rendering to surface */
for (i = 1; i < render->num_render_targets; i++)
for (i = 1; i < render->previous_state.num_render_targets; i++)
IDirect3DDevice9_SetRenderTarget(device, i, NULL);
if (surface_desc.Usage & D3DUSAGE_RENDERTARGET)
@ -249,7 +288,7 @@ static HRESULT WINAPI D3DXRenderToSurface_BeginScene(ID3DXRenderToSurface *iface
return IDirect3DDevice9_BeginScene(device);
cleanup:
restore_previous_device_state(render);
device_state_restore(device, &render->previous_state);
if (render->dst_surface) IDirect3DSurface9_Release(render->dst_surface);
render->dst_surface = NULL;
@ -282,7 +321,7 @@ static HRESULT WINAPI D3DXRenderToSurface_EndScene(ID3DXRenderToSurface *iface,
if (FAILED(hr)) ERR("Copying render target data to surface failed %#x\n", hr);
}
restore_previous_device_state(render);
device_state_restore(render->device, &render->previous_state);
/* release resources */
if (render->render_target)
@ -339,18 +378,13 @@ HRESULT WINAPI D3DXCreateRenderToSurface(IDirect3DDevice9 *device,
ID3DXRenderToSurface **out)
{
HRESULT hr;
D3DCAPS9 caps;
struct render_to_surface *render;
unsigned int i;
TRACE("(%p, %u, %u, %#x, %d, %#x, %p)\n", device, width, height, format,
depth_stencil, depth_stencil_format, out);
if (!device || !out) return D3DERR_INVALIDCALL;
hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
if (FAILED(hr)) return hr;
render = HeapAlloc(GetProcessHeap(), 0, sizeof(struct render_to_surface));
if (!render) return E_OUTOFMEMORY;
@ -367,19 +401,13 @@ HRESULT WINAPI D3DXCreateRenderToSurface(IDirect3DDevice9 *device,
render->render_target = NULL;
render->depth_stencil = NULL;
render->num_render_targets = caps.NumSimultaneousRTs;
render->previous_render_targets = HeapAlloc(GetProcessHeap(), 0,
render->num_render_targets * sizeof(IDirect3DSurface9 *));
if (!render->previous_render_targets)
hr = device_state_init(device, &render->previous_state);
if (FAILED(hr))
{
HeapFree(GetProcessHeap(), 0, render);
return E_OUTOFMEMORY;
return hr;
}
for (i = 0; i < render->num_render_targets; i++)
render->previous_render_targets[i] = NULL;
render->previous_depth_stencil = NULL;
IDirect3DDevice9_AddRef(device);
render->device = device;