r300g: add texture compare modes

This commit is contained in:
Marek Olšák 2009-12-16 06:07:39 +01:00 committed by Corbin Simpson
parent 4b6dee0865
commit 6ba83cd63f
6 changed files with 148 additions and 37 deletions

View file

@ -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 */

View file

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

View file

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

View file

@ -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 */

View file

@ -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,

View file

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