svga: better path for generating white pixels for xor logicop workaround

This commit is contained in:
Keith Whitwell 2010-01-27 13:48:21 +00:00
parent 2f28ca0a27
commit 5cb255f0d7
6 changed files with 76 additions and 107 deletions

View file

@ -215,7 +215,6 @@ struct pipe_context *svga_context_create( struct pipe_screen *screen )
svga->state.hw_draw.num_views = 0;
svga->dirty = ~0;
svga->state.white_fs_id = SVGA3D_INVALID_ID;
LIST_INITHEAD(&svga->dirty_buffers);

View file

@ -329,10 +329,6 @@ struct svga_context
unsigned texture_timestamp;
/* Internally generated shaders:
*/
unsigned white_fs_id;
/*
*/
struct svga_sw_state sw;

View file

@ -103,70 +103,6 @@ fail:
return ret;
}
/* The blend workaround for simulating logicop xor behaviour requires
* that the incoming fragment color be white. This change achieves
* that by hooking up a hard-wired fragment shader that just emits
* color 1,1,1,1
*
* This is a slightly incomplete solution as it assumes that the
* actual bound shader has no other effects beyond generating a
* fragment color. In particular shaders containing TEXKIL and/or
* depth-write will not have the correct behaviour, nor will those
* expecting to use alphatest.
*
* These are avoidable issues, but they are not much worse than the
* unavoidable ones associated with this technique, so it's not clear
* how much effort should be expended trying to resolve them - the
* ultimate result will still not be correct in most cases.
*
* Shader below was generated with:
* SVGA_DEBUG=tgsi ./mesa/progs/fp/fp-tri white.txt
*/
static int emit_white_fs( struct svga_context *svga )
{
int ret = PIPE_ERROR;
/* ps_3_0
* def c0, 1.000000, 0.000000, 0.000000, 1.000000
* mov oC0, c0.x
* end
*/
static const unsigned white_tokens[] = {
0xffff0300,
0x05000051,
0xa00f0000,
0x3f800000,
0x00000000,
0x00000000,
0x3f800000,
0x02000001,
0x800f0800,
0xa0000000,
0x0000ffff,
};
assert(SVGA3D_INVALID_ID == UTIL_BITMASK_INVALID_INDEX);
svga->state.white_fs_id = util_bitmask_add(svga->fs_bm);
if(svga->state.white_fs_id == SVGA3D_INVALID_ID)
goto no_fs_id;
ret = SVGA3D_DefineShader(svga->swc,
svga->state.white_fs_id,
SVGA3D_SHADERTYPE_PS,
white_tokens,
sizeof(white_tokens));
if (ret)
goto no_definition;
return 0;
no_definition:
util_bitmask_clear(svga->fs_bm, svga->state.white_fs_id);
svga->state.white_fs_id = SVGA3D_INVALID_ID;
no_fs_id:
return ret;
}
/* SVGA_NEW_TEXTURE_BINDING
* SVGA_NEW_RAST
@ -194,6 +130,23 @@ static int make_fs_key( const struct svga_context *svga,
PIPE_WINDING_CW);
}
/* The blend workaround for simulating logicop xor behaviour
* requires that the incoming fragment color be white. This change
* achieves that by creating a varient of the current fragment
* shader that overrides all output colors with 1,1,1,1
*
* This will work for most shaders, including those containing
* TEXKIL and/or depth-write. However, it will break on the
* combination of xor-logicop plus alphatest.
*
* Ultimately, we could implement alphatest in the shader using
* texkil prior to overriding the outgoing fragment color.
*
* SVGA_NEW_BLEND
*/
if (svga->curr.blend->need_white_fragments) {
key->white_fragments = 1;
}
/* XXX: want to limit this to the textures that the shader actually
* refers to.
@ -233,40 +186,29 @@ static int emit_hw_fs( struct svga_context *svga,
unsigned id = SVGA3D_INVALID_ID;
int ret = 0;
/* SVGA_NEW_BLEND
*/
if (svga->curr.blend->need_white_fragments) {
if (svga->state.white_fs_id == SVGA3D_INVALID_ID) {
ret = emit_white_fs( svga );
if (ret)
return ret;
}
id = svga->state.white_fs_id;
}
else {
struct svga_fragment_shader *fs = svga->curr.fs;
struct svga_fs_compile_key key;
struct svga_fragment_shader *fs = svga->curr.fs;
struct svga_fs_compile_key key;
/* SVGA_NEW_TEXTURE_BINDING
* SVGA_NEW_RAST
* SVGA_NEW_NEED_SWTNL
* SVGA_NEW_SAMPLER
*/
ret = make_fs_key( svga, &key );
/* SVGA_NEW_BLEND
* SVGA_NEW_TEXTURE_BINDING
* SVGA_NEW_RAST
* SVGA_NEW_NEED_SWTNL
* SVGA_NEW_SAMPLER
*/
ret = make_fs_key( svga, &key );
if (ret)
return ret;
result = search_fs_key( fs, &key );
if (!result) {
ret = compile_fs( svga, fs, &key, &result );
if (ret)
return ret;
result = search_fs_key( fs, &key );
if (!result) {
ret = compile_fs( svga, fs, &key, &result );
if (ret)
return ret;
}
assert (result);
id = result->id;
}
assert (result);
id = result->id;
assert(id != SVGA3D_INVALID_ID);
if (result != svga->state.hw_draw.fs) {

View file

@ -49,6 +49,7 @@ struct svga_fs_compile_key
{
boolean light_twoside:1;
boolean front_cw:1;
boolean white_fragments:1;
ubyte num_textures;
ubyte num_unnormalized_coords;
struct {

View file

@ -194,8 +194,19 @@ static boolean ps30_output( struct svga_shader_emitter *emit,
switch (semantic.SemanticName) {
case TGSI_SEMANTIC_COLOR:
emit->output_map[idx] = dst_register( SVGA3DREG_COLOROUT,
semantic.SemanticIndex );
if (emit->unit == PIPE_SHADER_FRAGMENT &&
emit->key.fkey.white_fragments) {
emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,
emit->nr_hw_temp++ );
emit->temp_col[idx] = emit->output_map[idx];
emit->true_col[idx] = dst_register( SVGA3DREG_COLOROUT,
semantic.SemanticIndex );
}
else {
emit->output_map[idx] = dst_register( SVGA3DREG_COLOROUT,
semantic.SemanticIndex );
}
break;
case TGSI_SEMANTIC_POSITION:
emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,

View file

@ -1011,10 +1011,10 @@ static boolean emit_kilp(struct svga_shader_emitter *emit,
{
SVGA3dShaderInstToken inst;
SVGA3dShaderDestToken temp;
struct src_register one = get_zero_immediate( emit );
struct src_register one = scalar( get_zero_immediate( emit ),
TGSI_SWIZZLE_W );
inst = inst_token( SVGA3DOP_TEXKILL );
one = scalar( one, TGSI_SWIZZLE_W );
/* texkill doesn't allow negation on the operand so lets move
* negation of {1} to a temp register */
@ -2254,11 +2254,28 @@ static boolean emit_ps_postamble( struct svga_shader_emitter *emit )
for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
if (SVGA3dShaderGetRegType(emit->true_col[i].value) != 0) {
if (!submit_op1( emit,
inst_token(SVGA3DOP_MOV),
emit->true_col[i],
src(emit->temp_col[i]) ))
return FALSE;
/* Potentially override output colors with white for XOR
* logicop workaround.
*/
if (emit->unit == PIPE_SHADER_FRAGMENT &&
emit->key.fkey.white_fragments) {
struct src_register one = scalar( get_zero_immediate( emit ),
TGSI_SWIZZLE_W );
if (!submit_op1( emit,
inst_token(SVGA3DOP_MOV),
emit->true_col[i],
one ))
return FALSE;
}
else {
if (!submit_op1( emit,
inst_token(SVGA3DOP_MOV),
emit->true_col[i],
src(emit->temp_col[i]) ))
return FALSE;
}
}
}
@ -2467,6 +2484,9 @@ needs_to_create_zero( struct svga_shader_emitter *emit )
if (emit->key.fkey.light_twoside)
return TRUE;
if (emit->key.fkey.white_fragments)
return TRUE;
if (emit->emit_frontface)
return TRUE;