[PATCH 4/5] wined3d: Move the FBO blitter to texture.c.
Henri Verbeet
hverbeet at codeweavers.com
Wed Apr 22 16:34:57 CDT 2020
Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
dlls/wined3d/surface.c | 370 -------------------------------
dlls/wined3d/texture.c | 382 +++++++++++++++++++++++++++++++++
dlls/wined3d/wined3d_private.h | 9 -
3 files changed, 382 insertions(+), 379 deletions(-)
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 2c072454f32..0dd8c4266b6 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -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)
{
@@ -859,117 +600,6 @@ void texture2d_load_fb_texture(struct wined3d_texture_gl *texture_gl,
context_restore(context, restore_texture, restore_idx);
}
-/* 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)
{
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index c11490057c3..0036607005c 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -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;
+}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b78fbde0f47..bd42e3f18b4 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -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,
--
2.20.1
More information about the wine-devel
mailing list