summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/r300/r300_fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/r300/r300_fs.c')
-rw-r--r--src/gallium/drivers/r300/r300_fs.c162
1 files changed, 94 insertions, 68 deletions
diff --git a/src/gallium/drivers/r300/r300_fs.c b/src/gallium/drivers/r300/r300_fs.c
index ca8ef99902..36463b9a2e 100644
--- a/src/gallium/drivers/r300/r300_fs.c
+++ b/src/gallium/drivers/r300/r300_fs.c
@@ -23,89 +23,115 @@
#include "r300_fs.h"
-void r300_translate_fragment_shader(struct r300_context* r300,
- struct r300_fragment_shader* fs)
-{
- struct tgsi_parse_context parser;
- int i;
- boolean is_r500 = r300_screen(r300->context.screen)->caps->is_r500;
- struct r300_constant_buffer* consts =
- &r300->shader_constants[PIPE_SHADER_FRAGMENT];
+#include "r300_tgsi_to_rc.h"
- struct r300_fs_asm* assembler = CALLOC_STRUCT(r300_fs_asm);
- if (assembler == NULL) {
- return;
- }
- /* Setup starting offset for immediates. */
- assembler->imm_offset = consts->user_count;
- /* Enable depth writes, if needed. */
- assembler->writes_depth = fs->info.writes_z;
-
- /* Make sure we start at the beginning of the shader. */
- if (is_r500) {
- ((struct r5xx_fragment_shader*)fs)->instruction_count = 0;
- }
+#include "radeon_compiler.h"
- tgsi_parse_init(&parser, fs->state.tokens);
+static void find_output_registers(struct r300_fragment_program_compiler * compiler,
+ struct r300_fragment_shader * fs)
+{
+ unsigned i;
- while (!tgsi_parse_end_of_tokens(&parser)) {
- tgsi_parse_token(&parser);
+ /* Mark the outputs as not present initially */
+ compiler->OutputColor = fs->info.num_outputs;
+ compiler->OutputDepth = fs->info.num_outputs;
- /* This is seriously the lamest way to create fragment programs ever.
- * I blame TGSI. */
- switch (parser.FullToken.Token.Type) {
- case TGSI_TOKEN_TYPE_DECLARATION:
- /* Allocated registers sitting at the beginning
- * of the program. */
- r300_fs_declare(assembler, &parser.FullToken.FullDeclaration);
+ /* Now see where they really are. */
+ for(i = 0; i < fs->info.num_outputs; ++i) {
+ switch(fs->info.output_semantic_name[i]) {
+ case TGSI_SEMANTIC_COLOR:
+ compiler->OutputColor = i;
+ break;
+ case TGSI_SEMANTIC_POSITION:
+ compiler->OutputDepth = i;
break;
- case TGSI_TOKEN_TYPE_IMMEDIATE:
- debug_printf("r300: Emitting immediate to constant buffer, "
- "position %d\n",
- assembler->imm_offset + assembler->imm_count);
- /* I am not amused by the length of these. */
- for (i = 0; i < 4; i++) {
- consts->constants[assembler->imm_offset +
- assembler->imm_count][i] =
- parser.FullToken.FullImmediate.u[i].Float;
- }
- assembler->imm_count++;
+ }
+ }
+}
+
+static void allocate_hardware_inputs(
+ struct r300_fragment_program_compiler * c,
+ void (*allocate)(void * data, unsigned input, unsigned hwreg),
+ void * mydata)
+{
+ struct tgsi_shader_info* info = &((struct r300_fragment_shader*)c->UserData)->info;
+ int total_colors = 0;
+ int colors = 0;
+ int total_generic = 0;
+ int generic = 0;
+ int i;
+
+ for (i = 0; i < info->num_inputs; i++) {
+ switch (info->input_semantic_name[i]) {
+ case TGSI_SEMANTIC_COLOR:
+ total_colors++;
break;
- case TGSI_TOKEN_TYPE_INSTRUCTION:
- if (is_r500) {
- r5xx_fs_instruction((struct r5xx_fragment_shader*)fs,
- assembler, &parser.FullToken.FullInstruction);
- } else {
- r3xx_fs_instruction((struct r3xx_fragment_shader*)fs,
- assembler, &parser.FullToken.FullInstruction);
- }
+ case TGSI_SEMANTIC_FOG:
+ case TGSI_SEMANTIC_GENERIC:
+ total_generic++;
break;
}
}
- debug_printf("r300: fs: %d texs and %d colors, first free reg is %d\n",
- assembler->tex_count, assembler->color_count,
- assembler->tex_count + assembler->color_count);
-
- consts->count = consts->user_count + assembler->imm_count;
- fs->uses_imms = assembler->imm_count;
- debug_printf("r300: fs: %d total constants, "
- "%d from user and %d from immediates\n", consts->count,
- consts->user_count, assembler->imm_count);
- r3xx_fs_finalize(fs, assembler);
- if (is_r500) {
- r5xx_fs_finalize((struct r5xx_fragment_shader*)fs, assembler);
+ for(i = 0; i < info->num_inputs; i++) {
+ switch (info->input_semantic_name[i]) {
+ case TGSI_SEMANTIC_COLOR:
+ allocate(mydata, i, colors);
+ colors++;
+ break;
+ case TGSI_SEMANTIC_FOG:
+ case TGSI_SEMANTIC_GENERIC:
+ allocate(mydata, i, total_colors + generic);
+ generic++;
+ break;
+ }
}
+}
+
+void r300_translate_fragment_shader(struct r300_context* r300,
+ struct r300_fragment_shader* fs)
+{
+ struct r300_fragment_program_compiler compiler;
+ struct tgsi_to_rc ttr;
- tgsi_dump(fs->state.tokens, 0);
- /* XXX finish r300 dumper too */
- if (is_r500) {
- r5xx_fs_dump((struct r5xx_fragment_shader*)fs);
+ memset(&compiler, 0, sizeof(compiler));
+ rc_init(&compiler.Base);
+ compiler.Base.Debug = 1;
+
+ compiler.code = &fs->code;
+ compiler.is_r500 = r300_screen(r300->context.screen)->caps->is_r500;
+ compiler.AllocateHwInputs = &allocate_hardware_inputs;
+ compiler.UserData = fs;
+
+ /* TODO: 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.
+ */
+
+ find_output_registers(&compiler, fs);
+
+ if (compiler.Base.Debug) {
+ debug_printf("r300: Initial fragment program\n");
+ tgsi_dump(fs->state.tokens, 0);
}
- tgsi_parse_free(&parser);
- FREE(assembler);
+ /* Translate TGSI to our internal representation */
+ ttr.compiler = &compiler.Base;
+ ttr.info = &fs->info;
+
+ r300_tgsi_to_rc(&ttr, fs->state.tokens);
+
+ /* Invoke the compiler */
+ r3xx_compile_fragment_program(&compiler);
+ if (compiler.Base.Error) {
+ /* Todo: Fail gracefully */
+ fprintf(stderr, "r300 FP: Compiler error\n");
+ abort();
+ }
/* And, finally... */
+ rc_destroy(&compiler.Base);
fs->translated = TRUE;
}