wined3d: Implement color keying in arbfp_blit.

This commit is contained in:
Stefan Dösinger 2015-04-10 12:05:53 +02:00 committed by Alexandre Julliard
parent 439076d591
commit 2d56694445
4 changed files with 99 additions and 29 deletions

View File

@ -6825,7 +6825,8 @@ struct arbfp_blit_type
{
enum complex_fixup fixup : 4;
enum wined3d_gl_resource_type res_type : 3;
DWORD padding : 25;
DWORD use_color_key : 1;
DWORD padding : 24;
};
struct arbfp_blit_desc
@ -6836,6 +6837,7 @@ struct arbfp_blit_desc
};
#define ARBFP_BLIT_PARAM_SIZE 0
#define ARBFP_BLIT_PARAM_COLOR_KEY 1
struct arbfp_blit_priv
{
@ -7287,6 +7289,11 @@ static GLuint gen_p8_shader(struct arbfp_blit_priv *priv,
GLint pos;
const char *tex_target = arbfp_texture_target(type->res_type);
/* This should not happen because we only use this conversion for
* present blits which don't use color keying. */
if (type->use_color_key)
FIXME("Implement P8 color keying.\n");
/* Shader header */
if (!shader_buffer_init(&buffer))
{
@ -7382,6 +7389,9 @@ static GLuint gen_yuv_shader(struct arbfp_blit_priv *priv, const struct wined3d_
char luminance_component;
GLint pos;
if (type->use_color_key)
FIXME("Implement YUV color keying.\n");
/* Shader header */
if (!shader_buffer_init(&buffer))
{
@ -7539,7 +7549,24 @@ static GLuint arbfp_gen_plain_shader(struct arbfp_blit_priv *priv,
GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader));
shader_addline(&buffer, "!!ARBfp1.0\n");
if (type->use_color_key)
{
shader_addline(&buffer, "TEMP color;\n");
shader_addline(&buffer, "TEMP compare;\n");
shader_addline(&buffer, "PARAM color_key = program.local[%u];\n", ARBFP_BLIT_PARAM_COLOR_KEY);
shader_addline(&buffer, "TEX color, fragment.texcoord[0], texture[0], %s;\n", tex_target);
shader_addline(&buffer, "SGE compare.r, color.a, color_key.a;\n");
shader_addline(&buffer, "SGE compare.g, -color.a, -color_key.a;\n");
shader_addline(&buffer, "MUL compare, compare.r, -compare.g;\n");
shader_addline(&buffer, "KIL compare;\n");
shader_addline(&buffer, "MOV result.color, color;\n");
}
else
{
shader_addline(&buffer, "TEX result.color, fragment.texcoord[0], texture[0], %s;\n", tex_target);
}
shader_addline(&buffer, "END\n");
GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
@ -7560,7 +7587,8 @@ static GLuint arbfp_gen_plain_shader(struct arbfp_blit_priv *priv,
}
/* Context activation is done by the caller. */
static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
const struct wined3d_color_key *color_key)
{
GLenum shader;
float size[4] = {(float) surface->pow2Width, (float) surface->pow2Height, 1.0f, 1.0f};
@ -7571,6 +7599,7 @@ static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context,
struct wine_rb_entry *entry;
struct arbfp_blit_type type;
struct arbfp_blit_desc *desc;
float float_color_key[4] = {0.0f, 0.0f, 0.0f, 0.0f};
if (is_complex_fixup(surface->resource.format->color_fixup))
fixup = get_complex_fixup(surface->resource.format->color_fixup);
@ -7604,7 +7633,7 @@ static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context,
type.res_type = WINED3D_GL_RES_TYPE_TEX_2D;
}
type.fixup = fixup;
type.padding = 0;
type.use_color_key = !!color_key;
entry = wine_rb_get(&priv->shaders, &type);
if (entry)
@ -7668,6 +7697,14 @@ err_out:
checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)");
GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARBFP_BLIT_PARAM_SIZE, size));
checkGLcall("glProgramLocalParameter4fvARB");
if (type.use_color_key)
{
if (surface->resource.format->id == WINED3DFMT_P8_UINT)
float_color_key[3] = color_key->color_space_low_value / 255.0f;
GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARBFP_BLIT_PARAM_COLOR_KEY, float_color_key));
checkGLcall("glProgramLocalParameter4fvARB");
}
return WINED3D_OK;
}
@ -7688,8 +7725,13 @@ static BOOL arbfp_blit_supported(const struct wined3d_gl_info *gl_info, enum win
if (!gl_info->supported[ARB_FRAGMENT_PROGRAM])
return FALSE;
if (blit_op != WINED3D_BLIT_OP_COLOR_BLIT)
switch (blit_op)
{
case WINED3D_BLIT_OP_COLOR_BLIT:
case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
break;
default:
TRACE("Unsupported blit_op=%d\n", blit_op);
return FALSE;
}
@ -7742,11 +7784,16 @@ static BOOL arbfp_blit_supported(const struct wined3d_gl_info *gl_info, enum win
HRESULT arbfp_blit_surface(struct wined3d_device *device, DWORD filter,
struct wined3d_surface *src_surface, const RECT *src_rect_in,
struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
struct wined3d_surface *dst_surface, const RECT *dst_rect_in,
const struct wined3d_color_key *color_key)
{
struct wined3d_context *context;
RECT src_rect = *src_rect_in;
RECT dst_rect = *dst_rect_in;
struct wined3d_color_key old_color_key = src_surface->container->async.src_blt_color_key;
DWORD old_color_key_flags = src_surface->container->async.color_key_flags;
wined3d_texture_set_color_key(src_surface->container, WINED3D_CKEY_SRC_BLT, color_key);
/* Activate the destination context, set it up for blitting */
context = context_acquire(device, dst_surface);
@ -7775,7 +7822,7 @@ HRESULT arbfp_blit_surface(struct wined3d_device *device, DWORD filter,
if (!wined3d_resource_is_offscreen(&dst_surface->container->resource))
surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
arbfp_blit_set(device->blit_priv, context, src_surface);
arbfp_blit_set(device->blit_priv, context, src_surface, color_key);
/* Draw a textured quad */
draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
@ -7793,6 +7840,9 @@ HRESULT arbfp_blit_surface(struct wined3d_device *device, DWORD filter,
surface_validate_location(dst_surface, dst_surface->container->resource.draw_binding);
surface_invalidate_location(dst_surface, ~dst_surface->container->resource.draw_binding);
wined3d_texture_set_color_key(src_surface->container, WINED3D_CKEY_SRC_BLT,
(old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_color_key : NULL);
return WINED3D_OK;
}

View File

@ -3398,7 +3398,7 @@ static void surface_blt_to_drawable(const struct wined3d_device *device,
if (!wined3d_resource_is_offscreen(&dst_surface->container->resource))
surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
device->blitter->set_shader(device->blit_priv, context, src_surface);
device->blitter->set_shader(device->blit_priv, context, src_surface, NULL);
if (alpha_test)
{
@ -4290,7 +4290,8 @@ static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK
static void ffp_blit_free(struct wined3d_device *device) { }
/* Context activation is done by the caller. */
static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
const struct wined3d_color_key *color_key)
{
const struct wined3d_gl_info *gl_info = context->gl_info;
@ -4324,6 +4325,7 @@ static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined
switch (blit_op)
{
case WINED3D_BLIT_OP_COLOR_BLIT:
case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
return FALSE;
@ -4434,7 +4436,8 @@ static void cpu_blit_free(struct wined3d_device *device)
}
/* Context activation is done by the caller. */
static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
const struct wined3d_color_key *color_key)
{
return WINED3D_OK;
}
@ -5078,6 +5081,8 @@ HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const REC
static const DWORD simple_blit = WINEDDBLT_ASYNC
| WINEDDBLT_COLORFILL
| WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_WAIT
| WINEDDBLT_DEPTHFILL
| WINEDDBLT_DONOTWAIT;
@ -5290,12 +5295,24 @@ HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const REC
}
else
{
TRACE("Color blit.\n");
enum wined3d_blit_op blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
const struct wined3d_color_key *color_key = NULL;
/* Upload */
if ((src_surface->locations & WINED3D_LOCATION_SYSMEM)
TRACE("Color blit.\n");
if (flags & WINEDDBLT_KEYSRCOVERRIDE)
{
color_key = &fx->ddckSrcColorkey;
blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
}
else if (flags & WINEDDBLT_KEYSRC)
{
color_key = &src_surface->container->async.src_blt_color_key;
blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
}
else if ((src_surface->locations & WINED3D_LOCATION_SYSMEM)
&& !(dst_surface->locations & WINED3D_LOCATION_SYSMEM))
{
/* Upload */
if (scale)
TRACE("Not doing upload because of scaling.\n");
else if (convert)
@ -5312,17 +5329,16 @@ HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const REC
}
}
}
else if (dst_swapchain && dst_swapchain->back_buffers
&& dst_surface->container == dst_swapchain->front_buffer
&& src_surface->container == dst_swapchain->back_buffers[0])
{
/* Use present for back -> front blits. The idea behind this is
* that present is potentially faster than a blit, in particular
* when FBO blits aren't available. Some ddraw applications like
* Half-Life and Prince of Persia 3D use Blt() from the backbuffer
* to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
* applications can't blit directly to the frontbuffer. */
if (dst_swapchain && dst_swapchain->back_buffers
&& dst_surface->container == dst_swapchain->front_buffer
&& src_surface->container == dst_swapchain->back_buffers[0])
{
enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
TRACE("Using present for backbuffer -> frontbuffer blit.\n");
@ -5336,7 +5352,7 @@ HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const REC
return WINED3D_OK;
}
if (fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
if (fbo_blit_supported(&device->adapter->gl_info, blit_op,
&src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
&dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
{
@ -5351,13 +5367,14 @@ HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const REC
return WINED3D_OK;
}
if (arbfp_blit.blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
if (arbfp_blit.blit_supported(&device->adapter->gl_info, blit_op,
&src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
&dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
{
TRACE("Using arbfp blit.\n");
if (SUCCEEDED(arbfp_blit_surface(device, filter, src_surface, &src_rect, dst_surface, &dst_rect)))
if (SUCCEEDED(arbfp_blit_surface(device, filter, src_surface, &src_rect,
dst_surface, &dst_rect, color_key)))
return WINED3D_OK;
}
}

View File

@ -367,7 +367,7 @@ static void swapchain_blit(const struct wined3d_swapchain *swapchain,
/* Set up the texture. The surface is not in a wined3d_texture
* container, so there are no D3D texture settings to dirtify. */
device->blitter->set_shader(device->blit_priv, context2, backbuffer);
device->blitter->set_shader(device->blit_priv, context2, backbuffer, NULL);
gl_info->gl_ops.gl.p_glTexParameteri(backbuffer->texture_target, GL_TEXTURE_MIN_FILTER, gl_filter);
gl_info->gl_ops.gl.p_glTexParameteri(backbuffer->texture_target, GL_TEXTURE_MAG_FILTER, gl_filter);

View File

@ -1323,6 +1323,7 @@ HRESULT compile_state_table(struct StateEntry *StateTable, APPLYSTATEFUNC **dev_
enum wined3d_blit_op
{
WINED3D_BLIT_OP_COLOR_BLIT,
WINED3D_BLIT_OP_COLOR_BLIT_CKEY,
WINED3D_BLIT_OP_COLOR_FILL,
WINED3D_BLIT_OP_DEPTH_FILL,
WINED3D_BLIT_OP_DEPTH_BLIT,
@ -1334,7 +1335,8 @@ struct blit_shader
{
HRESULT (*alloc_private)(struct wined3d_device *device);
void (*free_private)(struct wined3d_device *device);
HRESULT (*set_shader)(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface);
HRESULT (*set_shader)(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
const struct wined3d_color_key *color_key);
void (*unset_shader)(const struct wined3d_gl_info *gl_info);
BOOL (*blit_supported)(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
@ -1357,7 +1359,8 @@ const struct blit_shader *wined3d_select_blitter(const struct wined3d_gl_info *g
/* Temporary blit_shader helper functions */
HRESULT arbfp_blit_surface(struct wined3d_device *device, DWORD filter,
struct wined3d_surface *src_surface, const RECT *src_rect,
struct wined3d_surface *dst_surface, const RECT *dst_rect) DECLSPEC_HIDDEN;
struct wined3d_surface *dst_surface, const RECT *dst_rect,
const struct wined3d_color_key *color_key) DECLSPEC_HIDDEN;
struct wined3d_context *context_acquire(const struct wined3d_device *device,
struct wined3d_surface *target) DECLSPEC_HIDDEN;