From: Stian Low wineryyyyy@gmail.com
--- dlls/wined3d/texture.c | 488 -------------------------------------- dlls/wined3d/texture_gl.c | 488 ++++++++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d_gl.h | 9 - 3 files changed, 488 insertions(+), 497 deletions(-)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 367c80f51a9..61c7067e39e 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -113,384 +113,6 @@ static uint32_t wined3d_resource_access_from_location(uint32_t location) } }
-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; - bool src_ds, dst_ds; - - if ((src_resource->format_attrs | dst_resource->format_attrs) & WINED3D_FORMAT_ATTR_HEIGHT_SCALE) - 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; - - /* We can't copy between depth/stencil and colour attachments. One notable - * way we can end up here is when copying between typeless resources with - * formats like R16_TYPELESS, which can end up using either a - * depth/stencil or a colour format on the OpenGL side, depending on the - * resource's bind flags. */ - src_ds = src_format->depth_size || src_format->stencil_size; - dst_ds = dst_format->depth_size || dst_format->stencil_size; - if (src_ds != dst_ds) - return false; - - switch (blit_op) - { - case WINED3D_BLIT_OP_COLOR_BLIT: - if (!((src_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_FBO_ATTACHABLE) - || (src_resource->bind_flags & WINED3D_BIND_RENDER_TARGET))) - return false; - if (!((dst_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_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->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_DEPTH_STENCIL)) - return false; - if (!(dst_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_DEPTH_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. */ -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, const struct wined3d_format *resolve_format) -{ - struct wined3d_texture *required_texture, *restore_texture, *dst_save_texture = dst_texture; - unsigned int restore_idx, dst_save_sub_resource_idx = dst_sub_resource_idx; - bool resolve, scaled_resolve, restore_context = false; - struct wined3d_texture *src_staging_texture = NULL; - const struct wined3d_gl_info *gl_info; - struct wined3d_context_gl *context_gl; - 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, resolve format %p.\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), resolve_format); - - resolve = wined3d_texture_gl_is_multisample_location(wined3d_texture_gl(src_texture), src_location); - scaled_resolve = resolve - && (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; - - if (resolve) - { - GLint resolve_internal, src_internal, dst_internal; - enum wined3d_format_id resolve_format_id; - - src_internal = wined3d_gl_get_internal_format(&src_texture->resource, - wined3d_format_gl(src_texture->resource.format), src_location == WINED3D_LOCATION_TEXTURE_SRGB); - dst_internal = wined3d_gl_get_internal_format(&dst_texture->resource, - wined3d_format_gl(dst_texture->resource.format), dst_location == WINED3D_LOCATION_TEXTURE_SRGB); - - if (resolve_format) - { - resolve_internal = wined3d_format_gl(resolve_format)->internal; - resolve_format_id = resolve_format->id; - } - else if (!wined3d_format_is_typeless(src_texture->resource.format)) - { - resolve_internal = src_internal; - resolve_format_id = src_texture->resource.format->id; - } - else - { - resolve_internal = dst_internal; - resolve_format_id = dst_texture->resource.format->id; - } - - /* In case of typeless resolve the texture type may not match the resolve type. - * To handle that, allocate intermediate texture(s) to resolve from/to. - * A possible performance improvement would be to resolve using a shader instead. */ - if (src_internal != resolve_internal) - { - struct wined3d_resource_desc desc; - unsigned src_level; - HRESULT hr; - - src_level = src_sub_resource_idx % src_texture->level_count; - desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; - desc.format = resolve_format_id; - desc.multisample_type = src_texture->resource.multisample_type; - desc.multisample_quality = src_texture->resource.multisample_quality; - desc.usage = WINED3DUSAGE_CS; - desc.bind_flags = 0; - desc.access = WINED3D_RESOURCE_ACCESS_GPU; - desc.width = wined3d_texture_get_level_width(src_texture, src_level); - desc.height = wined3d_texture_get_level_height(src_texture, src_level); - desc.depth = 1; - desc.size = 0; - - hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops, - &src_staging_texture); - if (FAILED(hr)) - { - ERR("Failed to create staging texture, hr %#lx.\n", hr); - goto done; - } - - if (src_location == WINED3D_LOCATION_DRAWABLE) - FIXME("WINED3D_LOCATION_DRAWABLE not supported for the source of a typeless resolve.\n"); - - device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context, - src_texture, src_sub_resource_idx, src_location, src_rect, - src_staging_texture, 0, src_location, src_rect, - NULL, WINED3D_TEXF_NONE, NULL); - - src_texture = src_staging_texture; - src_sub_resource_idx = 0; - } - - if (dst_internal != resolve_internal) - { - struct wined3d_resource_desc desc; - unsigned dst_level; - HRESULT hr; - - dst_level = dst_sub_resource_idx % dst_texture->level_count; - desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; - desc.format = resolve_format_id; - desc.multisample_type = dst_texture->resource.multisample_type; - desc.multisample_quality = dst_texture->resource.multisample_quality; - desc.usage = WINED3DUSAGE_CS; - desc.bind_flags = 0; - desc.access = WINED3D_RESOURCE_ACCESS_GPU; - desc.width = wined3d_texture_get_level_width(dst_texture, dst_level); - desc.height = wined3d_texture_get_level_height(dst_texture, dst_level); - desc.depth = 1; - desc.size = 0; - - hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops, - &dst_texture); - if (FAILED(hr)) - { - ERR("Failed to create staging texture, hr %#lx.\n", hr); - goto done; - } - - wined3d_texture_load_location(dst_texture, 0, context, dst_location); - dst_sub_resource_idx = 0; - } - } - - /* 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 (!wined3d_texture_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); - restore_context = true; - } - - context_gl = wined3d_context_gl(context); - if (!context_gl->valid) - { - context_release(context); - WARN("Invalid context, skipping blit.\n"); - restore_context = false; - goto done; - } - - 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_explicit(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); - - context_gl_apply_texture_draw_state(context_gl, dst_texture, dst_sub_resource_idx, dst_location); - - if (dst_location == WINED3D_LOCATION_DRAWABLE) - { - d = *dst_rect; - wined3d_texture_translate_drawable_coords(dst_texture, context_gl->window, &d); - dst_rect = &d; - } - - 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 (dst_texture != dst_save_texture) - { - if (dst_location == WINED3D_LOCATION_DRAWABLE) - FIXME("WINED3D_LOCATION_DRAWABLE not supported for the destination of a typeless resolve.\n"); - - device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context, - dst_texture, 0, dst_location, dst_rect, - dst_save_texture, dst_save_sub_resource_idx, dst_location, dst_rect, - NULL, WINED3D_TEXF_NONE, NULL); - } - -done: - if (dst_texture != dst_save_texture) - wined3d_texture_decref(dst_texture); - - if (src_staging_texture) - wined3d_texture_decref(src_staging_texture); - - if (restore_context) - 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; - GLbitfield 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 = 0; - if (src_texture->resource.format->depth_size) - src_mask |= GL_DEPTH_BUFFER_BIT; - if (src_texture->resource.format->stencil_size) - src_mask |= GL_STENCIL_BUFFER_BIT; - - dst_mask = 0; - if (dst_texture->resource.format->depth_size) - dst_mask |= GL_DEPTH_BUFFER_BIT; - if (dst_texture->resource.format->stencil_size) - dst_mask |= GL_STENCIL_BUFFER_BIT; - - 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 = src_mask; - - /* 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 (!wined3d_texture_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_explicit(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); - - context_gl_apply_texture_draw_state(context_gl, dst_texture, dst_sub_resource_idx, dst_location); - - if (gl_mask & GL_DEPTH_BUFFER_BIT) - { - gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE); - context_invalidate_state(context, STATE_DEPTH_STENCIL); - } - 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); - gl_info->gl_ops.gl.p_glStencilMask(~0U); - context_invalidate_state(context, STATE_DEPTH_STENCIL); - } - - 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; @@ -2993,116 +2615,6 @@ void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wine *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); - - 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, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int 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, - const struct wined3d_format *resolve_format) -{ - 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, resolve_format %p.\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), resolve_format); - - 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->depth_size || dst_resource->format->stencil_size) - 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, - resolve_format); - } - - 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, resolve_format); - 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 (!(blitter = malloc(sizeof(*blitter)))) - return; - - TRACE("Created blitter %p.\n", blitter); - - blitter->ops = &fbo_blitter_ops; - blitter->next = *next; - *next = blitter; -} - static void raw_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context) { struct wined3d_blitter *next; diff --git a/dlls/wined3d/texture_gl.c b/dlls/wined3d/texture_gl.c index 06915206743..42fcf10c3d9 100644 --- a/dlls/wined3d/texture_gl.c +++ b/dlls/wined3d/texture_gl.c @@ -63,6 +63,494 @@ GLenum wined3d_texture_get_gl_buffer(const struct wined3d_texture *texture) return GL_BACK; }
+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; + bool src_ds, dst_ds; + + if ((src_resource->format_attrs | dst_resource->format_attrs) & WINED3D_FORMAT_ATTR_HEIGHT_SCALE) + 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; + + /* We can't copy between depth/stencil and colour attachments. One notable + * way we can end up here is when copying between typeless resources with + * formats like R16_TYPELESS, which can end up using either a + * depth/stencil or a colour format on the OpenGL side, depending on the + * resource's bind flags. */ + src_ds = src_format->depth_size || src_format->stencil_size; + dst_ds = dst_format->depth_size || dst_format->stencil_size; + if (src_ds != dst_ds) + return false; + + switch (blit_op) + { + case WINED3D_BLIT_OP_COLOR_BLIT: + if (!((src_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_FBO_ATTACHABLE) + || (src_resource->bind_flags & WINED3D_BIND_RENDER_TARGET))) + return false; + if (!((dst_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_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->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_DEPTH_STENCIL)) + return false; + if (!(dst_format->caps[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3D_FORMAT_CAP_DEPTH_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, const struct wined3d_format *resolve_format) +{ + struct wined3d_texture *required_texture, *restore_texture, *dst_save_texture = dst_texture; + unsigned int restore_idx, dst_save_sub_resource_idx = dst_sub_resource_idx; + bool resolve, scaled_resolve, restore_context = false; + struct wined3d_texture *src_staging_texture = NULL; + const struct wined3d_gl_info *gl_info; + struct wined3d_context_gl *context_gl; + 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, resolve format %p.\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), resolve_format); + + resolve = wined3d_texture_gl_is_multisample_location(wined3d_texture_gl(src_texture), src_location); + scaled_resolve = resolve + && (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; + + if (resolve) + { + GLint resolve_internal, src_internal, dst_internal; + enum wined3d_format_id resolve_format_id; + + src_internal = wined3d_gl_get_internal_format(&src_texture->resource, + wined3d_format_gl(src_texture->resource.format), src_location == WINED3D_LOCATION_TEXTURE_SRGB); + dst_internal = wined3d_gl_get_internal_format(&dst_texture->resource, + wined3d_format_gl(dst_texture->resource.format), dst_location == WINED3D_LOCATION_TEXTURE_SRGB); + + if (resolve_format) + { + resolve_internal = wined3d_format_gl(resolve_format)->internal; + resolve_format_id = resolve_format->id; + } + else if (!wined3d_format_is_typeless(src_texture->resource.format)) + { + resolve_internal = src_internal; + resolve_format_id = src_texture->resource.format->id; + } + else + { + resolve_internal = dst_internal; + resolve_format_id = dst_texture->resource.format->id; + } + + /* In case of typeless resolve the texture type may not match the resolve type. + * To handle that, allocate intermediate texture(s) to resolve from/to. + * A possible performance improvement would be to resolve using a shader instead. */ + if (src_internal != resolve_internal) + { + struct wined3d_resource_desc desc; + unsigned src_level; + HRESULT hr; + + src_level = src_sub_resource_idx % src_texture->level_count; + desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; + desc.format = resolve_format_id; + desc.multisample_type = src_texture->resource.multisample_type; + desc.multisample_quality = src_texture->resource.multisample_quality; + desc.usage = WINED3DUSAGE_CS; + desc.bind_flags = 0; + desc.access = WINED3D_RESOURCE_ACCESS_GPU; + desc.width = wined3d_texture_get_level_width(src_texture, src_level); + desc.height = wined3d_texture_get_level_height(src_texture, src_level); + desc.depth = 1; + desc.size = 0; + + hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops, + &src_staging_texture); + if (FAILED(hr)) + { + ERR("Failed to create staging texture, hr %#lx.\n", hr); + goto done; + } + + if (src_location == WINED3D_LOCATION_DRAWABLE) + FIXME("WINED3D_LOCATION_DRAWABLE not supported for the source of a typeless resolve.\n"); + + device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context, + src_texture, src_sub_resource_idx, src_location, src_rect, + src_staging_texture, 0, src_location, src_rect, + NULL, WINED3D_TEXF_NONE, NULL); + + src_texture = src_staging_texture; + src_sub_resource_idx = 0; + } + + if (dst_internal != resolve_internal) + { + struct wined3d_resource_desc desc; + unsigned dst_level; + HRESULT hr; + + dst_level = dst_sub_resource_idx % dst_texture->level_count; + desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; + desc.format = resolve_format_id; + desc.multisample_type = dst_texture->resource.multisample_type; + desc.multisample_quality = dst_texture->resource.multisample_quality; + desc.usage = WINED3DUSAGE_CS; + desc.bind_flags = 0; + desc.access = WINED3D_RESOURCE_ACCESS_GPU; + desc.width = wined3d_texture_get_level_width(dst_texture, dst_level); + desc.height = wined3d_texture_get_level_height(dst_texture, dst_level); + desc.depth = 1; + desc.size = 0; + + hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops, + &dst_texture); + if (FAILED(hr)) + { + ERR("Failed to create staging texture, hr %#lx.\n", hr); + goto done; + } + + wined3d_texture_load_location(dst_texture, 0, context, dst_location); + dst_sub_resource_idx = 0; + } + } + + /* 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 (!wined3d_texture_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); + restore_context = true; + } + + context_gl = wined3d_context_gl(context); + if (!context_gl->valid) + { + context_release(context); + WARN("Invalid context, skipping blit.\n"); + restore_context = false; + goto done; + } + + 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_explicit(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); + + context_gl_apply_texture_draw_state(context_gl, dst_texture, dst_sub_resource_idx, dst_location); + + if (dst_location == WINED3D_LOCATION_DRAWABLE) + { + d = *dst_rect; + wined3d_texture_translate_drawable_coords(dst_texture, context_gl->window, &d); + dst_rect = &d; + } + + 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 (dst_texture != dst_save_texture) + { + if (dst_location == WINED3D_LOCATION_DRAWABLE) + FIXME("WINED3D_LOCATION_DRAWABLE not supported for the destination of a typeless resolve.\n"); + + device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context, + dst_texture, 0, dst_location, dst_rect, + dst_save_texture, dst_save_sub_resource_idx, dst_location, dst_rect, + NULL, WINED3D_TEXF_NONE, NULL); + } + +done: + if (dst_texture != dst_save_texture) + wined3d_texture_decref(dst_texture); + + if (src_staging_texture) + wined3d_texture_decref(src_staging_texture); + + if (restore_context) + 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; + GLbitfield 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 = 0; + if (src_texture->resource.format->depth_size) + src_mask |= GL_DEPTH_BUFFER_BIT; + if (src_texture->resource.format->stencil_size) + src_mask |= GL_STENCIL_BUFFER_BIT; + + dst_mask = 0; + if (dst_texture->resource.format->depth_size) + dst_mask |= GL_DEPTH_BUFFER_BIT; + if (dst_texture->resource.format->stencil_size) + dst_mask |= GL_STENCIL_BUFFER_BIT; + + 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 = src_mask; + + /* 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 (!wined3d_texture_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_explicit(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); + + context_gl_apply_texture_draw_state(context_gl, dst_texture, dst_sub_resource_idx, dst_location); + + if (gl_mask & GL_DEPTH_BUFFER_BIT) + { + gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE); + context_invalidate_state(context, STATE_DEPTH_STENCIL); + } + 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); + gl_info->gl_ops.gl.p_glStencilMask(~0U); + context_invalidate_state(context, STATE_DEPTH_STENCIL); + } + + 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 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); + + 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, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int 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, + const struct wined3d_format *resolve_format) +{ + 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, resolve_format %p.\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), resolve_format); + + 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->depth_size || dst_resource->format->stencil_size) + 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, + resolve_format); + } + + 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, resolve_format); + 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 (!(blitter = malloc(sizeof(*blitter)))) + return; + + TRACE("Created blitter %p.\n", blitter); + + blitter->ops = &fbo_blitter_ops; + blitter->next = *next; + *next = blitter; +} + struct wined3d_rect_f { float l; diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h index 69ccc5281ea..ed537686007 100644 --- a/dlls/wined3d/wined3d_gl.h +++ b/dlls/wined3d/wined3d_gl.h @@ -790,15 +790,6 @@ void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wine struct wined3d_blitter *wined3d_glsl_blitter_create(struct wined3d_blitter **next, const struct wined3d_device *device); void wined3d_raw_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info);
-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); -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, const struct wined3d_format *resolve_format); - struct wined3d_caps_gl_ctx { HDC dc;