diff options
| author | Brian Paul <brianp@vmware.com> | 2009-02-13 17:17:52 -0700 | 
|---|---|---|
| committer | Brian Paul <brianp@vmware.com> | 2009-02-13 17:18:36 -0700 | 
| commit | c51c822ee02cb47ddba46da668577d51b7c02831 (patch) | |
| tree | 905cafdc5a02f07aa67fc04e66a7fb1734abec20 | |
| parent | 74b6d55864b9264323a09856781f655e453b182b (diff) | |
i965: rewrite the code for handling shader subroutine calls
Previously, the prog_instruction::Data field was used to map original Mesa
instructions to brw instructions in order to resolve subroutine calls.  This
was a rather tangled mess.  Plus it's an obstacle to implementing dynamic
allocation/growing of the instruction buffer (it's still a fixed size).
Mesa's GLSL compiler emits a label for each subroutine and CAL instruction.
Now we use those labels to patch the subroutine calls after code generation
has been done.  We just keep a list of all CAL instructions that needs patching
and a list of all subroutine labels.  It's a simple matter to resolve them.
This also consolidates some redundant post-emit code between brw_vs_emit.c and
brw_wm_glsl.c and removes some loops that cleared the prog_instruction::Data
fields at the end.
Plus, a bunch of new comments.
| -rw-r--r-- | src/mesa/drivers/dri/i965/brw_eu.c | 123 | ||||
| -rw-r--r-- | src/mesa/drivers/dri/i965/brw_eu.h | 18 | ||||
| -rw-r--r-- | src/mesa/drivers/dri/i965/brw_vs_emit.c | 71 | ||||
| -rw-r--r-- | src/mesa/drivers/dri/i965/brw_wm.h | 2 | ||||
| -rw-r--r-- | src/mesa/drivers/dri/i965/brw_wm_fp.c | 1 | ||||
| -rw-r--r-- | src/mesa/drivers/dri/i965/brw_wm_glsl.c | 36 | 
6 files changed, 187 insertions, 64 deletions
| diff --git a/src/mesa/drivers/dri/i965/brw_eu.c b/src/mesa/drivers/dri/i965/brw_eu.c index b3ae4eef33..c53efba599 100644 --- a/src/mesa/drivers/dri/i965/brw_eu.c +++ b/src/mesa/drivers/dri/i965/brw_eu.c @@ -129,3 +129,126 @@ const GLuint *brw_get_program( struct brw_compile *p,     return (const GLuint *)p->store;  } + + +/** + * Subroutine calls require special attention. + * Mesa instructions may be expanded into multiple hardware instructions + * so the prog_instruction::BranchTarget field can't be used as an index + * into the hardware instructions. + * + * The BranchTarget field isn't needed, however.  Mesa's GLSL compiler + * emits CAL and BGNSUB instructions with labels that can be used to map + * subroutine calls to actual subroutine code blocks. + * + * The structures and function here implement patching of CAL instructions + * so they jump to the right subroutine code... + */ + + +/** + * For each OPCODE_BGNSUB we create one of these. + */ +struct brw_glsl_label +{ +   const char *name; /**< the label string */ +   GLuint position;  /**< the position of the brw instruction for this label */ +   struct brw_glsl_label *next;  /**< next in linked list */ +}; + + +/** + * For each OPCODE_CAL we create one of these. + */ +struct brw_glsl_call +{ +   GLuint call_inst_pos;  /**< location of the CAL instruction */ +   const char *sub_name;  /**< name of subroutine to call */ +   struct brw_glsl_call *next;  /**< next in linked list */ +}; + + +/** + * Called for each OPCODE_BGNSUB. + */ +void +brw_save_label(struct brw_compile *c, const char *name, GLuint position) +{ +   struct brw_glsl_label *label = CALLOC_STRUCT(brw_glsl_label); +   label->name = name; +   label->position = position; +   label->next = c->first_label; +   c->first_label = label; +} + + +/** + * Called for each OPCODE_CAL. + */ +void +brw_save_call(struct brw_compile *c, const char *name, GLuint call_pos) +{ +   struct brw_glsl_call *call = CALLOC_STRUCT(brw_glsl_call); +   call->call_inst_pos = call_pos; +   call->sub_name = name; +   call->next = c->first_call; +   c->first_call = call; +} + + +/** + * Lookup a label, return label's position/offset. + */ +static GLuint +brw_lookup_label(struct brw_compile *c, const char *name) +{ +   const struct brw_glsl_label *label; +   for (label = c->first_label; label; label = label->next) { +      if (strcmp(name, label->name) == 0) { +         return label->position; +      } +   } +   abort();  /* should never happen */ +   return ~0; +} + + +/** + * When we're done generating code, this function is called to resolve + * subroutine calls. + */ +void +brw_resolve_cals(struct brw_compile *c) +{ +    const struct brw_glsl_call *call; + +    for (call = c->first_call; call; call = call->next) { +        const GLuint sub_loc = brw_lookup_label(c, call->sub_name); +	struct brw_instruction *brw_call_inst = &c->store[call->call_inst_pos]; +	struct brw_instruction *brw_sub_inst = &c->store[sub_loc]; +	GLint offset = brw_sub_inst - brw_call_inst; + +	/* patch brw_inst1 to point to brw_inst2 */ +	brw_set_src1(brw_call_inst, brw_imm_d(offset * 16)); +    } + +    /* free linked list of calls */ +    { +        struct brw_glsl_call *call, *next; +        for (call = c->first_call; call; call = next) { +	    next = call->next; +	    _mesa_free(call); +	} +	c->first_call = NULL; +    } + +    /* free linked list of labels */ +    { +        struct brw_glsl_label *label, *next; +	for (label = c->first_label; label; label = next) { +	    next = label->next; +	    _mesa_free(label); +	} +	c->first_label = NULL; +    } +} diff --git a/src/mesa/drivers/dri/i965/brw_eu.h b/src/mesa/drivers/dri/i965/brw_eu.h index 9e2b39af9b..b36a1976ef 100644 --- a/src/mesa/drivers/dri/i965/brw_eu.h +++ b/src/mesa/drivers/dri/i965/brw_eu.h @@ -91,6 +91,11 @@ struct brw_indirect {  }; +struct brw_glsl_label; +struct brw_glsl_call; + + +  #define BRW_EU_MAX_INSN_STACK 5  #define BRW_EU_MAX_INSN 1200 @@ -106,9 +111,22 @@ struct brw_compile {     GLuint flag_value;     GLboolean single_program_flow;     struct brw_context *brw; + +   struct brw_glsl_label *first_label;  /**< linked list of labels */ +   struct brw_glsl_call *first_call;    /**< linked list of CALs */  }; +void +brw_save_label(struct brw_compile *c, const char *name, GLuint position); + +void +brw_save_call(struct brw_compile *c, const char *name, GLuint call_pos); + +void +brw_resolve_cals(struct brw_compile *c); + +  static INLINE int type_sz( GLuint type )  { diff --git a/src/mesa/drivers/dri/i965/brw_vs_emit.c b/src/mesa/drivers/dri/i965/brw_vs_emit.c index a1328f6967..235f826812 100644 --- a/src/mesa/drivers/dri/i965/brw_vs_emit.c +++ b/src/mesa/drivers/dri/i965/brw_vs_emit.c @@ -954,36 +954,27 @@ static void emit_vertex_write( struct brw_vs_compile *c)  } +/** + * Called after code generation to resolve subroutine calls and the + * END instruction. + * \param end_inst  points to brw code for END instruction + * \param last_inst  points to last instruction emitted before vertex write + */  static void  -post_vs_emit( struct brw_vs_compile *c, struct brw_instruction *end_inst ) +post_vs_emit( struct brw_vs_compile *c, +              struct brw_instruction *end_inst, +              struct brw_instruction *last_inst )  { -   GLuint nr_insns = c->vp->program.Base.NumInstructions; -   GLuint insn, target_insn; -   struct prog_instruction *inst1, *inst2; -   struct brw_instruction *brw_inst1, *brw_inst2; -   int offset; -   for (insn = 0; insn < nr_insns; insn++) { -       inst1 = &c->vp->program.Base.Instructions[insn]; -       brw_inst1 = inst1->Data; -       switch (inst1->Opcode) { -	   case OPCODE_CAL: -	   case OPCODE_BRA: -	       target_insn = inst1->BranchTarget; -	       inst2 = &c->vp->program.Base.Instructions[target_insn]; -	       brw_inst2 = inst2->Data; -	       offset = brw_inst2 - brw_inst1; -	       brw_set_src1(brw_inst1, brw_imm_d(offset*16)); -	       break; -	   case OPCODE_END: -	       offset = end_inst - brw_inst1; -	       brw_set_src1(brw_inst1, brw_imm_d(offset*16)); -	       break; -	   default: -	       break; -       } -   } +   GLint offset; + +   brw_resolve_cals(&c->func); + +   /* patch up the END code to jump past subroutines, etc */ +   offset = last_inst - end_inst; +   brw_set_src1(end_inst, brw_imm_d(offset * 16));  } +  /* Emit the fragment program instructions here.   */  void brw_vs_emit(struct brw_vs_compile *c ) @@ -992,7 +983,8 @@ void brw_vs_emit(struct brw_vs_compile *c )     struct brw_compile *p = &c->func;     GLuint nr_insns = c->vp->program.Base.NumInstructions;     GLuint insn, if_insn = 0; -   struct brw_instruction *end_inst; +   GLuint end_offset = 0; +   struct brw_instruction *end_inst, *last_inst;     struct brw_instruction *if_inst[MAX_IFSN];     struct brw_indirect stack_index = brw_indirect(0, 0);    @@ -1035,7 +1027,6 @@ void brw_vs_emit(struct brw_vs_compile *c )        /* Get argument regs.  SWZ is special and does this itself.         */ -      inst->Data = &p->store[p->nr_insn];        if (inst->Opcode != OPCODE_SWZ)  	  for (i = 0; i < 3; i++) {  	      struct prog_src_register *src = &inst->SrcReg[i]; @@ -1203,7 +1194,7 @@ void brw_vs_emit(struct brw_vs_compile *c )  	 brw_set_access_mode(p, BRW_ALIGN_16);  	 brw_ADD(p, get_addr_reg(stack_index),  			 get_addr_reg(stack_index), brw_imm_d(4)); -	 inst->Data = &p->store[p->nr_insn]; +         brw_save_call(p, inst->Comment, p->nr_insn);  	 brw_ADD(p, brw_ip_reg(), brw_ip_reg(), brw_imm_d(1*16));           break;        case OPCODE_RET: @@ -1214,13 +1205,21 @@ void brw_vs_emit(struct brw_vs_compile *c )  	 brw_set_access_mode(p, BRW_ALIGN_16);  	 break;        case OPCODE_END:	 +         end_offset = p->nr_insn; +         /* this instruction will get patched later to jump past subroutine +          * code, etc. +          */           brw_ADD(p, brw_ip_reg(), brw_ip_reg(), brw_imm_d(1*16));           break;        case OPCODE_PRINT: +         /* no-op */ +         break;        case OPCODE_BGNSUB: +         brw_save_label(p, inst->Comment, p->nr_insn); +         break;        case OPCODE_ENDSUB: -         /* no-op instructions */ -	 break; +         /* no-op */ +         break;        default:  	 _mesa_problem(NULL, "Unsupported opcode %i (%s) in vertex shader",                         inst->Opcode, inst->Opcode < MAX_OPCODE ? @@ -1258,9 +1257,11 @@ void brw_vs_emit(struct brw_vs_compile *c )        release_tmps(c);     } -   end_inst = &p->store[p->nr_insn]; +   end_inst = &p->store[end_offset]; +   last_inst = &p->store[p->nr_insn]; + +   /* The END instruction will be patched to jump to this code */     emit_vertex_write(c); -   post_vs_emit(c, end_inst); -   for (insn = 0; insn < nr_insns; insn++) -       c->vp->program.Base.Instructions[insn].Data = NULL; + +   post_vs_emit(c, end_inst, last_inst);  } diff --git a/src/mesa/drivers/dri/i965/brw_wm.h b/src/mesa/drivers/dri/i965/brw_wm.h index 0f46a25b1a..582031f5f6 100644 --- a/src/mesa/drivers/dri/i965/brw_wm.h +++ b/src/mesa/drivers/dri/i965/brw_wm.h @@ -281,4 +281,6 @@ void brw_wm_lookup_iz( GLuint line_aa,  GLboolean brw_wm_is_glsl(const struct gl_fragment_program *fp);  void brw_wm_glsl_emit(struct brw_context *brw, struct brw_wm_compile *c); + +  #endif diff --git a/src/mesa/drivers/dri/i965/brw_wm_fp.c b/src/mesa/drivers/dri/i965/brw_wm_fp.c index 0a44f8bcca..8b5ccdba93 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_fp.c +++ b/src/mesa/drivers/dri/i965/brw_wm_fp.c @@ -183,7 +183,6 @@ static struct prog_instruction *emit_insn(struct brw_wm_compile *c,  {     struct prog_instruction *inst = get_fp_inst(c);     *inst = *inst0; -   inst->Data = (void *)inst0;     return inst;  } diff --git a/src/mesa/drivers/dri/i965/brw_wm_glsl.c b/src/mesa/drivers/dri/i965/brw_wm_glsl.c index 0d3e2eb770..d99aa372a9 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_glsl.c +++ b/src/mesa/drivers/dri/i965/brw_wm_glsl.c @@ -2252,28 +2252,12 @@ static void emit_tex(struct brw_wm_compile *c,  	brw_MOV(p, dst[3], brw_imm_f(1.0));  } +/** + * Resolve subroutine calls after code emit is done. + */  static void post_wm_emit( struct brw_wm_compile *c )  { -    GLuint nr_insns = c->fp->program.Base.NumInstructions; -    GLuint insn, target_insn; -    struct prog_instruction *inst1, *inst2; -    struct brw_instruction *brw_inst1, *brw_inst2; -    int offset; -    for (insn = 0; insn < nr_insns; insn++) { -	inst1 = &c->fp->program.Base.Instructions[insn]; -	brw_inst1 = inst1->Data; -	switch (inst1->Opcode) { -	    case OPCODE_CAL: -		target_insn = inst1->BranchTarget; -		inst2 = &c->fp->program.Base.Instructions[target_insn]; -		brw_inst2 = inst2->Data; -		offset = brw_inst2 - brw_inst1; -		brw_set_src1(brw_inst1, brw_imm_d(offset*16)); -		break; -	    default: -		break; -	} -    } +    brw_resolve_cals(&c->func);  }  static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c) @@ -2293,10 +2277,6 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)      for (i = 0; i < c->nr_fp_insns; i++) {  	struct prog_instruction *inst = &c->prog_instructions[i]; -	struct prog_instruction *orig_inst; - -	if ((orig_inst = inst->Data) != 0) -	    orig_inst->Data = current_insn(p);  	if (inst->CondUpdate)  	    brw_set_conditionalmod(p, BRW_CONDITIONAL_NZ); @@ -2454,7 +2434,10 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)  		brw_ENDIF(p, if_inst[--if_insn]);  		break;  	    case OPCODE_BGNSUB: +		brw_save_label(p, inst->Comment, p->nr_insn); +		break;  	    case OPCODE_ENDSUB: +		/* no-op */  		break;  	    case OPCODE_CAL:   		brw_push_insn_state(p); @@ -2464,8 +2447,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)                  brw_set_access_mode(p, BRW_ALIGN_16);                  brw_ADD(p, get_addr_reg(stack_index),                           get_addr_reg(stack_index), brw_imm_d(4)); -                orig_inst = inst->Data; -                orig_inst->Data = &p->store[p->nr_insn]; +		brw_save_call(&c->func, inst->Comment, p->nr_insn);                  brw_ADD(p, brw_ip_reg(), brw_ip_reg(), brw_imm_d(1*16));                  brw_pop_insn_state(p);  		break; @@ -2518,8 +2500,6 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)  	    brw_set_predicate_control(p, BRW_PREDICATE_NONE);      }      post_wm_emit(c); -    for (i = 0; i < c->fp->program.Base.NumInstructions; i++) -	c->fp->program.Base.Instructions[i].Data = NULL;  } | 
