};
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 */
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]);
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;
}
* 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"
#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;
}
}
-
static void find_output_registers(struct r300_fragment_program_compiler * compiler,
struct r300_fragment_shader * fs)
{
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. */
}
}
-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);
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) {
/* 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;
}
#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;
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 */
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;
}
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;
}
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);
}
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) |
}
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,
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:
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;
}
}
/* 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)