static int emit_vs_consts( struct svga_context *svga,
                           unsigned dirty )
{
   const struct svga_shader_result *result = svga->state.hw_draw.vs;
   const struct svga_vs_compile_key *key = &result->key.vkey;
   int ret = 0;
   unsigned offset;

   /* SVGA_NEW_VS_RESULT
    */
   if (result == NULL) 
      return 0;

   /* SVGA_NEW_VS_CONST_BUFFER 
    */
   ret = emit_consts( svga, 0, PIPE_SHADER_VERTEX );
   if (ret)
      return ret;

   offset = result->shader->info.file_max[TGSI_FILE_CONSTANT] + 1;

   /* SVGA_NEW_VS_RESULT
    */
   if (key->need_prescale) {
      ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++,
                        svga->state.hw_clear.prescale.scale );
      if (ret)
         return ret;

      ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++,
                        svga->state.hw_clear.prescale.translate );
      if (ret)
         return ret;
   }

   /* SVGA_NEW_ZERO_STRIDE
    */
   if (key->zero_stride_vertex_elements) {
      unsigned i, curr_zero_stride = 0;
      for (i = 0; i < PIPE_MAX_ATTRIBS; ++i) {
         if (key->zero_stride_vertex_elements & (1 << i)) {
            ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++,
                              svga->curr.zero_stride_constants +
                              4 * curr_zero_stride );
            if (ret)
               return ret;
            ++curr_zero_stride;
         }
      }
   }

   return 0;
}
static enum pipe_error
emit_vs_consts(struct svga_context *svga, unsigned dirty)
{
   const struct svga_shader_result *result = svga->state.hw_draw.vs;
   const struct svga_vs_compile_key *key;
   enum pipe_error ret = PIPE_OK;
   unsigned offset;

   /* SVGA_NEW_VS_RESULT
    */
   if (result == NULL)
      return PIPE_OK;

   key = &result->key.vkey;

   /* SVGA_NEW_VS_CONST_BUFFER
    */
   ret = emit_consts( svga, PIPE_SHADER_VERTEX );
   if (ret != PIPE_OK)
      return ret;

   /* offset = number of constants in the VS const buffer */
   offset = result->shader->info.file_max[TGSI_FILE_CONSTANT] + 1;

   /* SVGA_NEW_VS_PRESCALE
    * Put the viewport pre-scale/translate values into the const buffer.
    */
   if (key->need_prescale) {
      ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++,
                        svga->state.hw_clear.prescale.scale );
      if (ret != PIPE_OK)
         return ret;

      ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++,
                        svga->state.hw_clear.prescale.translate );
      if (ret != PIPE_OK)
         return ret;
   }

   return PIPE_OK;
}
/**
 * Emit all the constants in a constant buffer for a shader stage.
 */
static enum pipe_error
emit_consts(struct svga_context *svga, unsigned shader)
{
   struct svga_screen *ss = svga_screen(svga->pipe.screen);
   struct pipe_transfer *transfer = NULL;
   unsigned count;
   const float (*data)[4] = NULL;
   unsigned i;
   enum pipe_error ret = PIPE_OK;
   const unsigned offset = 0;

   assert(shader < PIPE_SHADER_TYPES);

   if (svga->curr.cb[shader] == NULL)
      goto done;

   count = svga->curr.cb[shader]->width0 / (4 * sizeof(float));

   data = (const float (*)[4])pipe_buffer_map(&svga->pipe,
                                              svga->curr.cb[shader],
                                              PIPE_TRANSFER_READ,
					      &transfer);
   if (data == NULL) {
      ret = PIPE_ERROR_OUT_OF_MEMORY;
      goto done;
   }

   if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) {
      ret = emit_const_range( svga, shader, offset, count, data );
      if (ret != PIPE_OK) {
         goto done;
      }
   } else {
      for (i = 0; i < count; i++) {
         ret = emit_const( svga, shader, offset + i, data[i] );
         if (ret != PIPE_OK) {
            goto done;
         }
      }
   }

done:
   if (data)
      pipe_buffer_unmap(&svga->pipe, transfer);

   return ret;
}
static int emit_fs_consts( struct svga_context *svga,
                           unsigned dirty )
{
   const struct svga_shader_result *result = svga->state.hw_draw.fs;
   const struct svga_fs_compile_key *key = &result->key.fkey;
   int ret = 0;

   ret = emit_consts( svga, 0, PIPE_SHADER_FRAGMENT );
   if (ret)
      return ret;

   /* The internally generated fragment shader for xor blending
    * doesn't have a 'result' struct.  It should be fixed to avoid
    * this special case, but work around it with a NULL check:
    */
   if (result != NULL &&
       key->num_unnormalized_coords)
   {
      unsigned offset = result->shader->info.file_max[TGSI_FILE_CONSTANT] + 1;
      int i;

      for (i = 0; i < key->num_textures; i++) {
         if (key->tex[i].unnormalized) {
            struct pipe_resource *tex = svga->curr.sampler_views[i]->texture;
            float data[4];

            data[0] = 1.0 / (float)tex->width0;
            data[1] = 1.0 / (float)tex->height0;
            data[2] = 1.0;
            data[3] = 1.0;

            ret = emit_const( svga,
                              PIPE_SHADER_FRAGMENT,
                              key->tex[i].width_height_idx + offset,
                              data );
            if (ret)
               return ret;
         }
      }

      offset += key->num_unnormalized_coords;
   }

   return 0;
}
static int emit_consts( struct svga_context *svga,
                        int offset,
                        int unit )
{
   struct pipe_transfer *transfer = NULL;
   unsigned count;
   const float (*data)[4] = NULL;
   unsigned i;
   int ret = PIPE_OK;

   if (svga->curr.cb[unit] == NULL)
      goto done;

   count = svga->curr.cb[unit]->width0 / (4 * sizeof(float));

   data = (const float (*)[4])pipe_buffer_map(&svga->pipe,
                                              svga->curr.cb[unit],
                                              PIPE_TRANSFER_READ,
					      &transfer);
   if (data == NULL) {
      ret = PIPE_ERROR_OUT_OF_MEMORY;
      goto done;
   }

   for (i = 0; i < count; i++) {
      ret = emit_const( svga, unit, offset + i, data[i] );
      if (ret)
         goto done;
   }

done:
   if (data)
      pipe_buffer_unmap(&svga->pipe, svga->curr.cb[unit], transfer);

   return ret;
}
Example #6
0
enum eval_result_type
compile_bytecodes (struct agent_expr *aexpr)
{
  int pc = 0;
  int done = 0;
  unsigned char op, next_op;
  int arg;
  /* This is only used to build 64-bit value for constants.  */
  ULONGEST top;
  struct bytecode_address *aentry, *aentry2;

#define UNHANDLED					\
  do							\
    {							\
      ax_debug ("Cannot compile op 0x%x\n", op);	\
      return expr_eval_unhandled_opcode;		\
    } while (0)

  if (aexpr->length == 0)
    {
      ax_debug ("empty agent expression\n");
      return expr_eval_empty_expression;
    }

  bytecode_address_table = NULL;

  while (!done)
    {
      op = aexpr->bytes[pc];

      ax_debug ("About to compile op 0x%x, pc=%d\n", op, pc);

      /* Record the compiled-code address of the bytecode, for use by
	 jump instructions.  */
      aentry = XNEW (struct bytecode_address);
      aentry->pc = pc;
      aentry->address = current_insn_ptr;
      aentry->goto_pc = -1;
      aentry->from_offset = aentry->from_size = 0;
      aentry->next = bytecode_address_table;
      bytecode_address_table = aentry;

      ++pc;

      emit_error = 0;

      switch (op)
	{
	case gdb_agent_op_add:
	  emit_add ();
	  break;

	case gdb_agent_op_sub:
	  emit_sub ();
	  break;

	case gdb_agent_op_mul:
	  emit_mul ();
	  break;

	case gdb_agent_op_div_signed:
	  UNHANDLED;
	  break;

	case gdb_agent_op_div_unsigned:
	  UNHANDLED;
	  break;

	case gdb_agent_op_rem_signed:
	  UNHANDLED;
	  break;

	case gdb_agent_op_rem_unsigned:
	  UNHANDLED;
	  break;

	case gdb_agent_op_lsh:
	  emit_lsh ();
	  break;

	case gdb_agent_op_rsh_signed:
	  emit_rsh_signed ();
	  break;

	case gdb_agent_op_rsh_unsigned:
	  emit_rsh_unsigned ();
	  break;

	case gdb_agent_op_trace:
	  UNHANDLED;
	  break;

	case gdb_agent_op_trace_quick:
	  UNHANDLED;
	  break;

	case gdb_agent_op_log_not:
	  emit_log_not ();
	  break;

	case gdb_agent_op_bit_and:
	  emit_bit_and ();
	  break;

	case gdb_agent_op_bit_or:
	  emit_bit_or ();
	  break;

	case gdb_agent_op_bit_xor:
	  emit_bit_xor ();
	  break;

	case gdb_agent_op_bit_not:
	  emit_bit_not ();
	  break;

	case gdb_agent_op_equal:
	  next_op = aexpr->bytes[pc];
	  if (next_op == gdb_agent_op_if_goto
	      && !is_goto_target (aexpr, pc)
	      && target_emit_ops ()->emit_eq_goto)
	    {
	      ax_debug ("Combining equal & if_goto");
	      pc += 1;
	      aentry->pc = pc;
	      arg = aexpr->bytes[pc++];
	      arg = (arg << 8) + aexpr->bytes[pc++];
	      aentry->goto_pc = arg;
	      emit_eq_goto (&(aentry->from_offset), &(aentry->from_size));
	    }
	  else if (next_op == gdb_agent_op_log_not
		   && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto)
		   && !is_goto_target (aexpr, pc + 1)
		   && target_emit_ops ()->emit_ne_goto)
	    {
	      ax_debug ("Combining equal & log_not & if_goto");
	      pc += 2;
	      aentry->pc = pc;
	      arg = aexpr->bytes[pc++];
	      arg = (arg << 8) + aexpr->bytes[pc++];
	      aentry->goto_pc = arg;
	      emit_ne_goto (&(aentry->from_offset), &(aentry->from_size));
	    }
	  else
	    emit_equal ();
	  break;

	case gdb_agent_op_less_signed:
	  next_op = aexpr->bytes[pc];
	  if (next_op == gdb_agent_op_if_goto
	      && !is_goto_target (aexpr, pc))
	    {
	      ax_debug ("Combining less_signed & if_goto");
	      pc += 1;
	      aentry->pc = pc;
	      arg = aexpr->bytes[pc++];
	      arg = (arg << 8) + aexpr->bytes[pc++];
	      aentry->goto_pc = arg;
	      emit_lt_goto (&(aentry->from_offset), &(aentry->from_size));
	    }
	  else if (next_op == gdb_agent_op_log_not
		   && !is_goto_target (aexpr, pc)
		   && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto)
		   && !is_goto_target (aexpr, pc + 1))
	    {
	      ax_debug ("Combining less_signed & log_not & if_goto");
	      pc += 2;
	      aentry->pc = pc;
	      arg = aexpr->bytes[pc++];
	      arg = (arg << 8) + aexpr->bytes[pc++];
	      aentry->goto_pc = arg;
	      emit_ge_goto (&(aentry->from_offset), &(aentry->from_size));
	    }
	  else
	    emit_less_signed ();
	  break;

	case gdb_agent_op_less_unsigned:
	  emit_less_unsigned ();
	  break;

	case gdb_agent_op_ext:
	  arg = aexpr->bytes[pc++];
	  if (arg < (sizeof (LONGEST) * 8))
	    emit_ext (arg);
	  break;

	case gdb_agent_op_ref8:
	  emit_ref (1);
	  break;

	case gdb_agent_op_ref16:
	  emit_ref (2);
	  break;

	case gdb_agent_op_ref32:
	  emit_ref (4);
	  break;

	case gdb_agent_op_ref64:
	  emit_ref (8);
	  break;

	case gdb_agent_op_if_goto:
	  arg = aexpr->bytes[pc++];
	  arg = (arg << 8) + aexpr->bytes[pc++];
	  aentry->goto_pc = arg;
	  emit_if_goto (&(aentry->from_offset), &(aentry->from_size));
	  break;

	case gdb_agent_op_goto:
	  arg = aexpr->bytes[pc++];
	  arg = (arg << 8) + aexpr->bytes[pc++];
	  aentry->goto_pc = arg;
	  emit_goto (&(aentry->from_offset), &(aentry->from_size));
	  break;

	case gdb_agent_op_const8:
	  emit_stack_flush ();
	  top = aexpr->bytes[pc++];
	  emit_const (top);
	  break;

	case gdb_agent_op_const16:
	  emit_stack_flush ();
	  top = aexpr->bytes[pc++];
	  top = (top << 8) + aexpr->bytes[pc++];
	  emit_const (top);
	  break;

	case gdb_agent_op_const32:
	  emit_stack_flush ();
	  top = aexpr->bytes[pc++];
	  top = (top << 8) + aexpr->bytes[pc++];
	  top = (top << 8) + aexpr->bytes[pc++];
	  top = (top << 8) + aexpr->bytes[pc++];
	  emit_const (top);
	  break;

	case gdb_agent_op_const64:
	  emit_stack_flush ();
	  top = aexpr->bytes[pc++];
	  top = (top << 8) + aexpr->bytes[pc++];
	  top = (top << 8) + aexpr->bytes[pc++];
	  top = (top << 8) + aexpr->bytes[pc++];
	  top = (top << 8) + aexpr->bytes[pc++];
	  top = (top << 8) + aexpr->bytes[pc++];
	  top = (top << 8) + aexpr->bytes[pc++];
	  top = (top << 8) + aexpr->bytes[pc++];
	  emit_const (top);
	  break;

	case gdb_agent_op_reg:
	  emit_stack_flush ();
	  arg = aexpr->bytes[pc++];
	  arg = (arg << 8) + aexpr->bytes[pc++];
	  emit_reg (arg);
	  break;

	case gdb_agent_op_end:
	  ax_debug ("At end of expression\n");

	  /* Assume there is one stack element left, and that it is
	     cached in "top" where emit_epilogue can get to it.  */
	  emit_stack_adjust (1);

	  done = 1;
	  break;

	case gdb_agent_op_dup:
	  /* In our design, dup is equivalent to stack flushing.  */
	  emit_stack_flush ();
	  break;

	case gdb_agent_op_pop:
	  emit_pop ();
	  break;

	case gdb_agent_op_zero_ext:
	  arg = aexpr->bytes[pc++];
	  if (arg < (sizeof (LONGEST) * 8))
	    emit_zero_ext (arg);
	  break;

	case gdb_agent_op_swap:
	  next_op = aexpr->bytes[pc];
	  /* Detect greater-than comparison sequences.  */
	  if (next_op == gdb_agent_op_less_signed
	      && !is_goto_target (aexpr, pc)
	      && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto)
	      && !is_goto_target (aexpr, pc + 1))
	    {
	      ax_debug ("Combining swap & less_signed & if_goto");
	      pc += 2;
	      aentry->pc = pc;
	      arg = aexpr->bytes[pc++];
	      arg = (arg << 8) + aexpr->bytes[pc++];
	      aentry->goto_pc = arg;
	      emit_gt_goto (&(aentry->from_offset), &(aentry->from_size));
	    }
	  else if (next_op == gdb_agent_op_less_signed
		   && !is_goto_target (aexpr, pc)
		   && (aexpr->bytes[pc + 1] == gdb_agent_op_log_not)
		   && !is_goto_target (aexpr, pc + 1)
		   && (aexpr->bytes[pc + 2] == gdb_agent_op_if_goto)
		   && !is_goto_target (aexpr, pc + 2))
	    {
	      ax_debug ("Combining swap & less_signed & log_not & if_goto");
	      pc += 3;
	      aentry->pc = pc;
	      arg = aexpr->bytes[pc++];
	      arg = (arg << 8) + aexpr->bytes[pc++];
	      aentry->goto_pc = arg;
	      emit_le_goto (&(aentry->from_offset), &(aentry->from_size));
	    }
	  else
	    emit_swap ();
	  break;

	case gdb_agent_op_getv:
	  emit_stack_flush ();
	  arg = aexpr->bytes[pc++];
	  arg = (arg << 8) + aexpr->bytes[pc++];
	  emit_int_call_1 (get_get_tsv_func_addr (),
			   arg);
	  break;

	case gdb_agent_op_setv:
	  arg = aexpr->bytes[pc++];
	  arg = (arg << 8) + aexpr->bytes[pc++];
	  emit_void_call_2 (get_set_tsv_func_addr (),
			    arg);
	  break;

	case gdb_agent_op_tracev:
	  UNHANDLED;
	  break;

	  /* GDB never (currently) generates any of these ops.  */
	case gdb_agent_op_float:
	case gdb_agent_op_ref_float:
	case gdb_agent_op_ref_double:
	case gdb_agent_op_ref_long_double:
	case gdb_agent_op_l_to_d:
	case gdb_agent_op_d_to_l:
	case gdb_agent_op_trace16:
	  UNHANDLED;
	  break;

	default:
	  ax_debug ("Agent expression op 0x%x not recognized\n", op);
	  /* Don't struggle on, things will just get worse.  */
	  return expr_eval_unrecognized_opcode;
	}

      /* This catches errors that occur in target-specific code
	 emission.  */
      if (emit_error)
	{
	  ax_debug ("Error %d while emitting code for %s\n",
		    emit_error, gdb_agent_op_name (op));
	  return expr_eval_unhandled_opcode;
	}

      ax_debug ("Op %s compiled\n", gdb_agent_op_name (op));
    }

  /* Now fill in real addresses as goto destinations.  */
  for (aentry = bytecode_address_table; aentry; aentry = aentry->next)
    {
      int written = 0;

      if (aentry->goto_pc < 0)
	continue;

      /* Find the location that we are going to, and call back into
	 target-specific code to write the actual address or
	 displacement.  */
      for (aentry2 = bytecode_address_table; aentry2; aentry2 = aentry2->next)
	{
	  if (aentry2->pc == aentry->goto_pc)
	    {
	      ax_debug ("Want to jump from %s to %s\n",
			paddress (aentry->address),
			paddress (aentry2->address));
	      write_goto_address (aentry->address + aentry->from_offset,
				  aentry2->address, aentry->from_size);
	      written = 1;
	      break;
	    }
	}

      /* Error out if we didn't find a destination.  */
      if (!written)
	{
	  ax_debug ("Destination of goto %d not found\n",
		    aentry->goto_pc);
	  return expr_eval_invalid_goto;
	}
    }

  return expr_eval_no_error;
}
/**
 * Emit all the constants in a constant buffer for a shader stage.
 * On VGPU10, emit_consts_vgpu10 is used instead.
 */
static enum pipe_error
emit_consts_vgpu9(struct svga_context *svga, unsigned shader)
{
   const struct pipe_constant_buffer *cbuf;
   struct svga_screen *ss = svga_screen(svga->pipe.screen);
   struct pipe_transfer *transfer = NULL;
   unsigned count;
   const float (*data)[4] = NULL;
   unsigned i;
   enum pipe_error ret = PIPE_OK;
   const unsigned offset = 0;

   assert(shader < PIPE_SHADER_TYPES);
   assert(!svga_have_vgpu10(svga));
   /* Only one constant buffer per shader is supported before VGPU10.
    * This is only an approximate check against that.
    */
   assert(svga->curr.constbufs[shader][1].buffer == NULL);

   cbuf = &svga->curr.constbufs[shader][0];

   if (svga->curr.constbufs[shader][0].buffer) {
      /* emit user-provided constants */
      data = (const float (*)[4])
         pipe_buffer_map(&svga->pipe, svga->curr.constbufs[shader][0].buffer,
                         PIPE_TRANSFER_READ, &transfer);
      if (!data) {
         return PIPE_ERROR_OUT_OF_MEMORY;
      }

      /* sanity check */
      assert(cbuf->buffer->width0 >=
             cbuf->buffer_size);

      /* Use/apply the constant buffer size and offsets here */
      count = cbuf->buffer_size / (4 * sizeof(float));
      data += cbuf->buffer_offset / (4 * sizeof(float));

      if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) {
         ret = emit_const_range( svga, shader, offset, count, data );
      }
      else {
         for (i = 0; i < count; i++) {
            ret = emit_const( svga, shader, offset + i, data[i] );
            if (ret != PIPE_OK) {
               break;
            }
         }
      }

      pipe_buffer_unmap(&svga->pipe, transfer);

      if (ret != PIPE_OK) {
         return ret;
      }
   }

   /* emit extra shader constants */
   {
      const struct svga_shader_variant *variant = NULL;
      unsigned offset;
      float extras[MAX_EXTRA_CONSTS][4];
      unsigned count, i;

      switch (shader) {
      case PIPE_SHADER_VERTEX:
         variant = svga->state.hw_draw.vs;
         count = svga_get_extra_vs_constants(svga, (float *) extras);
         break;
      case PIPE_SHADER_FRAGMENT:
         variant = svga->state.hw_draw.fs;
         count = svga_get_extra_fs_constants(svga, (float *) extras);
         break;
      default:
         assert(!"Unexpected shader type");
         count = 0;
      }

      assert(variant);
      offset = variant->shader->info.file_max[TGSI_FILE_CONSTANT] + 1;
      assert(count <= ARRAY_SIZE(extras));

      if (count > 0) {
         if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) {
            ret = emit_const_range(svga, shader, offset, count,
                                   (const float (*) [4])extras);
         }
         else {
            for (i = 0; i < count; i++) {
               ret = emit_const(svga, shader, offset + i, extras[i]);
               if (ret != PIPE_OK)
                  return ret;
            }
         }
      }
   }

   return ret;
}