mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-24 13:10:10 +01:00
r300g: add texture compare modes
This commit is contained in:
parent
4b6dee0865
commit
6ba83cd63f
6 changed files with 148 additions and 37 deletions
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue