wined3d: Move FBO based color blits from IWineD3DSurfaceImpl_BltOverride() to wined3d_surface_blt().

This commit is contained in:
Henri Verbeet 2011-08-21 21:35:00 +02:00 committed by Alexandre Julliard
parent d063ff55e7
commit a04f0e9c78
1 changed files with 140 additions and 153 deletions

View File

@ -1171,6 +1171,127 @@ static void wined3d_surface_depth_blt_fbo(struct wined3d_device *device, struct
context_release(context);
}
/* Blit between surface locations. Onscreen on different swapchains is not supported.
* Depth / stencil is not supported. */
static void surface_blt_fbo(struct wined3d_device *device, const WINED3DTEXTUREFILTERTYPE filter,
struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
{
const struct wined3d_gl_info *gl_info;
struct wined3d_context *context;
RECT src_rect, dst_rect;
GLenum gl_filter;
GLenum buffer;
TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
TRACE("src_surface %p, src_location %s, src_rect %s,\n",
src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in));
TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in));
src_rect = *src_rect_in;
dst_rect = *dst_rect_in;
switch (filter)
{
case WINED3DTEXF_LINEAR:
gl_filter = GL_LINEAR;
break;
default:
FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
case WINED3DTEXF_NONE:
case WINED3DTEXF_POINT:
gl_filter = GL_NEAREST;
break;
}
if (src_location == SFLAG_INDRAWABLE && surface_is_offscreen(src_surface))
src_location = SFLAG_INTEXTURE;
if (dst_location == SFLAG_INDRAWABLE && surface_is_offscreen(dst_surface))
dst_location = SFLAG_INTEXTURE;
/* Make sure the locations are up-to-date. Loading the destination
* surface isn't required if the entire surface is overwritten. (And is
* in fact harmful if we're being called by surface_load_location() with
* the purpose of loading the destination surface.) */
surface_load_location(src_surface, src_location, NULL);
if (!surface_is_full_rect(dst_surface, &dst_rect))
surface_load_location(dst_surface, dst_location, NULL);
if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface);
else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface);
else context = context_acquire(device, NULL);
if (!context->valid)
{
context_release(context);
WARN("Invalid context, skipping blit.\n");
return;
}
gl_info = context->gl_info;
if (src_location == SFLAG_INDRAWABLE)
{
TRACE("Source surface %p is onscreen.\n", src_surface);
buffer = surface_get_gl_buffer(src_surface);
surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
}
else
{
TRACE("Source surface %p is offscreen.\n", src_surface);
buffer = GL_COLOR_ATTACHMENT0;
}
ENTER_GL();
context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
glReadBuffer(buffer);
checkGLcall("glReadBuffer()");
context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
LEAVE_GL();
if (dst_location == SFLAG_INDRAWABLE)
{
TRACE("Destination surface %p is onscreen.\n", dst_surface);
buffer = surface_get_gl_buffer(dst_surface);
surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
}
else
{
TRACE("Destination surface %p is offscreen.\n", dst_surface);
buffer = GL_COLOR_ATTACHMENT0;
}
ENTER_GL();
context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
context_set_draw_buffer(context, buffer);
context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
context_invalidate_state(context, STATE_FRAMEBUFFER);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
glDisable(GL_SCISSOR_TEST);
context_invalidate_state(context, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
checkGLcall("glBlitFramebuffer()");
LEAVE_GL();
if (wined3d_settings.strict_draw_ordering
|| (dst_location == SFLAG_INDRAWABLE
&& dst_surface->container.u.swapchain->front_buffer == dst_surface))
wglFlush();
context_release(context);
}
static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool, const struct wined3d_format *src_format,
const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool, const struct wined3d_format *dst_format)
@ -1545,6 +1666,23 @@ HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const REC
if (SUCCEEDED(surface_color_fill(dst_surface, &dst_rect, &color)))
return WINED3D_OK;
}
else
{
TRACE("Color blit.\n");
if (fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
&src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
&dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
{
TRACE("Using FBO blit.\n");
surface_blt_fbo(device, filter,
src_surface, SFLAG_INDRAWABLE, &src_rect,
dst_surface, SFLAG_INDRAWABLE, &dst_rect);
surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
return WINED3D_OK;
}
}
}
fallback:
@ -5045,127 +5183,6 @@ void surface_translate_drawable_coords(const struct wined3d_surface *surface, HW
rect->bottom = drawable_height - rect->bottom;
}
/* blit between surface locations. onscreen on different swapchains is not supported.
* depth / stencil is not supported. */
static void surface_blt_fbo(struct wined3d_device *device, const WINED3DTEXTUREFILTERTYPE filter,
struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
{
const struct wined3d_gl_info *gl_info;
struct wined3d_context *context;
RECT src_rect, dst_rect;
GLenum gl_filter;
GLenum buffer;
TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
TRACE("src_surface %p, src_location %s, src_rect %s,\n",
src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in));
TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in));
src_rect = *src_rect_in;
dst_rect = *dst_rect_in;
switch (filter)
{
case WINED3DTEXF_LINEAR:
gl_filter = GL_LINEAR;
break;
default:
FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
case WINED3DTEXF_NONE:
case WINED3DTEXF_POINT:
gl_filter = GL_NEAREST;
break;
}
if (src_location == SFLAG_INDRAWABLE && surface_is_offscreen(src_surface))
src_location = SFLAG_INTEXTURE;
if (dst_location == SFLAG_INDRAWABLE && surface_is_offscreen(dst_surface))
dst_location = SFLAG_INTEXTURE;
/* Make sure the locations are up-to-date. Loading the destination
* surface isn't required if the entire surface is overwritten. (And is
* in fact harmful if we're being called by surface_load_location() with
* the purpose of loading the destination surface.) */
surface_load_location(src_surface, src_location, NULL);
if (!surface_is_full_rect(dst_surface, &dst_rect))
surface_load_location(dst_surface, dst_location, NULL);
if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface);
else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface);
else context = context_acquire(device, NULL);
if (!context->valid)
{
context_release(context);
WARN("Invalid context, skipping blit.\n");
return;
}
gl_info = context->gl_info;
if (src_location == SFLAG_INDRAWABLE)
{
TRACE("Source surface %p is onscreen.\n", src_surface);
buffer = surface_get_gl_buffer(src_surface);
surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
}
else
{
TRACE("Source surface %p is offscreen.\n", src_surface);
buffer = GL_COLOR_ATTACHMENT0;
}
ENTER_GL();
context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
glReadBuffer(buffer);
checkGLcall("glReadBuffer()");
context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
LEAVE_GL();
if (dst_location == SFLAG_INDRAWABLE)
{
TRACE("Destination surface %p is onscreen.\n", dst_surface);
buffer = surface_get_gl_buffer(dst_surface);
surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
}
else
{
TRACE("Destination surface %p is offscreen.\n", dst_surface);
buffer = GL_COLOR_ATTACHMENT0;
}
ENTER_GL();
context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
context_set_draw_buffer(context, buffer);
context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
context_invalidate_state(context, STATE_FRAMEBUFFER);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
context_invalidate_state(context, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
glDisable(GL_SCISSOR_TEST);
context_invalidate_state(context, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
checkGLcall("glBlitFramebuffer()");
LEAVE_GL();
if (wined3d_settings.strict_draw_ordering
|| (dst_location == SFLAG_INDRAWABLE
&& dst_surface->container.u.swapchain->front_buffer == dst_surface))
wglFlush();
context_release(context);
}
static void surface_blt_to_drawable(struct wined3d_device *device,
WINED3DTEXTUREFILTERTYPE filter, BOOL color_key,
struct wined3d_surface *src_surface, const RECT *src_rect_in,
@ -5455,21 +5472,8 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surfa
* than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
* back buffer. This is slower than reading line per line, thus not used for flipping
* -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
* pixel by pixel
*
* If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
* FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
* backends. */
if (fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
{
surface_blt_fbo(device, Filter,
src_surface, SFLAG_INDRAWABLE, src_rect,
dst_surface, SFLAG_INDRAWABLE, dst_rect);
surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
}
else if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
* pixel by pixel. */
if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
|| dst_rect->bottom - dst_rect->top > src_surface->resource.height)
{
TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
@ -5500,23 +5504,6 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surfa
TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
if (!(flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
&& fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
src_rect, src_surface->resource.usage, src_surface->resource.pool,
src_surface->resource.format,
dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
dst_surface->resource.format))
{
TRACE("Using surface_blt_fbo.\n");
/* The source is always a texture, but never the currently active render target, and the texture
* contents are never upside down. */
surface_blt_fbo(device, Filter,
src_surface, SFLAG_INDRAWABLE, src_rect,
dst_surface, SFLAG_INDRAWABLE, dst_rect);
surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
return WINED3D_OK;
}
if (!(flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
&& arbfp_blit.blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
src_rect, src_surface->resource.usage, src_surface->resource.pool,