wined3d: Move the OpenGL fixed-function blitter to texture.c.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2020-04-23 02:04:56 +04:30 committed by Alexandre Julliard
parent 599a299288
commit 445d37f5d2
2 changed files with 389 additions and 390 deletions

View File

@ -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)
{

View File

@ -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;
}