From 6ba83cd63f84a4d74dd679d62662d59533fd1bdb Mon Sep 17 00:00:00 2001 From: Marek Olšák Date: Wed, 16 Dec 2009 06:07:39 +0100 Subject: r300g: add texture compare modes --- src/gallium/drivers/r300/r300_context.h | 2 + src/gallium/drivers/r300/r300_emit.c | 17 +++-- src/gallium/drivers/r300/r300_fs.c | 102 +++++++++++++++++++++++------ src/gallium/drivers/r300/r300_fs.h | 32 ++++++--- src/gallium/drivers/r300/r300_state.c | 23 ++++++- src/gallium/drivers/r300/r300_tgsi_to_rc.c | 9 ++- 6 files changed, 148 insertions(+), 37 deletions(-) (limited to 'src/gallium') diff --git a/src/gallium/drivers/r300/r300_context.h b/src/gallium/drivers/r300/r300_context.h index 6bd2766730f..232530b7dc4 100644 --- a/src/gallium/drivers/r300/r300_context.h +++ b/src/gallium/drivers/r300/r300_context.h @@ -91,6 +91,8 @@ struct r300_rs_block { }; struct r300_sampler_state { + struct pipe_sampler_state state; + uint32_t filter0; /* R300_TX_FILTER0: 0x4400 */ uint32_t filter1; /* R300_TX_FILTER1: 0x4440 */ uint32_t border_color; /* R300_TX_BORDER_COLOR: 0x45c0 */ diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c index d7b6511d6d5..199ce3a945d 100644 --- a/src/gallium/drivers/r300/r300_emit.c +++ b/src/gallium/drivers/r300/r300_emit.c @@ -158,6 +158,13 @@ static const float * get_shader_constant( vec[1] = 1.0 / tex->height0; break; + /* Texture compare-fail value. */ + /* XXX Since Gallium doesn't support GL_ARB_shadow_ambient, + * this is always (0,0,0,0). */ + case RC_STATE_SHADOW_AMBIENT: + vec[3] = 0; + break; + default: debug_printf("r300: Implementation error: " "Unknown RC_CONSTANT type %d\n", constant->u.State[0]); @@ -1030,18 +1037,20 @@ validate: if (r300->dirty_state & R300_NEW_FRAGMENT_SHADER) { if (r300screen->caps->is_r500) { - r500_emit_fragment_program_code(r300, &r300->fs->code); + r500_emit_fragment_program_code(r300, &r300->fs->shader->code); } else { - r300_emit_fragment_program_code(r300, &r300->fs->code); + r300_emit_fragment_program_code(r300, &r300->fs->shader->code); } r300->dirty_state &= ~R300_NEW_FRAGMENT_SHADER; } if (r300->dirty_state & R300_NEW_FRAGMENT_SHADER_CONSTANTS) { if (r300screen->caps->is_r500) { - r500_emit_fs_constant_buffer(r300, &r300->fs->code.constants); + r500_emit_fs_constant_buffer(r300, + &r300->fs->shader->code.constants); } else { - r300_emit_fs_constant_buffer(r300, &r300->fs->code.constants); + r300_emit_fs_constant_buffer(r300, + &r300->fs->shader->code.constants); } r300->dirty_state &= ~R300_NEW_FRAGMENT_SHADER_CONSTANTS; } diff --git a/src/gallium/drivers/r300/r300_fs.c b/src/gallium/drivers/r300/r300_fs.c index 79b01bb4dc2..4e1b61ca409 100644 --- a/src/gallium/drivers/r300/r300_fs.c +++ b/src/gallium/drivers/r300/r300_fs.c @@ -22,6 +22,9 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "util/u_math.h" +#include "util/u_memory.h" + #include "tgsi/tgsi_dump.h" #include "r300_context.h" @@ -33,8 +36,8 @@ #include "radeon_compiler.h" /* Convert info about FS input semantics to r300_shader_semantics. */ -static void r300_shader_read_fs_inputs(struct tgsi_shader_info* info, - struct r300_shader_semantics* fs_inputs) +void r300_shader_read_fs_inputs(struct tgsi_shader_info* info, + struct r300_shader_semantics* fs_inputs) { int i; unsigned index; @@ -66,7 +69,6 @@ static void r300_shader_read_fs_inputs(struct tgsi_shader_info* info, } } - static void find_output_registers(struct r300_fragment_program_compiler * compiler, struct r300_fragment_shader * fs) { @@ -95,7 +97,7 @@ static void allocate_hardware_inputs( void * mydata) { struct r300_shader_semantics* inputs = - &((struct r300_fragment_shader*)c->UserData)->inputs; + (struct r300_shader_semantics*)c->UserData; int i, reg = 0; /* Allocate input registers. */ @@ -114,31 +116,45 @@ static void allocate_hardware_inputs( } } -void r300_translate_fragment_shader(struct r300_context* r300, - struct r300_fragment_shader* fs) +static void get_compare_state( + struct r300_context* r300, + struct r300_fragment_program_external_state* state, + unsigned shadow_samplers) +{ + memset(state, 0, sizeof(*state)); + + for (int i = 0; i < r300->sampler_count; i++) { + struct r300_sampler_state* s = r300->sampler_states[i]; + + if (s && s->state.compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { + /* XXX Gallium doesn't provide us with any information regarding + * this mode, so we are screwed. I'm setting 0 = LUMINANCE. */ + state->unit[i].depth_texture_mode = 0; + + /* Fortunately, no need to translate this. */ + state->unit[i].texture_compare_func = s->state.compare_func; + } + } +} + +static void r300_translate_fragment_shader( + struct r300_context* r300, + struct r300_fragment_shader_code* shader) { + struct r300_fragment_shader* fs = r300->fs; struct r300_fragment_program_compiler compiler; struct tgsi_to_rc ttr; - /* Initialize. */ - r300_shader_read_fs_inputs(&fs->info, &fs->inputs); - /* Setup the compiler. */ memset(&compiler, 0, sizeof(compiler)); rc_init(&compiler.Base); compiler.Base.Debug = DBG_ON(r300, DBG_FP); - compiler.code = &fs->code; + compiler.code = &shader->code; + compiler.state = shader->compare_state; compiler.is_r500 = r300_screen(r300->context.screen)->caps->is_r500; compiler.AllocateHwInputs = &allocate_hardware_inputs; - compiler.UserData = fs; - - /* XXX: Program compilation depends on texture compare modes, - * which are sampler state. Therefore, programs need to be recompiled - * depending on this state as in the classic Mesa driver. - * - * This is not yet handled correctly. - */ + compiler.UserData = &fs->inputs; find_output_registers(&compiler, fs); @@ -153,6 +169,8 @@ void r300_translate_fragment_shader(struct r300_context* r300, r300_tgsi_to_rc(&ttr, fs->state.tokens); + fs->shadow_samplers = compiler.Base.Program.ShadowSamplers; + /* Invoke the compiler */ r3xx_compile_fragment_program(&compiler); if (compiler.Base.Error) { @@ -164,5 +182,51 @@ void r300_translate_fragment_shader(struct r300_context* r300, /* And, finally... */ rc_destroy(&compiler.Base); - fs->translated = TRUE; +} + +boolean r300_pick_fragment_shader(struct r300_context* r300) +{ + struct r300_fragment_shader* fs = r300->fs; + struct r300_fragment_program_external_state state; + struct r300_fragment_shader_code* ptr; + + if (!fs->first) { + /* Build the fragment shader for the first time. */ + fs->first = fs->shader = CALLOC_STRUCT(r300_fragment_shader_code); + + /* BTW shadow samplers will be known after the first translation, + * therefore we set ~0, which means it should look at all sampler + * states. This choice doesn't have any impact on the correctness. */ + get_compare_state(r300, &fs->shader->compare_state, ~0); + r300_translate_fragment_shader(r300, fs->shader); + return TRUE; + + } else if (fs->shadow_samplers) { + get_compare_state(r300, &state, fs->shadow_samplers); + + /* Check if the currently-bound shader has been compiled + * with the texture-compare state we need. */ + if (memcmp(&fs->shader->compare_state, &state, sizeof(state)) != 0) { + /* Search for the right shader. */ + ptr = fs->first; + while (ptr) { + if (memcmp(&ptr->compare_state, &state, sizeof(state)) == 0) { + fs->shader = ptr; + return TRUE; + } + ptr = ptr->next; + } + + /* Not found, gotta compile a new one. */ + ptr = CALLOC_STRUCT(r300_fragment_shader_code); + ptr->next = fs->first; + fs->first = fs->shader = ptr; + + ptr->compare_state = state; + r300_translate_fragment_shader(r300, ptr); + return TRUE; + } + } + + return FALSE; } diff --git a/src/gallium/drivers/r300/r300_fs.h b/src/gallium/drivers/r300/r300_fs.h index 630e2d0c8a5..40ce874353c 100644 --- a/src/gallium/drivers/r300/r300_fs.h +++ b/src/gallium/drivers/r300/r300_fs.h @@ -30,6 +30,13 @@ #include "radeon_code.h" #include "r300_shader_semantics.h" +struct r300_fragment_shader_code { + struct r300_fragment_program_external_state compare_state; + struct rX00_fragment_program_code code; + + struct r300_fragment_shader_code* next; +}; + struct r300_fragment_shader { /* Parent class */ struct pipe_shader_state state; @@ -37,21 +44,28 @@ struct r300_fragment_shader { struct tgsi_shader_info info; struct r300_shader_semantics inputs; - /* Has this shader been translated yet? */ - boolean translated; + /* Bits 0-15: TRUE if it's a shadow sampler, FALSE otherwise. */ + unsigned shadow_samplers; - /* Compiled code */ - struct rX00_fragment_program_code code; + /* Currently-bound fragment shader. */ + struct r300_fragment_shader_code* shader; + + /* List of the same shaders compiled with different texture-compare + * states. */ + struct r300_fragment_shader_code* first; }; +void r300_shader_read_fs_inputs(struct tgsi_shader_info* info, + struct r300_shader_semantics* fs_inputs); -void r300_translate_fragment_shader(struct r300_context* r300, - struct r300_fragment_shader* fs); +/* Return TRUE if the shader was switched and should be re-emitted. */ +boolean r300_pick_fragment_shader(struct r300_context* r300); -static inline boolean r300_fragment_shader_writes_depth(struct r300_fragment_shader *fs) +static INLINE boolean r300_fragment_shader_writes_depth(struct r300_fragment_shader *fs) { if (!fs) - return FALSE; - return (fs->code.writes_depth) ? TRUE : FALSE; + return FALSE; + return (fs->shader->code.writes_depth) ? TRUE : FALSE; } + #endif /* R300_FS_H */ diff --git a/src/gallium/drivers/r300/r300_state.c b/src/gallium/drivers/r300/r300_state.c index 5f332b2e0c2..8bcd6c50608 100644 --- a/src/gallium/drivers/r300/r300_state.c +++ b/src/gallium/drivers/r300/r300_state.c @@ -355,6 +355,7 @@ static void* r300_create_fs_state(struct pipe_context* pipe, fs->state.tokens = tgsi_dup_tokens(shader->tokens); tgsi_scan_shader(shader->tokens, &fs->info); + r300_shader_read_fs_inputs(&fs->info, &fs->inputs); return (void*)fs; } @@ -368,11 +369,10 @@ static void r300_bind_fs_state(struct pipe_context* pipe, void* shader) if (fs == NULL) { r300->fs = NULL; return; - } else if (!fs->translated) { - r300_translate_fragment_shader(r300, fs); } r300->fs = fs; + r300_pick_fragment_shader(r300); r300->dirty_state |= R300_NEW_FRAGMENT_SHADER | R300_NEW_FRAGMENT_SHADER_CONSTANTS; } @@ -381,7 +381,14 @@ static void r300_bind_fs_state(struct pipe_context* pipe, void* shader) static void r300_delete_fs_state(struct pipe_context* pipe, void* shader) { struct r300_fragment_shader* fs = (struct r300_fragment_shader*)shader; - rc_constants_destroy(&fs->code.constants); + struct r300_fragment_shader_code *tmp, *ptr = fs->first; + + while (ptr) { + tmp = ptr; + ptr = ptr->next; + rc_constants_destroy(&tmp->code.constants); + FREE(tmp); + } FREE((void*)fs->state.tokens); FREE(shader); } @@ -547,6 +554,8 @@ static void* int lod_bias; union util_color uc; + sampler->state = *state; + sampler->filter0 |= (r300_translate_wrap(state->wrap_s) << R300_TX_WRAP_S_SHIFT) | (r300_translate_wrap(state->wrap_t) << R300_TX_WRAP_T_SHIFT) | @@ -597,6 +606,14 @@ static void r300_bind_sampler_states(struct pipe_context* pipe, } r300->sampler_count = count; + + /* Pick a fragment shader based on the texture compare state. */ + if (r300->fs && (r300->dirty_state & R300_ANY_NEW_SAMPLERS)) { + if (r300_pick_fragment_shader(r300)) { + r300->dirty_state |= R300_NEW_FRAGMENT_SHADER | + R300_NEW_FRAGMENT_SHADER_CONSTANTS; + } + } } static void r300_lacks_vertex_textures(struct pipe_context* pipe, diff --git a/src/gallium/drivers/r300/r300_tgsi_to_rc.c b/src/gallium/drivers/r300/r300_tgsi_to_rc.c index 9fb2de24032..096cdb20bbe 100644 --- a/src/gallium/drivers/r300/r300_tgsi_to_rc.c +++ b/src/gallium/drivers/r300/r300_tgsi_to_rc.c @@ -212,7 +212,8 @@ static void transform_srcreg( dst->Negate = src->Register.Negate ? RC_MASK_XYZW : 0; } -static void transform_texture(struct rc_instruction * dst, struct tgsi_instruction_texture src) +static void transform_texture(struct rc_instruction * dst, struct tgsi_instruction_texture src, + uint32_t *shadowSamplers) { switch(src.Texture) { case TGSI_TEXTURE_1D: @@ -233,14 +234,17 @@ static void transform_texture(struct rc_instruction * dst, struct tgsi_instructi case TGSI_TEXTURE_SHADOW1D: dst->U.I.TexSrcTarget = RC_TEXTURE_1D; dst->U.I.TexShadow = 1; + *shadowSamplers |= 1 << dst->U.I.TexSrcUnit; break; case TGSI_TEXTURE_SHADOW2D: dst->U.I.TexSrcTarget = RC_TEXTURE_2D; dst->U.I.TexShadow = 1; + *shadowSamplers |= 1 << dst->U.I.TexSrcUnit; break; case TGSI_TEXTURE_SHADOWRECT: dst->U.I.TexSrcTarget = RC_TEXTURE_RECT; dst->U.I.TexShadow = 1; + *shadowSamplers |= 1 << dst->U.I.TexSrcUnit; break; } } @@ -269,7 +273,8 @@ static void transform_instruction(struct tgsi_to_rc * ttr, struct tgsi_full_inst /* Texturing. */ if (src->Instruction.Texture) - transform_texture(dst, src->Texture); + transform_texture(dst, src->Texture, + &ttr->compiler->Program.ShadowSamplers); } static void handle_immediate(struct tgsi_to_rc * ttr, struct tgsi_full_immediate * imm) -- cgit v1.2.3