Signed-off-by: Henri Verbeet hverbeet@codeweavers.com --- dlls/wined3d/surface.c | 390 ----------------------------------------- dlls/wined3d/texture.c | 389 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 389 insertions(+), 390 deletions(-)
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 06912203122..2c072454f32 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -1106,396 +1106,6 @@ void wined3d_raw_blitter_create(struct wined3d_blitter **next, const struct wine *next = blitter; }
-/* Context activation is done by the caller. */ -static void ffp_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 BOOL ffp_blit_supported(enum wined3d_blit_op blit_op, const struct wined3d_context *context, - 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 decompress; - - if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D) - return FALSE; - - decompress = (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED) - && !(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED); - if (!decompress && !(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU)) - { - TRACE("Source or destination resource is not GPU accessible.\n"); - return FALSE; - } - - if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_format->id == src_format->id) - { - if (dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)) - blit_op = WINED3D_BLIT_OP_DEPTH_BLIT; - else - blit_op = WINED3D_BLIT_OP_COLOR_BLIT; - } - - switch (blit_op) - { - case WINED3D_BLIT_OP_COLOR_BLIT_CKEY: - if (context->d3d_info->shader_color_key) - { - TRACE("Color keying requires converted textures.\n"); - return FALSE; - } - case WINED3D_BLIT_OP_COLOR_BLIT: - case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST: - if (!wined3d_context_gl_const(context)->gl_info->supported[WINED3D_GL_LEGACY_CONTEXT]) - return FALSE; - - if (TRACE_ON(d3d)) - { - TRACE("Checking support for fixup:\n"); - dump_color_fixup_desc(src_format->color_fixup); - } - - /* We only support identity conversions. */ - if (!is_identity_fixup(src_format->color_fixup) - || !is_identity_fixup(dst_format->color_fixup)) - { - if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER - && dst_format->id == src_format->id && dst_location == WINED3D_LOCATION_DRAWABLE) - { - WARN("Claiming fixup support because of ORM_BACKBUFFER.\n"); - } - else - { - TRACE("Fixups are not supported.\n"); - return FALSE; - } - } - - if (!(dst_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)) - { - TRACE("Can only blit to render targets.\n"); - return FALSE; - } - return TRUE; - - default: - TRACE("Unsupported blit operation %#x.\n", blit_op); - return FALSE; - } -} - -static BOOL ffp_blitter_use_cpu_clear(struct wined3d_rendertarget_view *view) -{ - struct wined3d_resource *resource; - struct wined3d_texture *texture; - DWORD locations; - - resource = view->resource; - if (resource->type == WINED3D_RTYPE_BUFFER) - return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU); - - texture = texture_from_resource(resource); - locations = texture->sub_resources[view->sub_resource_idx].locations; - if (locations & (resource->map_binding | WINED3D_LOCATION_DISCARDED)) - return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU) - || (texture->flags & WINED3D_TEXTURE_PIN_SYSMEM); - - return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU) - && !(texture->flags & WINED3D_TEXTURE_CONVERTED); -} - -static void ffp_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_rendertarget_view *view, *previous = NULL; - BOOL have_identical_size = TRUE; - struct wined3d_fb_state tmp_fb; - unsigned int next_rt_count = 0; - struct wined3d_blitter *next; - DWORD next_flags = 0; - unsigned int i; - - if (flags & WINED3DCLEAR_TARGET) - { - for (i = 0; i < rt_count; ++i) - { - if (!(view = fb->render_targets[i])) - continue; - - if (ffp_blitter_use_cpu_clear(view) - || (!(view->resource->bind_flags & WINED3D_BIND_RENDER_TARGET) - && (wined3d_settings.offscreen_rendering_mode != ORM_FBO - || !(view->format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE)))) - { - next_flags |= WINED3DCLEAR_TARGET; - flags &= ~WINED3DCLEAR_TARGET; - next_rt_count = rt_count; - rt_count = 0; - break; - } - - /* FIXME: We should reject colour fills on formats with fixups, - * but this would break P8 colour fills for example. */ - } - } - - if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil) - && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER)) - && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL)) - && ffp_blitter_use_cpu_clear(view)) - { - next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); - flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); - } - - if (flags) - { - for (i = 0; i < rt_count; ++i) - { - if (!(view = fb->render_targets[i])) - continue; - - if (previous && (previous->width != view->width || previous->height != view->height)) - have_identical_size = FALSE; - previous = view; - } - if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) - { - view = fb->depth_stencil; - - if (previous && (previous->width != view->width || previous->height != view->height)) - have_identical_size = FALSE; - } - - if (have_identical_size) - { - device_clear_render_targets(device, rt_count, fb, rect_count, - clear_rects, draw_rect, flags, colour, depth, stencil); - } - else - { - for (i = 0; i < rt_count; ++i) - { - if (!(view = fb->render_targets[i])) - continue; - - tmp_fb.render_targets[0] = view; - tmp_fb.depth_stencil = NULL; - device_clear_render_targets(device, 1, &tmp_fb, rect_count, - clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil); - } - if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) - { - tmp_fb.render_targets[0] = NULL; - tmp_fb.depth_stencil = fb->depth_stencil; - device_clear_render_targets(device, 0, &tmp_fb, rect_count, - clear_rects, draw_rect, flags & ~WINED3DCLEAR_TARGET, colour, depth, stencil); - } - } - } - - if (next_flags && (next = blitter->next)) - next->ops->blitter_clear(next, device, next_rt_count, fb, rect_count, - clear_rects, draw_rect, next_flags, colour, depth, stencil); -} - -static DWORD ffp_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 *color_key, enum wined3d_texture_filter_type filter) -{ - struct wined3d_texture_gl *src_texture_gl = wined3d_texture_gl(src_texture); - struct wined3d_context_gl *context_gl = wined3d_context_gl(context); - const struct wined3d_gl_info *gl_info = context_gl->gl_info; - struct wined3d_resource *src_resource, *dst_resource; - struct wined3d_texture *staging_texture = NULL; - struct wined3d_color_key old_blt_key; - struct wined3d_device *device; - struct wined3d_blitter *next; - DWORD old_color_key_flags; - RECT r; - - src_resource = &src_texture->resource; - dst_resource = &dst_texture->resource; - device = dst_resource->device; - - if (!ffp_blit_supported(op, context, src_resource, src_location, dst_resource, dst_location)) - { - if ((next = blitter->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, color_key, filter); - } - - TRACE("Blt from texture %p, %u to rendertarget %p, %u.\n", - src_texture, src_sub_resource_idx, dst_texture, dst_sub_resource_idx); - - old_blt_key = src_texture->async.src_blt_color_key; - old_color_key_flags = src_texture->async.color_key_flags; - wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, color_key); - - if (!(src_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU)) - { - struct wined3d_resource_desc desc; - struct wined3d_box upload_box; - unsigned int src_level; - HRESULT hr; - - TRACE("Source texture is not GPU accessible, creating a staging texture.\n"); - - src_level = src_sub_resource_idx % src_texture->level_count; - desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; - desc.format = src_texture->resource.format->id; - desc.multisample_type = src_texture->resource.multisample_type; - desc.multisample_quality = src_texture->resource.multisample_quality; - desc.usage = WINED3DUSAGE_PRIVATE; - 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; - - if (FAILED(hr = wined3d_texture_create(device, &desc, 1, 1, 0, - NULL, NULL, &wined3d_null_parent_ops, &staging_texture))) - { - ERR("Failed to create staging texture, hr %#x.\n", hr); - return dst_location; - } - - wined3d_box_set(&upload_box, 0, 0, desc.width, desc.height, 0, desc.depth); - wined3d_texture_upload_from_texture(staging_texture, 0, 0, 0, 0, - src_texture, src_sub_resource_idx, &upload_box); - - src_texture = staging_texture; - src_texture_gl = wined3d_texture_gl(src_texture); - src_sub_resource_idx = 0; - } - else - { - /* Make sure the surface is up-to-date. This should probably use - * surface_load_location() and worry about the destination surface - * too, unless we're overwriting it completely. */ - wined3d_texture_load(src_texture, context, FALSE); - } - - wined3d_context_gl_apply_ffp_blit_state(context_gl, device); - - if (dst_location == WINED3D_LOCATION_DRAWABLE) - { - r = *dst_rect; - wined3d_texture_translate_drawable_coords(dst_texture, context_gl->window, &r); - dst_rect = &r; - } - - if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) - { - GLenum buffer; - - if (dst_location == WINED3D_LOCATION_DRAWABLE) - { - TRACE("Destination texture %p is onscreen.\n", dst_texture); - buffer = wined3d_texture_get_gl_buffer(dst_texture); - } - 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_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_glEnable(src_texture_gl->target); - checkGLcall("glEnable(target)"); - - if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST || color_key) - { - gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST); - checkGLcall("glEnable(GL_ALPHA_TEST)"); - } - - if (color_key) - { - /* For P8 surfaces, the alpha component contains the palette index. - * Which means that the colorkey is one of the palette entries. In - * other cases pixels that should be masked away have alpha set to 0. */ - if (src_texture->resource.format->id == WINED3DFMT_P8_UINT) - gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, - (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f); - else - gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f); - checkGLcall("glAlphaFunc"); - } - - wined3d_context_gl_draw_textured_quad(context_gl, src_texture_gl, - src_sub_resource_idx, src_rect, dst_rect, filter); - - if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST || color_key) - { - gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST); - checkGLcall("glDisable(GL_ALPHA_TEST)"); - } - - gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D); - checkGLcall("glDisable(GL_TEXTURE_2D)"); - if (gl_info->supported[ARB_TEXTURE_CUBE_MAP]) - { - gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB); - checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); - } - if (gl_info->supported[ARB_TEXTURE_RECTANGLE]) - { - gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB); - checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)"); - } - - if (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture) - gl_info->gl_ops.gl.p_glFlush(); - - /* Restore the color key parameters */ - wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, - (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL); - - if (staging_texture) - wined3d_texture_decref(staging_texture); - - return dst_location; -} - -static const struct wined3d_blitter_ops ffp_blitter_ops = -{ - ffp_blitter_destroy, - ffp_blitter_clear, - ffp_blitter_blit, -}; - -void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info) -{ - struct wined3d_blitter *blitter; - - if (!(blitter = heap_alloc(sizeof(*blitter)))) - return; - - TRACE("Created blitter %p.\n", blitter); - - blitter->ops = &ffp_blitter_ops; - blitter->next = *next; - *next = blitter; -} - /* Context activation is done by the caller. */ static void cpu_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context) { diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index ac3601d4f47..c11490057c3 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -4821,3 +4821,392 @@ HRESULT wined3d_texture_vk_init(struct wined3d_texture_vk *texture_vk, struct wi return wined3d_texture_init(&texture_vk->t, desc, layer_count, level_count, flags, device, parent, parent_ops, &texture_vk[1], &wined3d_texture_vk_ops); } + +static void ffp_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 bool ffp_blit_supported(enum wined3d_blit_op blit_op, const struct wined3d_context *context, + 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 decompress; + + if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D) + return false; + + decompress = (src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED) + && !(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED); + if (!decompress && !(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU)) + { + TRACE("Source or destination resource is not GPU accessible.\n"); + return false; + } + + if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_format->id == src_format->id) + { + if (dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)) + blit_op = WINED3D_BLIT_OP_DEPTH_BLIT; + else + blit_op = WINED3D_BLIT_OP_COLOR_BLIT; + } + + switch (blit_op) + { + case WINED3D_BLIT_OP_COLOR_BLIT_CKEY: + if (context->d3d_info->shader_color_key) + { + TRACE("Colour keying requires converted textures.\n"); + return false; + } + case WINED3D_BLIT_OP_COLOR_BLIT: + case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST: + if (!wined3d_context_gl_const(context)->gl_info->supported[WINED3D_GL_LEGACY_CONTEXT]) + return false; + + if (TRACE_ON(d3d)) + { + TRACE("Checking support for fixup:\n"); + dump_color_fixup_desc(src_format->color_fixup); + } + + /* We only support identity conversions. */ + if (!is_identity_fixup(src_format->color_fixup) + || !is_identity_fixup(dst_format->color_fixup)) + { + if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER + && dst_format->id == src_format->id && dst_location == WINED3D_LOCATION_DRAWABLE) + { + WARN("Claiming fixup support because of ORM_BACKBUFFER.\n"); + } + else + { + TRACE("Fixups are not supported.\n"); + return false; + } + } + + if (!(dst_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)) + { + TRACE("Can only blit to render targets.\n"); + return false; + } + return true; + + default: + TRACE("Unsupported blit operation %#x.\n", blit_op); + return false; + } +} + +static bool ffp_blitter_use_cpu_clear(struct wined3d_rendertarget_view *view) +{ + struct wined3d_resource *resource; + struct wined3d_texture *texture; + DWORD locations; + + resource = view->resource; + if (resource->type == WINED3D_RTYPE_BUFFER) + return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU); + + texture = texture_from_resource(resource); + locations = texture->sub_resources[view->sub_resource_idx].locations; + if (locations & (resource->map_binding | WINED3D_LOCATION_DISCARDED)) + return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU) + || (texture->flags & WINED3D_TEXTURE_PIN_SYSMEM); + + return !(resource->access & WINED3D_RESOURCE_ACCESS_GPU) + && !(texture->flags & WINED3D_TEXTURE_CONVERTED); +} + +static void ffp_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_rendertarget_view *view, *previous = NULL; + bool have_identical_size = TRUE; + struct wined3d_fb_state tmp_fb; + unsigned int next_rt_count = 0; + struct wined3d_blitter *next; + DWORD next_flags = 0; + unsigned int i; + + if (flags & WINED3DCLEAR_TARGET) + { + for (i = 0; i < rt_count; ++i) + { + if (!(view = fb->render_targets[i])) + continue; + + if (ffp_blitter_use_cpu_clear(view) + || (!(view->resource->bind_flags & WINED3D_BIND_RENDER_TARGET) + && (wined3d_settings.offscreen_rendering_mode != ORM_FBO + || !(view->format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE)))) + { + next_flags |= WINED3DCLEAR_TARGET; + flags &= ~WINED3DCLEAR_TARGET; + next_rt_count = rt_count; + rt_count = 0; + break; + } + + /* FIXME: We should reject colour fills on formats with fixups, + * but this would break P8 colour fills for example. */ + } + } + + if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil) + && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER)) + && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL)) + && ffp_blitter_use_cpu_clear(view)) + { + next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); + flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); + } + + if (flags) + { + for (i = 0; i < rt_count; ++i) + { + if (!(view = fb->render_targets[i])) + continue; + + if (previous && (previous->width != view->width || previous->height != view->height)) + have_identical_size = false; + previous = view; + } + if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) + { + view = fb->depth_stencil; + + if (previous && (previous->width != view->width || previous->height != view->height)) + have_identical_size = false; + } + + if (have_identical_size) + { + device_clear_render_targets(device, rt_count, fb, rect_count, + clear_rects, draw_rect, flags, colour, depth, stencil); + } + else + { + for (i = 0; i < rt_count; ++i) + { + if (!(view = fb->render_targets[i])) + continue; + + tmp_fb.render_targets[0] = view; + tmp_fb.depth_stencil = NULL; + device_clear_render_targets(device, 1, &tmp_fb, rect_count, + clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil); + } + if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) + { + tmp_fb.render_targets[0] = NULL; + tmp_fb.depth_stencil = fb->depth_stencil; + device_clear_render_targets(device, 0, &tmp_fb, rect_count, + clear_rects, draw_rect, flags & ~WINED3DCLEAR_TARGET, colour, depth, stencil); + } + } + } + + if (next_flags && (next = blitter->next)) + next->ops->blitter_clear(next, device, next_rt_count, fb, rect_count, + clear_rects, draw_rect, next_flags, colour, depth, stencil); +} + +static DWORD ffp_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_texture_gl *src_texture_gl = wined3d_texture_gl(src_texture); + struct wined3d_context_gl *context_gl = wined3d_context_gl(context); + const struct wined3d_gl_info *gl_info = context_gl->gl_info; + struct wined3d_resource *src_resource, *dst_resource; + struct wined3d_texture *staging_texture = NULL; + struct wined3d_color_key old_blt_key; + struct wined3d_device *device; + struct wined3d_blitter *next; + DWORD old_colour_key_flags; + RECT r; + + src_resource = &src_texture->resource; + dst_resource = &dst_texture->resource; + device = dst_resource->device; + + if (!ffp_blit_supported(op, context, src_resource, src_location, dst_resource, dst_location)) + { + if ((next = blitter->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); + } + + TRACE("Blt from texture %p, %u to rendertarget %p, %u.\n", + src_texture, src_sub_resource_idx, dst_texture, dst_sub_resource_idx); + + old_blt_key = src_texture->async.src_blt_color_key; + old_colour_key_flags = src_texture->async.color_key_flags; + wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, colour_key); + + if (!(src_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU)) + { + struct wined3d_resource_desc desc; + struct wined3d_box upload_box; + unsigned int src_level; + HRESULT hr; + + TRACE("Source texture is not GPU accessible, creating a staging texture.\n"); + + src_level = src_sub_resource_idx % src_texture->level_count; + desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; + desc.format = src_texture->resource.format->id; + desc.multisample_type = src_texture->resource.multisample_type; + desc.multisample_quality = src_texture->resource.multisample_quality; + desc.usage = WINED3DUSAGE_PRIVATE; + 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; + + if (FAILED(hr = wined3d_texture_create(device, &desc, 1, 1, 0, + NULL, NULL, &wined3d_null_parent_ops, &staging_texture))) + { + ERR("Failed to create staging texture, hr %#x.\n", hr); + return dst_location; + } + + wined3d_box_set(&upload_box, 0, 0, desc.width, desc.height, 0, desc.depth); + wined3d_texture_upload_from_texture(staging_texture, 0, 0, 0, 0, + src_texture, src_sub_resource_idx, &upload_box); + + src_texture = staging_texture; + src_texture_gl = wined3d_texture_gl(src_texture); + src_sub_resource_idx = 0; + } + else + { + /* Make sure the surface is up-to-date. This should probably use + * surface_load_location() and worry about the destination surface + * too, unless we're overwriting it completely. */ + wined3d_texture_load(src_texture, context, FALSE); + } + + wined3d_context_gl_apply_ffp_blit_state(context_gl, device); + + if (dst_location == WINED3D_LOCATION_DRAWABLE) + { + r = *dst_rect; + wined3d_texture_translate_drawable_coords(dst_texture, context_gl->window, &r); + dst_rect = &r; + } + + if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) + { + GLenum buffer; + + if (dst_location == WINED3D_LOCATION_DRAWABLE) + { + TRACE("Destination texture %p is onscreen.\n", dst_texture); + buffer = wined3d_texture_get_gl_buffer(dst_texture); + } + 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_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_glEnable(src_texture_gl->target); + checkGLcall("glEnable(target)"); + + if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST || colour_key) + { + gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST); + checkGLcall("glEnable(GL_ALPHA_TEST)"); + } + + if (colour_key) + { + /* For P8 surfaces, the alpha component contains the palette index. + * Which means that the colourkey is one of the palette entries. In + * other cases pixels that should be masked away have alpha set to 0. */ + if (src_texture->resource.format->id == WINED3DFMT_P8_UINT) + gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, + (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f); + else + gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f); + checkGLcall("glAlphaFunc"); + } + + wined3d_context_gl_draw_textured_quad(context_gl, src_texture_gl, + src_sub_resource_idx, src_rect, dst_rect, filter); + + if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST || colour_key) + { + gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST); + checkGLcall("glDisable(GL_ALPHA_TEST)"); + } + + gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D); + checkGLcall("glDisable(GL_TEXTURE_2D)"); + if (gl_info->supported[ARB_TEXTURE_CUBE_MAP]) + { + gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); + } + if (gl_info->supported[ARB_TEXTURE_RECTANGLE]) + { + gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB); + checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)"); + } + + if (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture) + gl_info->gl_ops.gl.p_glFlush(); + + /* Restore the colour key parameters */ + wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, + (old_colour_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL); + + if (staging_texture) + wined3d_texture_decref(staging_texture); + + return dst_location; +} + +static const struct wined3d_blitter_ops ffp_blitter_ops = +{ + ffp_blitter_destroy, + ffp_blitter_clear, + ffp_blitter_blit, +}; + +void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info) +{ + struct wined3d_blitter *blitter; + + if (!(blitter = heap_alloc(sizeof(*blitter)))) + return; + + TRACE("Created blitter %p.\n", blitter); + + blitter->ops = &ffp_blitter_ops; + blitter->next = *next; + *next = blitter; +}