Merge branch 'master' of ../mesa into vulkan
[mesa.git] / src / gallium / drivers / r600 / sb / sb_bc_parser.cpp
index a7e712816b121866adbd18667f0f585f9b8a287c..19bd0784a61eb5c1bc64bff6a4853ba012f2b6f8 100644 (file)
 #define BCP_DUMP(q)
 #endif
 
-extern "C" {
 #include "r600_pipe.h"
 #include "r600_shader.h"
-}
 
 #include <stack>
 
@@ -58,7 +56,10 @@ int bc_parser::decode() {
        if (pshader) {
                switch (bc->type) {
                case TGSI_PROCESSOR_FRAGMENT: t = TARGET_PS; break;
-               case TGSI_PROCESSOR_VERTEX: t = TARGET_VS; break;
+               case TGSI_PROCESSOR_VERTEX:
+                       t = pshader->vs_as_es ? TARGET_ES : TARGET_VS;
+                       break;
+               case TGSI_PROCESSOR_GEOMETRY: t = TARGET_GS; break;
                case TGSI_PROCESSOR_COMPUTE: t = TARGET_COMPUTE; break;
                default: assert(!"unknown shader target"); return -1; break;
                }
@@ -94,7 +95,7 @@ int bc_parser::decode_shader() {
                if ((r = decode_cf(i, eop)))
                        return r;
 
-       } while (!eop || (i >> 1) <= max_cf);
+       } while (!eop || (i >> 1) < max_cf);
 
        return 0;
 }
@@ -134,31 +135,48 @@ int bc_parser::parse_decls() {
                }
        }
 
-       if (sh->target == TARGET_VS)
+       // GS inputs can add indirect addressing
+       if (sh->target == TARGET_GS) {
+               if (pshader->num_arrays) {
+                       for (unsigned i = 0; i < pshader->num_arrays; ++i) {
+                               r600_shader_array &a = pshader->arrays[i];
+                               sh->add_gpr_array(a.gpr_start, a.gpr_count, a.comp_mask);
+                       }
+               }
+       }
+
+       if (sh->target == TARGET_VS || sh->target == TARGET_ES)
+               sh->add_input(0, 1, 0x0F);
+       else if (sh->target == TARGET_GS) {
                sh->add_input(0, 1, 0x0F);
+               sh->add_input(1, 1, 0x0F);
+       }
 
        bool ps_interp = ctx.hw_class >= HW_CLASS_EVERGREEN
                        && sh->target == TARGET_PS;
 
-       unsigned linear = 0, persp = 0, centroid = 1;
+       bool ij_interpolators[6];
+       memset(ij_interpolators, 0, sizeof(ij_interpolators));
 
        for (unsigned i = 0; i < pshader->ninput; ++i) {
                r600_shader_io & in = pshader->input[i];
                bool preloaded = sh->target == TARGET_PS && !(ps_interp && in.spi_sid);
                sh->add_input(in.gpr, preloaded, /*in.write_mask*/ 0x0F);
                if (ps_interp && in.spi_sid) {
-                       if (in.interpolate == TGSI_INTERPOLATE_LINEAR ||
-                                       in.interpolate == TGSI_INTERPOLATE_COLOR)
-                               linear = 1;
-                       else if (in.interpolate == TGSI_INTERPOLATE_PERSPECTIVE)
-                               persp = 1;
-                       if (in.centroid)
-                               centroid = 2;
+                       int k = eg_get_interpolator_index(in.interpolate, in.interpolate_location);
+                       if (k >= 0)
+                               ij_interpolators[k] |= true;
                }
        }
 
        if (ps_interp) {
-               unsigned mask = (1 << (2 * (linear + persp) * centroid)) - 1;
+               /* add the egcm ij interpolators to live inputs */
+               unsigned num_ij = 0;
+               for (unsigned i = 0; i < Elements(ij_interpolators); i++) {
+                       num_ij += ij_interpolators[i];
+               }
+
+               unsigned mask = (1 << (2 * num_ij)) - 1;
                unsigned gpr = 0;
 
                while (mask) {
@@ -202,7 +220,7 @@ int bc_parser::decode_cf(unsigned &i, bool &eop) {
                if (cf->bc.rw_rel)
                        gpr_reladdr = true;
                assert(!cf->bc.rw_rel);
-       } else if (flags & (CF_STRM | CF_RAT)) {
+       } else if (flags & CF_MEM) {
                if (cf->bc.rw_rel)
                        gpr_reladdr = true;
                assert(!cf->bc.rw_rel);
@@ -385,6 +403,11 @@ int bc_parser::prepare_alu_group(cf_node* cf, alu_group_node *g) {
                        } else if (src.sel == ALU_SRC_PS || src.sel == ALU_SRC_PV) {
                                unsigned pgroup = !cgroup, prev_slot = src.sel == ALU_SRC_PS ?
                                                SLOT_TRANS : src.chan;
+
+                               // XXX shouldn't happen but llvm backend uses PS on cayman
+                               if (prev_slot == SLOT_TRANS && ctx.is_cayman())
+                                       prev_slot = SLOT_X;
+
                                alu_node *prev_alu = slots[pgroup][prev_slot];
 
                                assert(prev_alu);
@@ -508,7 +531,7 @@ int bc_parser::decode_fetch_clause(cf_node* cf) {
 
 int bc_parser::prepare_fetch_clause(cf_node *cf) {
 
-       vvec grad_v, grad_h;
+       vvec grad_v, grad_h, texture_offsets;
 
        for (node_iterator I = cf->begin(), E = cf->end(); I != E; ++I) {
 
@@ -526,7 +549,7 @@ int bc_parser::prepare_fetch_clause(cf_node *cf) {
                        sh->uses_gradients = true;
                }
 
-               if (flags & FF_SETGRAD) {
+               if (flags & (FF_SETGRAD | FF_SET_TEXTURE_OFFSETS)) {
 
                        vvec *grad = NULL;
 
@@ -537,6 +560,9 @@ int bc_parser::prepare_fetch_clause(cf_node *cf) {
                                case FETCH_OP_SET_GRADIENTS_H:
                                        grad = &grad_h;
                                        break;
+                               case FETCH_OP_SET_TEXTURE_OFFSETS:
+                                       grad = &texture_offsets;
+                                       break;
                                default:
                                        assert(!"unexpected SET_GRAD instruction");
                                        return -1;
@@ -556,11 +582,15 @@ int bc_parser::prepare_fetch_clause(cf_node *cf) {
                                        (*grad)[s] = sh->get_const_value(1.0f);
                        }
                } else {
-
+                       // Fold source values for instructions with hidden target values in to the instructions
+                       // using them. The set instructions are later re-emitted by bc_finalizer
                        if (flags & FF_USEGRAD) {
                                n->src.resize(12);
                                std::copy(grad_v.begin(), grad_v.end(), n->src.begin() + 4);
                                std::copy(grad_h.begin(), grad_h.end(), n->src.begin() + 8);
+                       } else if (flags & FF_USE_TEXTURE_OFFSETS) {
+                               n->src.resize(8);
+                               std::copy(texture_offsets.begin(), texture_offsets.end(), n->src.begin() + 4);
                        } else {
                                n->src.resize(4);
                        }
@@ -671,7 +701,7 @@ int bc_parser::prepare_ir() {
                        } while (1);
 
                        c->bc.end_of_program = eop;
-               } else if (flags & (CF_STRM | CF_RAT)) {
+               } else if (flags & CF_MEM) {
 
                        unsigned burst_count = c->bc.burst_count;
                        unsigned eop = c->bc.end_of_program;
@@ -689,7 +719,7 @@ int bc_parser::prepare_ir() {
                                                                sh->get_gpr_value(true, c->bc.rw_gpr, s, false);
                                }
 
-                               if ((flags & CF_RAT) && (c->bc.type & 1)) { // indexed write
+                               if (((flags & CF_RAT) || (!(flags & CF_STRM))) && (c->bc.type & 1)) { // indexed write
                                        c->src.resize(8);
                                        for(int s = 0; s < 3; ++s) {
                                                c->src[4 + s] =
@@ -700,6 +730,16 @@ int bc_parser::prepare_ir() {
                                        c->flags |= NF_DONT_HOIST | NF_DONT_MOVE;
                                }
 
+                               if (flags & CF_EMIT) {
+                                       // Instruction implicitly depends on prior [EMIT_][CUT]_VERTEX
+                                       c->src.push_back(sh->get_special_value(SV_GEOMETRY_EMIT));
+                                       c->dst.push_back(sh->get_special_value(SV_GEOMETRY_EMIT));
+                                       if (sh->target == TARGET_ES) {
+                                               // For ES shaders this is an export
+                                               c->flags |= NF_DONT_KILL;
+                                       }
+                               }
+
                                if (!burst_count--)
                                        break;
 
@@ -716,6 +756,23 @@ int bc_parser::prepare_ir() {
 
                        c->bc.end_of_program = eop;
 
+               } else if (flags & CF_EMIT) {
+                       /* quick peephole */
+                       cf_node *prev = static_cast<cf_node *>(c->prev);
+                       if (c->bc.op == CF_OP_CUT_VERTEX &&
+                               prev && prev->is_valid() &&
+                               prev->bc.op == CF_OP_EMIT_VERTEX &&
+                               c->bc.count == prev->bc.count) {
+                               prev->bc.set_op(CF_OP_EMIT_CUT_VERTEX);
+                               prev->bc.end_of_program = c->bc.end_of_program;
+                               c->remove();
+                       }
+                       else {
+                               c->flags |= NF_DONT_KILL | NF_DONT_HOIST | NF_DONT_MOVE;
+
+                               c->src.push_back(sh->get_special_value(SV_GEOMETRY_EMIT));
+                               c->dst.push_back(sh->get_special_value(SV_GEOMETRY_EMIT));
+                       }
                }
        }
 
@@ -724,6 +781,7 @@ int bc_parser::prepare_ir() {
 }
 
 int bc_parser::prepare_loop(cf_node* c) {
+       assert(c->bc.addr-1 < cf_map.size());
 
        cf_node *end = cf_map[c->bc.addr - 1];
        assert(end->bc.op == CF_OP_LOOP_END);
@@ -736,13 +794,19 @@ int bc_parser::prepare_loop(cf_node* c) {
        c->insert_before(reg);
        rep->move(c, end->next);
 
+       reg->src_loop = true;
+
        loop_stack.push(reg);
        return 0;
 }
 
 int bc_parser::prepare_if(cf_node* c) {
+       assert(c->bc.addr-1 < cf_map.size());
        cf_node *c_else = NULL, *end = cf_map[c->bc.addr];
 
+       if (!end)
+               return 0; // not quite sure how this happens, malformed input?
+
        BCP_DUMP(
                sblog << "parsing JUMP @" << c->bc.id;
                sblog << "\n";
@@ -768,7 +832,7 @@ int bc_parser::prepare_if(cf_node* c) {
        if (c_else->parent != c->parent)
                c_else = NULL;
 
-       if (end->parent != c->parent)
+       if (end && end->parent != c->parent)
                end = NULL;
 
        region_node *reg = sh->create_region();