r300g: implement gl_FrontFacing
authorMarek Olšák <maraeo@gmail.com>
Tue, 10 Aug 2010 12:21:05 +0000 (14:21 +0200)
committerMarek Olšák <maraeo@gmail.com>
Wed, 11 Aug 2010 02:48:56 +0000 (04:48 +0200)
src/gallium/drivers/r300/r300_fs.c
src/gallium/drivers/r300/r300_shader_semantics.h
src/gallium/drivers/r300/r300_state_derived.c
src/mesa/drivers/dri/r300/compiler/radeon_compiler.c
src/mesa/drivers/dri/r300/compiler/radeon_compiler.h

index 5c905c11596e140c17c450bc28052eb56a244c57..2a0c30620adf4f4cac91fdb35f3f1b0911ff79f8 100644 (file)
@@ -72,6 +72,11 @@ void r300_shader_read_fs_inputs(struct tgsi_shader_info* info,
                 fs_inputs->wpos = i;
                 break;
 
+            case TGSI_SEMANTIC_FACE:
+                assert(index == 0);
+                fs_inputs->face = i;
+                break;
+
             default:
                 fprintf(stderr, "r300: FP: Unknown input semantic: %i\n",
                         info->input_semantic_name[i]);
@@ -120,6 +125,9 @@ static void allocate_hardware_inputs(
             allocate(mydata, inputs->color[i], reg++);
         }
     }
+    if (inputs->face != ATTR_UNUSED) {
+        allocate(mydata, inputs->face, reg++);
+    }
     for (i = 0; i < ATTR_GENERIC_COUNT; i++) {
         if (inputs->generic[i] != ATTR_UNUSED) {
             allocate(mydata, inputs->generic[i], reg++);
@@ -360,13 +368,14 @@ static void r300_translate_fragment_shader(
 {
     struct r300_fragment_program_compiler compiler;
     struct tgsi_to_rc ttr;
-    int wpos;
+    int wpos, face;
     unsigned i;
 
     tgsi_scan_shader(tokens, &shader->info);
     r300_shader_read_fs_inputs(&shader->info, &shader->inputs);
 
     wpos = shader->inputs.wpos;
+    face = shader->inputs.face;
 
     /* Setup the compiler. */
     memset(&compiler, 0, sizeof(compiler));
@@ -406,6 +415,10 @@ static void r300_translate_fragment_shader(
         rc_transform_fragment_wpos(&compiler.Base, wpos, wpos, TRUE);
     }
 
+    if (face != ATTR_UNUSED) {
+        rc_transform_fragment_face(&compiler.Base, face);
+    }
+
     /* Invoke the compiler */
     r3xx_compile_fragment_program(&compiler);
 
index cb7a37033f3117ac1fe7403f7db861cdd8e4de75..4be23e64ce79efbbedc57316887a166e1f92d0fc 100644 (file)
@@ -38,6 +38,7 @@ struct r300_shader_semantics {
     int psize;
     int color[ATTR_COLOR_COUNT];
     int bcolor[ATTR_COLOR_COUNT];
+    int face;
     int generic[ATTR_GENERIC_COUNT];
     int fog;
     int wpos;
@@ -50,6 +51,7 @@ static INLINE void r300_shader_semantics_reset(
 
     info->pos = ATTR_UNUSED;
     info->psize = ATTR_UNUSED;
+    info->face = ATTR_UNUSED;
     info->fog = ATTR_UNUSED;
     info->wpos = ATTR_UNUSED;
 
index 1f36e7758fdcdd47916d6d065f43ef523ea2abe3..39000477cb0506a5487965f895619e189edd6a40 100644 (file)
@@ -46,6 +46,11 @@ enum r300_rs_swizzle {
     SWIZ_0001,
 };
 
+enum r300_rs_col_write_type {
+    WRITE_COLOR = 0,
+    WRITE_FACE
+};
+
 static void r300_draw_emit_attrib(struct r300_context* r300,
                                   enum attrib_emit emit,
                                   enum interp_mode interp,
@@ -203,8 +208,10 @@ static void r300_rs_col(struct r300_rs_block* rs, int id, int ptr,
     rs->inst[id] |= R300_RS_INST_COL_ID(id);
 }
 
-static void r300_rs_col_write(struct r300_rs_block* rs, int id, int fp_offset)
+static void r300_rs_col_write(struct r300_rs_block* rs, int id, int fp_offset,
+                              enum r300_rs_col_write_type type)
 {
+    assert(type != WRITE_COLOR);
     rs->inst[id] |= R300_RS_INST_COL_CN_WRITE |
                     R300_RS_INST_COL_ADDR(fp_offset);
 }
@@ -252,10 +259,16 @@ static void r500_rs_col(struct r300_rs_block* rs, int id, int ptr,
     rs->inst[id] |= R500_RS_INST_COL_ID(id);
 }
 
-static void r500_rs_col_write(struct r300_rs_block* rs, int id, int fp_offset)
+static void r500_rs_col_write(struct r300_rs_block* rs, int id, int fp_offset,
+                              enum r300_rs_col_write_type type)
 {
-    rs->inst[id] |= R500_RS_INST_COL_CN_WRITE |
-                    R500_RS_INST_COL_ADDR(fp_offset);
+    if (type == WRITE_FACE)
+        rs->inst[id] |= R500_RS_INST_COL_CN_WRITE_BACKFACE |
+                        R500_RS_INST_COL_ADDR(fp_offset);
+    else
+        rs->inst[id] |= R500_RS_INST_COL_CN_WRITE |
+                        R500_RS_INST_COL_ADDR(fp_offset);
+
 }
 
 static void r500_rs_tex(struct r300_rs_block* rs, int id, int ptr,
@@ -305,7 +318,7 @@ static void r300_update_rs_block(struct r300_context *r300)
     struct r300_rs_block rs = {0};
     int i, col_count = 0, tex_count = 0, fp_offset = 0, count, loc = 0, tex_ptr = 0;
     void (*rX00_rs_col)(struct r300_rs_block*, int, int, enum r300_rs_swizzle);
-    void (*rX00_rs_col_write)(struct r300_rs_block*, int, int);
+    void (*rX00_rs_col_write)(struct r300_rs_block*, int, int, enum r300_rs_col_write_type);
     void (*rX00_rs_tex)(struct r300_rs_block*, int, int, enum r300_rs_swizzle);
     void (*rX00_rs_tex_write)(struct r300_rs_block*, int, int);
     boolean any_bcolor_used = vs_outputs->bcolor[0] != ATTR_UNUSED ||
@@ -350,7 +363,7 @@ static void r300_update_rs_block(struct r300_context *r300)
 
             /* Write it to the FS input register if it's needed by the FS. */
             if (fs_inputs->color[i] != ATTR_UNUSED) {
-                rX00_rs_col_write(&rs, col_count, fp_offset);
+                rX00_rs_col_write(&rs, col_count, fp_offset, WRITE_COLOR);
                 fp_offset++;
 
                 DBG(r300, DBG_RS,
@@ -398,6 +411,24 @@ static void r300_update_rs_block(struct r300_context *r300)
         }
     }
 
+    /* gl_FrontFacing.
+     * Note that we can use either the two-sided color selection based on
+     * the front and back vertex shader colors, or gl_FrontFacing,
+     * but not both! It locks up otherwise.
+     *
+     * In Direct3D 9, the two-sided color selection can be used
+     * with shaders 2.0 only, while gl_FrontFacing can be used
+     * with shaders 3.0 only. The hardware apparently hasn't been designed
+     * to support both at the same time. */
+    if (r300->screen->caps.is_r500 && fs_inputs->face != ATTR_UNUSED &&
+        !(any_bcolor_used && r300->two_sided_color)) {
+        rX00_rs_col(&rs, col_count, col_count, SWIZ_XYZW);
+        rX00_rs_col_write(&rs, col_count, fp_offset, WRITE_FACE);
+        fp_offset++;
+        col_count++;
+        DBG(r300, DBG_RS, "r300: Rasterized FACE written to FS.\n");
+    }
+
     /* Rasterize texture coordinates. */
     for (i = 0; i < ATTR_GENERIC_COUNT && tex_count < 8; i++) {
        bool sprite_coord = !!(r300->sprite_coord_enable & (1 << i));
index 1c8ba864a41ef518cc0462254cd605206a379daa..935dc9b0a806e5e9f6a8e2c8c686eb7f589c5405 100644 (file)
@@ -307,3 +307,46 @@ void rc_transform_fragment_wpos(struct radeon_compiler * c, unsigned wpos, unsig
        }
 }
 
+
+/**
+ * The FACE input in hardware contains 1 if it's a back face, 0 otherwise.
+ * Gallium and OpenGL define it the other way around.
+ *
+ * So let's just negate FACE at the beginning of the shader and rewrite the rest
+ * of the shader to read from the newly allocated temporary.
+ */
+void rc_transform_fragment_face(struct radeon_compiler *c, unsigned face)
+{
+       unsigned tempregi = rc_find_free_temporary(c);
+       struct rc_instruction *inst_add;
+       struct rc_instruction *inst;
+
+       /* perspective divide */
+       inst_add = rc_insert_new_instruction(c, &c->Program.Instructions);
+       inst_add->U.I.Opcode = RC_OPCODE_ADD;
+
+       inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY;
+       inst_add->U.I.DstReg.Index = tempregi;
+       inst_add->U.I.DstReg.WriteMask = RC_MASK_X;
+
+       inst_add->U.I.SrcReg[0].File = RC_FILE_NONE;
+       inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_1111;
+
+       inst_add->U.I.SrcReg[1].File = RC_FILE_INPUT;
+       inst_add->U.I.SrcReg[1].Index = face;
+       inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XXXX;
+       inst_add->U.I.SrcReg[1].Negate = RC_MASK_XYZW;
+
+       for (inst = inst_add->Next; inst != &c->Program.Instructions; inst = inst->Next) {
+               const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
+               unsigned i;
+
+               for(i = 0; i < opcode->NumSrcRegs; i++) {
+                       if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT &&
+                           inst->U.I.SrcReg[i].Index == face) {
+                               inst->U.I.SrcReg[i].File = RC_FILE_TEMPORARY;
+                               inst->U.I.SrcReg[i].Index = tempregi;
+                       }
+               }
+       }
+}
index e15291dd19745f504da108b2ef879e29e5047cb5..7c42eb3ae5783e88e9a608e6b9649b46183c7aad 100644 (file)
@@ -81,6 +81,7 @@ void rc_move_output(struct radeon_compiler * c, unsigned output, unsigned new_ou
 void rc_copy_output(struct radeon_compiler * c, unsigned output, unsigned dup_output);
 void rc_transform_fragment_wpos(struct radeon_compiler * c, unsigned wpos, unsigned new_input,
                                 int full_vtransform);
+void rc_transform_fragment_face(struct radeon_compiler *c, unsigned face);
 
 struct r300_fragment_program_compiler {
        struct radeon_compiler Base;