Commit dc918d43 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

wined3d: Use FBOs when the onscreen depth stencil format isn't suitable.

This allows proper support of float depth buffers when rendering to onscreen surfaces.
parent 19b6f5ca
...@@ -1929,6 +1929,57 @@ void context_set_draw_buffer(struct wined3d_context *context, GLenum buffer) ...@@ -1929,6 +1929,57 @@ void context_set_draw_buffer(struct wined3d_context *context, GLenum buffer)
context->draw_buffer_dirty = TRUE; context->draw_buffer_dirty = TRUE;
} }
static inline void context_set_render_offscreen(struct wined3d_context *context, const struct StateEntry *StateTable,
BOOL offscreen)
{
if (context->render_offscreen == offscreen) return;
Context_MarkStateDirty(context, STATE_TRANSFORM(WINED3DTS_PROJECTION), StateTable);
Context_MarkStateDirty(context, STATE_VDECL, StateTable);
Context_MarkStateDirty(context, STATE_VIEWPORT, StateTable);
Context_MarkStateDirty(context, STATE_SCISSORRECT, StateTable);
Context_MarkStateDirty(context, STATE_FRONTFACE, StateTable);
context->render_offscreen = offscreen;
}
static BOOL match_depth_stencil_format(const struct wined3d_format_desc *existing,
const struct wined3d_format_desc *required)
{
short existing_depth, existing_stencil, required_depth, required_stencil;
if(existing == required) return TRUE;
if((existing->Flags & WINED3DFMT_FLAG_FLOAT) != (required->Flags & WINED3DFMT_FLAG_FLOAT)) return FALSE;
getDepthStencilBits(existing, &existing_depth, &existing_stencil);
getDepthStencilBits(required, &required_depth, &required_stencil);
if(existing_depth < required_depth) return FALSE;
/* If stencil bits are used the exact amount is required - otherwise wrapping
* won't work correctly */
if(required_stencil && required_stencil != existing_stencil) return FALSE;
return TRUE;
}
/* The caller provides a context */
static void context_validate_onscreen_formats(IWineD3DDeviceImpl *device, struct wined3d_context *context)
{
/* Onscreen surfaces are always in a swapchain */
IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) device->stencilBufferTarget;
IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) ((IWineD3DSurfaceImpl *)context->current_rt)->container;
if (!depth_stencil) return;
if (match_depth_stencil_format(swapchain->ds_format, depth_stencil->resource.format_desc)) return;
/* TODO: If the requested format would satisfy the needs of the existing one(reverse match),
* or no onscreen depth buffer was created, the OpenGL drawable could be changed to the new
* format. */
WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
/* The currently active context is the necessary context to access the swapchain's onscreen buffers */
IWineD3DSurface_LoadLocation(context->current_rt, SFLAG_INTEXTURE, NULL);
swapchain->render_to_fbo = TRUE;
context_set_render_offscreen(context, device->StateTable, TRUE);
}
/* Context activation is done by the caller. */ /* Context activation is done by the caller. */
static void context_apply_state(struct wined3d_context *context, IWineD3DDeviceImpl *device, enum ContextUsage usage) static void context_apply_state(struct wined3d_context *context, IWineD3DDeviceImpl *device, enum ContextUsage usage)
{ {
...@@ -1939,6 +1990,7 @@ static void context_apply_state(struct wined3d_context *context, IWineD3DDeviceI ...@@ -1939,6 +1990,7 @@ static void context_apply_state(struct wined3d_context *context, IWineD3DDeviceI
case CTXUSAGE_CLEAR: case CTXUSAGE_CLEAR:
case CTXUSAGE_DRAWPRIM: case CTXUSAGE_DRAWPRIM:
if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) { if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
if (!context->render_offscreen) context_validate_onscreen_formats(device, context);
ENTER_GL(); ENTER_GL();
context_apply_fbo_state(context); context_apply_fbo_state(context);
LEAVE_GL(); LEAVE_GL();
...@@ -1951,6 +2003,7 @@ static void context_apply_state(struct wined3d_context *context, IWineD3DDeviceI ...@@ -1951,6 +2003,7 @@ static void context_apply_state(struct wined3d_context *context, IWineD3DDeviceI
case CTXUSAGE_BLIT: case CTXUSAGE_BLIT:
if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) { if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
if (!context->render_offscreen) context_validate_onscreen_formats(device, context);
if (context->render_offscreen) if (context->render_offscreen)
{ {
FIXME("Activating for CTXUSAGE_BLIT for an offscreen target with ORM_FBO. This should be avoided.\n"); FIXME("Activating for CTXUSAGE_BLIT for an offscreen target with ORM_FBO. This should be avoided.\n");
...@@ -2043,21 +2096,14 @@ static void context_apply_state(struct wined3d_context *context, IWineD3DDeviceI ...@@ -2043,21 +2096,14 @@ static void context_apply_state(struct wined3d_context *context, IWineD3DDeviceI
static void context_setup_target(IWineD3DDeviceImpl *device, struct wined3d_context *context, IWineD3DSurface *target) static void context_setup_target(IWineD3DDeviceImpl *device, struct wined3d_context *context, IWineD3DSurface *target)
{ {
BOOL old_render_offscreen = context->render_offscreen; BOOL old_render_offscreen = context->render_offscreen, render_offscreen;
const struct StateEntry *StateTable = device->StateTable; const struct StateEntry *StateTable = device->StateTable;
if (!target) return; if (!target) return;
else if (context->current_rt == target) return; else if (context->current_rt == target) return;
context->render_offscreen = surface_is_offscreen(target); render_offscreen = surface_is_offscreen(target);
if (context->render_offscreen != old_render_offscreen) context_set_render_offscreen(context, StateTable, render_offscreen);
{
Context_MarkStateDirty(context, STATE_TRANSFORM(WINED3DTS_PROJECTION), StateTable);
Context_MarkStateDirty(context, STATE_VDECL, StateTable);
Context_MarkStateDirty(context, STATE_VIEWPORT, StateTable);
Context_MarkStateDirty(context, STATE_SCISSORRECT, StateTable);
Context_MarkStateDirty(context, STATE_FRONTFACE, StateTable);
}
/* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers /* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers
* the alpha blend state changes with different render target formats. */ * the alpha blend state changes with different render target formats. */
......
...@@ -811,7 +811,7 @@ HRESULT swapchain_init(IWineD3DSwapChainImpl *swapchain, WINED3DSURFTYPE surface ...@@ -811,7 +811,7 @@ HRESULT swapchain_init(IWineD3DSwapChainImpl *swapchain, WINED3DSURFTYPE surface
if (!present_parameters->EnableAutoDepthStencil if (!present_parameters->EnableAutoDepthStencil
|| swapchain->presentParms.AutoDepthStencilFormat != WINED3DFMT_D24_UNORM_S8_UINT) || swapchain->presentParms.AutoDepthStencilFormat != WINED3DFMT_D24_UNORM_S8_UINT)
{ {
FIXME("Add OpenGL context recreation support to SetDepthStencilSurface\n"); FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n");
} }
swapchain->ds_format = getFormatDescEntry(WINED3DFMT_D24_UNORM_S8_UINT, gl_info); swapchain->ds_format = getFormatDescEntry(WINED3DFMT_D24_UNORM_S8_UINT, gl_info);
swapchain->context[0] = context_create(swapchain, (IWineD3DSurfaceImpl *)swapchain->frontBuffer, swapchain->context[0] = context_create(swapchain, (IWineD3DSurfaceImpl *)swapchain->frontBuffer,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment