/*
* Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com>
* Joakim Sindholt <opensource@zhasha.com>
+ * Copyright 2009 Marek Olšák <maraeo@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE. */
+#include "tgsi/tgsi_dump.h"
+
+#include "r300_context.h"
+#include "r300_screen.h"
#include "r300_fs.h"
+#include "r300_tgsi_to_rc.h"
-void r300_translate_fragment_shader(struct r300_context* r300,
- struct r300_fragment_shader* fs)
+#include "radeon_code.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)
{
- 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];
+ unsigned index;
- 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;
- }
+ r300_shader_semantics_reset(fs_inputs);
- tgsi_parse_init(&parser, fs->state.tokens);
+ for (i = 0; i < info->num_inputs; i++) {
+ index = info->input_semantic_index[i];
- while (!tgsi_parse_end_of_tokens(&parser)) {
- tgsi_parse_token(&parser);
+ switch (info->input_semantic_name[i]) {
+ case TGSI_SEMANTIC_COLOR:
+ assert(index <= ATTR_COLOR_COUNT);
+ fs_inputs->color[index] = i;
+ break;
- /* 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);
+ case TGSI_SEMANTIC_GENERIC:
+ assert(index <= ATTR_GENERIC_COUNT);
+ fs_inputs->generic[index] = 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.ImmediateFloat32[i]
- .Float;
- }
- assembler->imm_count++;
+
+ case TGSI_SEMANTIC_FOG:
+ assert(index == 0);
+ fs_inputs->fog = i;
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+}
+
+
+static void find_output_registers(struct r300_fragment_program_compiler * compiler,
+ struct r300_fragment_shader * fs)
+{
+ unsigned i;
+
+ /* Mark the outputs as not present initially */
+ compiler->OutputColor = fs->info.num_outputs;
+ compiler->OutputDepth = fs->info.num_outputs;
+
+ /* 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_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_POSITION:
+ compiler->OutputDepth = i;
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);
+static void allocate_hardware_inputs(
+ struct r300_fragment_program_compiler * c,
+ void (*allocate)(void * data, unsigned input, unsigned hwreg),
+ void * mydata)
+{
+ struct r300_shader_semantics* inputs =
+ &((struct r300_fragment_shader*)c->UserData)->inputs;
+ int i, reg = 0;
+
+ /* Allocate input registers. */
+ for (i = 0; i < ATTR_COLOR_COUNT; i++) {
+ if (inputs->color[i] != ATTR_UNUSED) {
+ allocate(mydata, inputs->color[i], reg++);
+ }
+ }
+ for (i = 0; i < ATTR_GENERIC_COUNT; i++) {
+ if (inputs->generic[i] != ATTR_UNUSED) {
+ allocate(mydata, inputs->generic[i], reg++);
+ }
+ }
+ if (inputs->fog != ATTR_UNUSED) {
+ allocate(mydata, inputs->fog, reg++);
}
+}
+
+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;
+
+ /* 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.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.
+ */
+
+ find_output_registers(&compiler, fs);
+
+ if (compiler.Base.Debug) {
+ debug_printf("r300: Initial fragment program\n");
+ tgsi_dump(fs->state.tokens, 0);
+ }
+
+ /* Translate TGSI to our internal representation */
+ ttr.compiler = &compiler.Base;
+ ttr.info = &fs->info;
+
+ r300_tgsi_to_rc(&ttr, fs->state.tokens);
- tgsi_dump(fs->state.tokens, 0);
- /* XXX finish r300 dumper too */
- if (is_r500) {
- r5xx_fs_dump((struct r5xx_fragment_shader*)fs);
+ /* Invoke the compiler */
+ r3xx_compile_fragment_program(&compiler);
+ if (compiler.Base.Error) {
+ /* XXX failover maybe? */
+ DBG(r300, DBG_FP, "r300: Error compiling fragment program: %s\n",
+ compiler.Base.ErrorMsg);
+ assert(0);
}
- tgsi_parse_free(&parser);
- FREE(assembler);
+ /* And, finally... */
+ rc_destroy(&compiler.Base);
+ fs->translated = TRUE;
}