Commit 6ec2110c authored by Henri Verbeet's avatar Henri Verbeet Committed by Alexandre Julliard

wined3d: Move the FBO blitter to texture.c.

parent 445d37f5
......@@ -57,265 +57,6 @@ static BOOL texture2d_is_full_rect(const struct wined3d_texture *texture, unsign
return TRUE;
}
static void texture2d_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_context *context,
struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, DWORD src_location,
const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
DWORD dst_location, const RECT *dst_rect)
{
struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
const struct wined3d_gl_info *gl_info = context_gl->gl_info;
DWORD src_mask, dst_mask;
GLbitfield gl_mask;
TRACE("device %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
"dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n", device,
src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect),
dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
src_mask = src_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
dst_mask = dst_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
if (src_mask != dst_mask)
{
ERR("Incompatible formats %s and %s.\n",
debug_d3dformat(src_texture->resource.format->id),
debug_d3dformat(dst_texture->resource.format->id));
return;
}
if (!src_mask)
{
ERR("Not a depth / stencil format: %s.\n",
debug_d3dformat(src_texture->resource.format->id));
return;
}
gl_mask = 0;
if (src_mask & WINED3DFMT_FLAG_DEPTH)
gl_mask |= GL_DEPTH_BUFFER_BIT;
if (src_mask & WINED3DFMT_FLAG_STENCIL)
gl_mask |= GL_STENCIL_BUFFER_BIT;
/* Make sure the locations are up-to-date. Loading the destination
* surface isn't required if the entire surface is overwritten. */
wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
else
wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_READ_FRAMEBUFFER, NULL, 0,
&src_texture->resource, src_sub_resource_idx, src_location);
wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER);
wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_DRAW_FRAMEBUFFER, NULL, 0,
&dst_texture->resource, dst_sub_resource_idx, dst_location);
wined3d_context_gl_set_draw_buffer(context_gl, GL_NONE);
wined3d_context_gl_check_fbo_status(context_gl, GL_DRAW_FRAMEBUFFER);
context_invalidate_state(context, STATE_FRAMEBUFFER);
if (gl_mask & GL_DEPTH_BUFFER_BIT)
{
gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
}
if (gl_mask & GL_STENCIL_BUFFER_BIT)
{
if (gl_info->supported[EXT_STENCIL_TWO_SIDE])
{
gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
}
gl_info->gl_ops.gl.p_glStencilMask(~0U);
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
}
gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
context_invalidate_state(context, STATE_RASTERIZER);
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_mask, GL_NEAREST);
checkGLcall("glBlitFramebuffer()");
}
/* Blit between surface locations. Onscreen on different swapchains is not supported.
* Depth / stencil is not supported. Context activation is done by the caller. */
void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_context *context,
enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture,
unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect,
struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location,
const RECT *dst_rect)
{
struct wined3d_texture *required_texture, *restore_texture;
const struct wined3d_gl_info *gl_info;
struct wined3d_context_gl *context_gl;
unsigned int restore_idx;
BOOL scaled_resolve;
GLenum gl_filter;
GLenum buffer;
RECT s, d;
TRACE("device %p, context %p, filter %s, src_texture %p, src_sub_resource_idx %u, src_location %s, "
"src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n",
device, context, debug_d3dtexturefiltertype(filter), src_texture, src_sub_resource_idx,
wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect), dst_texture,
dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
scaled_resolve = wined3d_texture_gl_is_multisample_location(wined3d_texture_gl(src_texture), src_location)
&& (abs(src_rect->bottom - src_rect->top) != abs(dst_rect->bottom - dst_rect->top)
|| abs(src_rect->right - src_rect->left) != abs(dst_rect->right - dst_rect->left));
if (filter == WINED3D_TEXF_LINEAR)
gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_NICEST_EXT : GL_LINEAR;
else
gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_FASTEST_EXT : GL_NEAREST;
/* 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.) */
wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
else
wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
/* Acquire a context for the front-buffer, even though we may be blitting
* to/from a back-buffer. Since context_acquire() doesn't take the
* resource location into account, it may consider the back-buffer to be
* offscreen. */
if (src_location == WINED3D_LOCATION_DRAWABLE)
required_texture = src_texture->swapchain->front_buffer;
else if (dst_location == WINED3D_LOCATION_DRAWABLE)
required_texture = dst_texture->swapchain->front_buffer;
else
required_texture = NULL;
restore_texture = context->current_rt.texture;
restore_idx = context->current_rt.sub_resource_idx;
if (restore_texture != required_texture)
context = context_acquire(device, required_texture, 0);
else
restore_texture = NULL;
context_gl = wined3d_context_gl(context);
if (!context_gl->valid)
{
context_release(context);
WARN("Invalid context, skipping blit.\n");
return;
}
gl_info = context_gl->gl_info;
if (src_location == WINED3D_LOCATION_DRAWABLE)
{
TRACE("Source texture %p is onscreen.\n", src_texture);
buffer = wined3d_texture_get_gl_buffer(src_texture);
s = *src_rect;
wined3d_texture_translate_drawable_coords(src_texture, context_gl->window, &s);
src_rect = &s;
}
else
{
TRACE("Source texture %p is offscreen.\n", src_texture);
buffer = GL_COLOR_ATTACHMENT0;
}
wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_READ_FRAMEBUFFER,
&src_texture->resource, src_sub_resource_idx, NULL, 0, src_location);
gl_info->gl_ops.gl.p_glReadBuffer(buffer);
checkGLcall("glReadBuffer()");
wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER);
if (dst_location == WINED3D_LOCATION_DRAWABLE)
{
TRACE("Destination texture %p is onscreen.\n", dst_texture);
buffer = wined3d_texture_get_gl_buffer(dst_texture);
d = *dst_rect;
wined3d_texture_translate_drawable_coords(dst_texture, context_gl->window, &d);
dst_rect = &d;
}
else
{
TRACE("Destination texture %p is offscreen.\n", dst_texture);
buffer = GL_COLOR_ATTACHMENT0;
}
wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_DRAW_FRAMEBUFFER,
&dst_texture->resource, dst_sub_resource_idx, NULL, 0, dst_location);
wined3d_context_gl_set_draw_buffer(context_gl, buffer);
wined3d_context_gl_check_fbo_status(context_gl, GL_DRAW_FRAMEBUFFER);
context_invalidate_state(context, STATE_FRAMEBUFFER);
gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
context_invalidate_state(context, STATE_BLEND);
gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
context_invalidate_state(context, STATE_RASTERIZER);
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()");
if (dst_location == WINED3D_LOCATION_DRAWABLE && dst_texture->swapchain->front_buffer == dst_texture)
gl_info->gl_ops.gl.p_glFlush();
if (restore_texture)
context_restore(context, restore_texture, restore_idx);
}
BOOL fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct wined3d_gl_info *gl_info,
const struct wined3d_resource *src_resource, DWORD src_location,
const struct wined3d_resource *dst_resource, DWORD dst_location)
{
const struct wined3d_format *src_format = src_resource->format;
const struct wined3d_format *dst_format = dst_resource->format;
if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
return FALSE;
/* Source and/or destination need to be on the GL side */
if (!(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU))
return FALSE;
if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D)
return FALSE;
switch (blit_op)
{
case WINED3D_BLIT_OP_COLOR_BLIT:
if (!((src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
|| (src_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)))
return FALSE;
if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
|| (dst_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)))
return FALSE;
if ((src_format->id != dst_format->id || dst_location == WINED3D_LOCATION_DRAWABLE)
&& (!is_identity_fixup(src_format->color_fixup) || !is_identity_fixup(dst_format->color_fixup)))
return FALSE;
break;
case WINED3D_BLIT_OP_DEPTH_BLIT:
if (!(src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
return FALSE;
if (!(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
return FALSE;
/* Accept pure swizzle fixups for depth formats. In general we
* ignore the stencil component (if present) at the moment and the
* swizzle is not relevant with just the depth component. */
if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup)
|| is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup))
return FALSE;
break;
default:
return FALSE;
}
return TRUE;
}
/* See also float_16_to_32() in wined3d_private.h */
static inline unsigned short float_32_to_16(const float *in)
{
......@@ -860,117 +601,6 @@ void texture2d_load_fb_texture(struct wined3d_texture_gl *texture_gl,
}
/* Context activation is done by the caller. */
static void fbo_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
{
struct wined3d_blitter *next;
if ((next = blitter->next))
next->ops->blitter_destroy(next, context);
heap_free(blitter);
}
static void fbo_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
{
struct wined3d_blitter *next;
if ((next = blitter->next))
next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
clear_rects, draw_rect, flags, colour, depth, stencil);
}
static DWORD fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter)
{
struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
struct wined3d_resource *src_resource, *dst_resource;
enum wined3d_blit_op blit_op = op;
struct wined3d_device *device;
struct wined3d_blitter *next;
TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
"dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, colour_key %p, filter %s.\n",
blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location),
wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter));
src_resource = &src_texture->resource;
dst_resource = &dst_texture->resource;
device = dst_resource->device;
if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_resource->format->id == src_resource->format->id)
{
if (dst_resource->format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
else
blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
}
if (!fbo_blitter_supported(blit_op, context_gl->gl_info,
src_resource, src_location, dst_resource, dst_location))
{
if (!(next = blitter->next))
{
ERR("No blitter to handle blit op %#x.\n", op);
return dst_location;
}
TRACE("Forwarding to blitter %p.\n", next);
return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter);
}
if (blit_op == WINED3D_BLIT_OP_COLOR_BLIT)
{
TRACE("Colour blit.\n");
texture2d_blt_fbo(device, context, filter, src_texture, src_sub_resource_idx, src_location,
src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
return dst_location;
}
if (blit_op == WINED3D_BLIT_OP_DEPTH_BLIT)
{
TRACE("Depth/stencil blit.\n");
texture2d_depth_blt_fbo(device, context, src_texture, src_sub_resource_idx, src_location,
src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
return dst_location;
}
ERR("This blitter does not implement blit op %#x.\n", blit_op);
return dst_location;
}
static const struct wined3d_blitter_ops fbo_blitter_ops =
{
fbo_blitter_destroy,
fbo_blitter_clear,
fbo_blitter_blit,
};
void wined3d_fbo_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
{
struct wined3d_blitter *blitter;
if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
return;
if (!(blitter = heap_alloc(sizeof(*blitter))))
return;
TRACE("Created blitter %p.\n", blitter);
blitter->ops = &fbo_blitter_ops;
blitter->next = *next;
*next = blitter;
}
/* Context activation is done by the caller. */
static void raw_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
{
struct wined3d_blitter *next;
......
......@@ -48,6 +48,19 @@ struct wined3d_rect_f
float b;
};
static bool texture2d_is_full_rect(const struct wined3d_texture *texture, unsigned int level, const RECT *r)
{
unsigned int t;
t = wined3d_texture_get_level_width(texture, level);
if ((r->left && r->right) || abs(r->right - r->left) != t)
return false;
t = wined3d_texture_get_level_height(texture, level);
if ((r->top && r->bottom) || abs(r->bottom - r->top) != t)
return false;
return true;
}
static BOOL wined3d_texture_use_pbo(const struct wined3d_texture *texture, const struct wined3d_gl_info *gl_info)
{
if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT]
......@@ -265,6 +278,265 @@ void texture2d_get_blt_info(const struct wined3d_texture_gl *texture_gl,
}
}
static bool fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct wined3d_gl_info *gl_info,
const struct wined3d_resource *src_resource, DWORD src_location,
const struct wined3d_resource *dst_resource, DWORD dst_location)
{
const struct wined3d_format *src_format = src_resource->format;
const struct wined3d_format *dst_format = dst_resource->format;
if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
return false;
/* Source and/or destination need to be on the GL side. */
if (!(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU))
return false;
if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D)
return false;
switch (blit_op)
{
case WINED3D_BLIT_OP_COLOR_BLIT:
if (!((src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
|| (src_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)))
return false;
if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
|| (dst_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)))
return false;
if ((src_format->id != dst_format->id || dst_location == WINED3D_LOCATION_DRAWABLE)
&& (!is_identity_fixup(src_format->color_fixup) || !is_identity_fixup(dst_format->color_fixup)))
return false;
break;
case WINED3D_BLIT_OP_DEPTH_BLIT:
if (!(src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
return false;
if (!(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
return false;
/* Accept pure swizzle fixups for depth formats. In general we
* ignore the stencil component (if present) at the moment and the
* swizzle is not relevant with just the depth component. */
if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup)
|| is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup))
return false;
break;
default:
return false;
}
return true;
}
/* Blit between surface locations. Onscreen on different swapchains is not supported.
* Depth / stencil is not supported. Context activation is done by the caller. */
static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_context *context,
enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture,
unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect,
struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location,
const RECT *dst_rect)
{
struct wined3d_texture *required_texture, *restore_texture;
const struct wined3d_gl_info *gl_info;
struct wined3d_context_gl *context_gl;
unsigned int restore_idx;
bool scaled_resolve;
GLenum gl_filter;
GLenum buffer;
RECT s, d;
TRACE("device %p, context %p, filter %s, src_texture %p, src_sub_resource_idx %u, src_location %s, "
"src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n",
device, context, debug_d3dtexturefiltertype(filter), src_texture, src_sub_resource_idx,
wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect), dst_texture,
dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
scaled_resolve = wined3d_texture_gl_is_multisample_location(wined3d_texture_gl(src_texture), src_location)
&& (abs(src_rect->bottom - src_rect->top) != abs(dst_rect->bottom - dst_rect->top)
|| abs(src_rect->right - src_rect->left) != abs(dst_rect->right - dst_rect->left));
if (filter == WINED3D_TEXF_LINEAR)
gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_NICEST_EXT : GL_LINEAR;
else
gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_FASTEST_EXT : GL_NEAREST;
/* 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.) */
wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
else
wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
/* Acquire a context for the front-buffer, even though we may be blitting
* to/from a back-buffer. Since context_acquire() doesn't take the
* resource location into account, it may consider the back-buffer to be
* offscreen. */
if (src_location == WINED3D_LOCATION_DRAWABLE)
required_texture = src_texture->swapchain->front_buffer;
else if (dst_location == WINED3D_LOCATION_DRAWABLE)
required_texture = dst_texture->swapchain->front_buffer;
else
required_texture = NULL;
restore_texture = context->current_rt.texture;
restore_idx = context->current_rt.sub_resource_idx;
if (restore_texture != required_texture)
context = context_acquire(device, required_texture, 0);
else
restore_texture = NULL;
context_gl = wined3d_context_gl(context);
if (!context_gl->valid)
{
context_release(context);
WARN("Invalid context, skipping blit.\n");
return;
}
gl_info = context_gl->gl_info;
if (src_location == WINED3D_LOCATION_DRAWABLE)
{
TRACE("Source texture %p is onscreen.\n", src_texture);
buffer = wined3d_texture_get_gl_buffer(src_texture);
s = *src_rect;
wined3d_texture_translate_drawable_coords(src_texture, context_gl->window, &s);
src_rect = &s;
}
else
{
TRACE("Source texture %p is offscreen.\n", src_texture);
buffer = GL_COLOR_ATTACHMENT0;
}
wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_READ_FRAMEBUFFER,
&src_texture->resource, src_sub_resource_idx, NULL, 0, src_location);
gl_info->gl_ops.gl.p_glReadBuffer(buffer);
checkGLcall("glReadBuffer()");
wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER);
if (dst_location == WINED3D_LOCATION_DRAWABLE)
{
TRACE("Destination texture %p is onscreen.\n", dst_texture);
buffer = wined3d_texture_get_gl_buffer(dst_texture);
d = *dst_rect;
wined3d_texture_translate_drawable_coords(dst_texture, context_gl->window, &d);
dst_rect = &d;
}
else
{
TRACE("Destination texture %p is offscreen.\n", dst_texture);
buffer = GL_COLOR_ATTACHMENT0;
}
wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_DRAW_FRAMEBUFFER,
&dst_texture->resource, dst_sub_resource_idx, NULL, 0, dst_location);
wined3d_context_gl_set_draw_buffer(context_gl, buffer);
wined3d_context_gl_check_fbo_status(context_gl, GL_DRAW_FRAMEBUFFER);
context_invalidate_state(context, STATE_FRAMEBUFFER);
gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
context_invalidate_state(context, STATE_BLEND);
gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
context_invalidate_state(context, STATE_RASTERIZER);
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()");
if (dst_location == WINED3D_LOCATION_DRAWABLE && dst_texture->swapchain->front_buffer == dst_texture)
gl_info->gl_ops.gl.p_glFlush();
if (restore_texture)
context_restore(context, restore_texture, restore_idx);
}
static void texture2d_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_context *context,
struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, DWORD src_location,
const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
DWORD dst_location, const RECT *dst_rect)
{
struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
const struct wined3d_gl_info *gl_info = context_gl->gl_info;
DWORD src_mask, dst_mask;
GLbitfield gl_mask;
TRACE("device %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
"dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n", device,
src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect),
dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
src_mask = src_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
dst_mask = dst_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
if (src_mask != dst_mask)
{
ERR("Incompatible formats %s and %s.\n",
debug_d3dformat(src_texture->resource.format->id),
debug_d3dformat(dst_texture->resource.format->id));
return;
}
if (!src_mask)
{
ERR("Not a depth / stencil format: %s.\n",
debug_d3dformat(src_texture->resource.format->id));
return;
}
gl_mask = 0;
if (src_mask & WINED3DFMT_FLAG_DEPTH)
gl_mask |= GL_DEPTH_BUFFER_BIT;
if (src_mask & WINED3DFMT_FLAG_STENCIL)
gl_mask |= GL_STENCIL_BUFFER_BIT;
/* Make sure the locations are up-to-date. Loading the destination
* surface isn't required if the entire surface is overwritten. */
wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
else
wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_READ_FRAMEBUFFER, NULL, 0,
&src_texture->resource, src_sub_resource_idx, src_location);
wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER);
wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_DRAW_FRAMEBUFFER, NULL, 0,
&dst_texture->resource, dst_sub_resource_idx, dst_location);
wined3d_context_gl_set_draw_buffer(context_gl, GL_NONE);
wined3d_context_gl_check_fbo_status(context_gl, GL_DRAW_FRAMEBUFFER);
context_invalidate_state(context, STATE_FRAMEBUFFER);
if (gl_mask & GL_DEPTH_BUFFER_BIT)
{
gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
}
if (gl_mask & GL_STENCIL_BUFFER_BIT)
{
if (gl_info->supported[EXT_STENCIL_TWO_SIDE])
{
gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
}
gl_info->gl_ops.gl.p_glStencilMask(~0U);
context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
}
gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
context_invalidate_state(context, STATE_RASTERIZER);
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_mask, GL_NEAREST);
checkGLcall("glBlitFramebuffer()");
}
static void wined3d_texture_evict_sysmem(struct wined3d_texture *texture)
{
struct wined3d_texture_sub_resource *sub_resource;
......@@ -5210,3 +5482,113 @@ void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wine
blitter->next = *next;
*next = blitter;
}
static void fbo_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
{
struct wined3d_blitter *next;
if ((next = blitter->next))
next->ops->blitter_destroy(next, context);
heap_free(blitter);
}
static void fbo_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
{
struct wined3d_blitter *next;
if ((next = blitter->next))
next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
clear_rects, draw_rect, flags, colour, depth, stencil);
}
static DWORD fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter)
{
struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
struct wined3d_resource *src_resource, *dst_resource;
enum wined3d_blit_op blit_op = op;
struct wined3d_device *device;
struct wined3d_blitter *next;
TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
"dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, colour_key %p, filter %s.\n",
blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location),
wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter));
src_resource = &src_texture->resource;
dst_resource = &dst_texture->resource;
device = dst_resource->device;
if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_resource->format->id == src_resource->format->id)
{
if (dst_resource->format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
else
blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
}
if (!fbo_blitter_supported(blit_op, context_gl->gl_info,
src_resource, src_location, dst_resource, dst_location))
{
if (!(next = blitter->next))
{
ERR("No blitter to handle blit op %#x.\n", op);
return dst_location;
}
TRACE("Forwarding to blitter %p.\n", next);
return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter);
}
if (blit_op == WINED3D_BLIT_OP_COLOR_BLIT)
{
TRACE("Colour blit.\n");
texture2d_blt_fbo(device, context, filter, src_texture, src_sub_resource_idx, src_location,
src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
return dst_location;
}
if (blit_op == WINED3D_BLIT_OP_DEPTH_BLIT)
{
TRACE("Depth/stencil blit.\n");
texture2d_depth_blt_fbo(device, context, src_texture, src_sub_resource_idx, src_location,
src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
return dst_location;
}
ERR("This blitter does not implement blit op %#x.\n", blit_op);
return dst_location;
}
static const struct wined3d_blitter_ops fbo_blitter_ops =
{
fbo_blitter_destroy,
fbo_blitter_clear,
fbo_blitter_blit,
};
void wined3d_fbo_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
{
struct wined3d_blitter *blitter;
if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
return;
if (!(blitter = heap_alloc(sizeof(*blitter))))
return;
TRACE("Created blitter %p.\n", blitter);
blitter->ops = &fbo_blitter_ops;
blitter->next = *next;
*next = blitter;
}
......@@ -2437,10 +2437,6 @@ struct wined3d_blitter *wined3d_glsl_blitter_create(struct wined3d_blitter **nex
void wined3d_raw_blitter_create(struct wined3d_blitter **next,
const struct wined3d_gl_info *gl_info) DECLSPEC_HIDDEN;
BOOL fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct wined3d_gl_info *gl_info,
const struct wined3d_resource *src_resource, DWORD src_location,
const struct wined3d_resource *dst_resource, DWORD dst_location) DECLSPEC_HIDDEN;
BOOL wined3d_clip_blit(const RECT *clip_rect, RECT *clipped, RECT *other) DECLSPEC_HIDDEN;
HGLRC context_create_wgl_attribs(const struct wined3d_gl_info *gl_info, HDC hdc, HGLRC share_ctx) DECLSPEC_HIDDEN;
......@@ -3872,11 +3868,6 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_
const struct wined3d_box *dst_box, struct wined3d_texture *src_texture,
unsigned int src_sub_resource_idx, const struct wined3d_box *src_box, DWORD flags,
const struct wined3d_blt_fx *blt_fx, enum wined3d_texture_filter_type filter) DECLSPEC_HIDDEN;
void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_context *context,
enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture,
unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect,
struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location,
const RECT *dst_rect) DECLSPEC_HIDDEN;
void texture2d_get_blt_info(const struct wined3d_texture_gl *texture_gl, unsigned int sub_resource_idx,
const RECT *rect, struct wined3d_blt_info *info) DECLSPEC_HIDDEN;
void texture2d_load_fb_texture(struct wined3d_texture_gl *texture_gl, unsigned int sub_resource_idx,
......
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