/* Samplers */
unsigned num_samplers;
+ ubyte sampler_target[PIPE_MAX_SAMPLERS]; /**< TGSI_TEXTURE_x */
+ ubyte sampler_return_type[PIPE_MAX_SAMPLERS]; /**< TGSI_RETURN_TYPE_x */
/* Address regs (really implemented with temps) */
unsigned num_address_regs;
/* user clip plane constant slot indexes */
unsigned clip_plane_const[PIPE_MAX_CLIP_PLANES];
+ unsigned num_output_writes;
+ boolean constant_color_output;
+
boolean uses_flat_interp;
/* For all shaders: const reg index for RECT coord scaling */
else
new_buf = NULL;
- if (new_buf == NULL) {
+ if (!new_buf) {
emit->ptr = err_buf;
emit->buf = err_buf;
emit->size = sizeof(err_buf);
*/
assert(sem_name == TGSI_SEMANTIC_COLOR);
index = emit->info.output_semantic_index[index];
+
+ emit->num_output_writes++;
}
}
}
static unsigned
alloc_system_value_index(struct svga_shader_emitter_v10 *emit, unsigned index)
{
- const unsigned n = emit->info.num_inputs + index;
+ const unsigned n = emit->info.file_max[TGSI_FILE_INPUT] + 1 + index;
assert(index < Elements(emit->system_value_indexes));
emit->system_value_indexes[index] = n;
return n;
emit->num_samplers = MAX2(emit->num_samplers, decl->Range.Last + 1);
return TRUE;
+#if 0
case TGSI_FILE_RESOURCE:
/*opcode0.opcodeType = VGPU10_OPCODE_DCL_RESOURCE;*/
/* XXX more, VGPU10_RETURN_TYPE_FLOAT */
assert(!"TGSI_FILE_RESOURCE not handled yet");
return FALSE;
+#endif
case TGSI_FILE_ADDRESS:
emit->num_address_regs = MAX2(emit->num_address_regs,
return TRUE;
case TGSI_FILE_SAMPLER_VIEW:
- /* Not used at this time, but maybe in the future.
- * See emit_resource_declarations().
- */
+ {
+ unsigned unit = decl->Range.First;
+ assert(decl->Range.First == decl->Range.Last);
+ emit->sampler_target[unit] = decl->SamplerView.Resource;
+ /* Note: we can ignore YZW return types for now */
+ emit->sampler_return_type[unit] = decl->SamplerView.ReturnTypeX;
+ }
return TRUE;
default:
else {
assert(emit->unit == PIPE_SHADER_VERTEX);
- for (i = 0; i < emit->info.num_inputs; i++) {
+ for (i = 0; i < emit->info.file_max[TGSI_FILE_INPUT] + 1; i++) {
unsigned usage_mask = emit->info.input_usage_mask[i];
unsigned index = i;
}
else if (emit->unit == PIPE_SHADER_FRAGMENT) {
if (emit->key.fs.alpha_func != SVGA3D_CMP_ALWAYS ||
+ emit->key.fs.white_fragments ||
emit->key.fs.write_color0_to_n_cbufs > 1) {
/* Allocate a temp to hold the output color */
emit->fs.color_tmp_index = total_temps;
/* Texture buffer sizes */
for (i = 0; i < emit->num_samplers; i++) {
- if (emit->key.tex[i].texture_target == PIPE_BUFFER) {
+ if (emit->sampler_target[i] == TGSI_TEXTURE_BUFFER) {
emit->texture_buffer_size_index[i] = total_consts++;
}
}
/**
- * Translate PIPE_TEXTURE_x to VGAPU10_RESOURCE_DIMENSION_x.
+ * Translate TGSI_TEXTURE_x to VGAPU10_RESOURCE_DIMENSION_x.
*/
static unsigned
-pipe_texture_to_resource_dimension(unsigned target, bool msaa)
+tgsi_texture_to_resource_dimension(unsigned target, boolean is_array)
{
switch (target) {
- case PIPE_BUFFER:
+ case TGSI_TEXTURE_BUFFER:
return VGPU10_RESOURCE_DIMENSION_BUFFER;
- case PIPE_TEXTURE_1D:
+ case TGSI_TEXTURE_1D:
return VGPU10_RESOURCE_DIMENSION_TEXTURE1D;
- case PIPE_TEXTURE_2D:
- case PIPE_TEXTURE_RECT:
- return msaa ? VGPU10_RESOURCE_DIMENSION_TEXTURE2DMS
- : VGPU10_RESOURCE_DIMENSION_TEXTURE2D;
- case PIPE_TEXTURE_3D:
+ case TGSI_TEXTURE_2D:
+ case TGSI_TEXTURE_RECT:
+ return VGPU10_RESOURCE_DIMENSION_TEXTURE2D;
+ case TGSI_TEXTURE_3D:
return VGPU10_RESOURCE_DIMENSION_TEXTURE3D;
- case PIPE_TEXTURE_CUBE:
+ case TGSI_TEXTURE_CUBE:
+ return VGPU10_RESOURCE_DIMENSION_TEXTURECUBE;
+ case TGSI_TEXTURE_SHADOW1D:
+ return VGPU10_RESOURCE_DIMENSION_TEXTURE1D;
+ case TGSI_TEXTURE_SHADOW2D:
+ case TGSI_TEXTURE_SHADOWRECT:
+ return VGPU10_RESOURCE_DIMENSION_TEXTURE2D;
+ case TGSI_TEXTURE_1D_ARRAY:
+ case TGSI_TEXTURE_SHADOW1D_ARRAY:
+ return is_array ? VGPU10_RESOURCE_DIMENSION_TEXTURE1DARRAY
+ : VGPU10_RESOURCE_DIMENSION_TEXTURE1D;
+ case TGSI_TEXTURE_2D_ARRAY:
+ case TGSI_TEXTURE_SHADOW2D_ARRAY:
+ return is_array ? VGPU10_RESOURCE_DIMENSION_TEXTURE2DARRAY
+ : VGPU10_RESOURCE_DIMENSION_TEXTURE2D;
+ case TGSI_TEXTURE_SHADOWCUBE:
return VGPU10_RESOURCE_DIMENSION_TEXTURECUBE;
- case PIPE_TEXTURE_1D_ARRAY:
- return VGPU10_RESOURCE_DIMENSION_TEXTURE1DARRAY;
- case PIPE_TEXTURE_2D_ARRAY:
- return msaa ? VGPU10_RESOURCE_DIMENSION_TEXTURE2DMSARRAY
- : VGPU10_RESOURCE_DIMENSION_TEXTURE2DARRAY;
- case PIPE_TEXTURE_CUBE_ARRAY:
+ case TGSI_TEXTURE_2D_MSAA:
+ return VGPU10_RESOURCE_DIMENSION_TEXTURE2DMS;
+ case TGSI_TEXTURE_2D_ARRAY_MSAA:
+ return is_array ? VGPU10_RESOURCE_DIMENSION_TEXTURE2DMSARRAY
+ : VGPU10_RESOURCE_DIMENSION_TEXTURE2DMS;
+ case TGSI_TEXTURE_CUBE_ARRAY:
return VGPU10_RESOURCE_DIMENSION_TEXTURECUBEARRAY;
default:
assert(!"Unexpected resource type");
opcode0.value = 0;
opcode0.opcodeType = VGPU10_OPCODE_DCL_RESOURCE;
opcode0.resourceDimension =
- pipe_texture_to_resource_dimension(emit->key.tex[i].texture_target,
- emit->key.tex[i].texture_msaa);
+ tgsi_texture_to_resource_dimension(emit->sampler_target[i],
+ emit->key.tex[i].is_array);
operand0.value = 0;
operand0.numComponents = VGPU10_OPERAND_0_COMPONENT;
operand0.operandType = VGPU10_OPERAND_TYPE_RESOURCE;
STATIC_ASSERT(VGPU10_RETURN_TYPE_SINT == TGSI_RETURN_TYPE_SINT + 1);
STATIC_ASSERT(VGPU10_RETURN_TYPE_UINT == TGSI_RETURN_TYPE_UINT + 1);
STATIC_ASSERT(VGPU10_RETURN_TYPE_FLOAT == TGSI_RETURN_TYPE_FLOAT + 1);
- assert(emit->key.tex[i].return_type <= TGSI_RETURN_TYPE_FLOAT);
- rt = emit->key.tex[i].return_type + 1;
+ assert(emit->sampler_return_type[i] <= TGSI_RETURN_TYPE_FLOAT);
+ rt = emit->sampler_return_type[i] + 1;
#else
- switch (emit->key.tex[i].return_type) {
+ switch (emit->sampler_return_type[i]) {
case TGSI_RETURN_TYPE_UNORM: rt = VGPU10_RETURN_TYPE_UNORM; break;
case TGSI_RETURN_TYPE_SNORM: rt = VGPU10_RETURN_TYPE_SNORM; break;
case TGSI_RETURN_TYPE_SINT: rt = VGPU10_RETURN_TYPE_SINT; break;
unsigned i;
unsigned clip_plane_enable = emit->key.clip_plane_enable;
unsigned clip_dist_tmp_index = emit->clip_dist_tmp_index;
- unsigned num_written_clipdist = emit->info.num_written_clipdistance;
+ int num_written_clipdist = emit->info.num_written_clipdistance;
assert(emit->clip_dist_out_index != INVALID_INDEX);
assert(emit->clip_dist_tmp_index != INVALID_INDEX);
*/
emit->clip_dist_tmp_index = INVALID_INDEX;
- for (i = 0; i < 2 && num_written_clipdist; i++, num_written_clipdist-=4) {
+ for (i = 0; i < 2 && num_written_clipdist > 0; i++, num_written_clipdist-=4) {
tmp_clip_dist_src = make_src_temp_reg(clip_dist_tmp_index + i);
unsigned swz_b = emit->key.tex[swz->unit].swizzle_b;
unsigned swz_a = emit->key.tex[swz->unit].swizzle_a;
unsigned writemask_0 = 0, writemask_1 = 0;
- boolean int_tex = is_integer_type(emit->key.tex[swz->unit].return_type);
+ boolean int_tex = is_integer_type(emit->sampler_return_type[swz->unit]);
/* Swizzle w/out zero/one terms */
struct tgsi_full_src_register src_swizzled =
swizzle_src(&swz->tmp_src,
- swz_r < PIPE_SWIZZLE_ZERO ? swz_r : PIPE_SWIZZLE_RED,
- swz_g < PIPE_SWIZZLE_ZERO ? swz_g : PIPE_SWIZZLE_GREEN,
- swz_b < PIPE_SWIZZLE_ZERO ? swz_b : PIPE_SWIZZLE_BLUE,
- swz_a < PIPE_SWIZZLE_ZERO ? swz_a : PIPE_SWIZZLE_ALPHA);
+ swz_r < PIPE_SWIZZLE_0 ? swz_r : PIPE_SWIZZLE_X,
+ swz_g < PIPE_SWIZZLE_0 ? swz_g : PIPE_SWIZZLE_Y,
+ swz_b < PIPE_SWIZZLE_0 ? swz_b : PIPE_SWIZZLE_Z,
+ swz_a < PIPE_SWIZZLE_0 ? swz_a : PIPE_SWIZZLE_W);
/* MOV dst, color(tmp).<swizzle> */
emit_instruction_op1(emit, VGPU10_OPCODE_MOV,
swz->inst_dst, &src_swizzled, FALSE);
/* handle swizzle zero terms */
- writemask_0 = (((swz_r == PIPE_SWIZZLE_ZERO) << 0) |
- ((swz_g == PIPE_SWIZZLE_ZERO) << 1) |
- ((swz_b == PIPE_SWIZZLE_ZERO) << 2) |
- ((swz_a == PIPE_SWIZZLE_ZERO) << 3));
+ writemask_0 = (((swz_r == PIPE_SWIZZLE_0) << 0) |
+ ((swz_g == PIPE_SWIZZLE_0) << 1) |
+ ((swz_b == PIPE_SWIZZLE_0) << 2) |
+ ((swz_a == PIPE_SWIZZLE_0) << 3));
if (writemask_0) {
struct tgsi_full_src_register zero = int_tex ?
}
/* handle swizzle one terms */
- writemask_1 = (((swz_r == PIPE_SWIZZLE_ONE) << 0) |
- ((swz_g == PIPE_SWIZZLE_ONE) << 1) |
- ((swz_b == PIPE_SWIZZLE_ONE) << 2) |
- ((swz_a == PIPE_SWIZZLE_ONE) << 3));
+ writemask_1 = (((swz_r == PIPE_SWIZZLE_1) << 0) |
+ ((swz_g == PIPE_SWIZZLE_1) << 1) |
+ ((swz_b == PIPE_SWIZZLE_1) << 2) |
+ ((swz_a == PIPE_SWIZZLE_1) << 3));
if (writemask_1) {
struct tgsi_full_src_register one = int_tex ?
boolean valid = TRUE;
if (tgsi_is_shadow_target(target) &&
- is_integer_type(emit->key.tex[unit].return_type)) {
+ is_integer_type(emit->sampler_return_type[unit])) {
debug_printf("Invalid SAMPLE_C with an integer texture!\n");
valid = FALSE;
}
const struct tgsi_full_instruction *inst)
{
const uint unit = inst->Src[1].Register.Index;
- const unsigned msaa = emit->key.tex[unit].texture_msaa;
+ const boolean msaa = tgsi_is_msaa_target(inst->Texture.Texture);
int offsets[3];
struct tex_swizzle_info swz_info;
{
const uint unit = inst->Src[1].Register.Index;
- if (emit->key.tex[unit].texture_target == PIPE_BUFFER) {
+ if (emit->sampler_target[unit] == TGSI_TEXTURE_BUFFER) {
/* RESINFO does not support querying texture buffers, so we instead
* store texture buffer sizes in shader constants, then copy them to
* implement TXQ instead of emitting RESINFO.
}
+/**
+ * We only special case the MOV instruction to try to detect constant
+ * color writes in the fragment shader.
+ */
+static boolean
+emit_mov(struct svga_shader_emitter_v10 *emit,
+ const struct tgsi_full_instruction *inst)
+{
+ const struct tgsi_full_src_register *src = &inst->Src[0];
+ const struct tgsi_full_dst_register *dst = &inst->Dst[0];
+
+ if (emit->unit == PIPE_SHADER_FRAGMENT &&
+ dst->Register.File == TGSI_FILE_OUTPUT &&
+ dst->Register.Index == 0 &&
+ src->Register.File == TGSI_FILE_CONSTANT &&
+ !src->Register.Indirect) {
+ emit->constant_color_output = TRUE;
+ }
+
+ return emit_simple(emit, inst);
+}
+
+
/**
* Emit a simple VGPU10 instruction which writes to multiple dest registers,
* where TGSI only uses one dest register.
case TGSI_OPCODE_MAD:
case TGSI_OPCODE_MAX:
case TGSI_OPCODE_MIN:
- case TGSI_OPCODE_MOV:
case TGSI_OPCODE_MUL:
case TGSI_OPCODE_NOP:
case TGSI_OPCODE_NOT:
/* simple instructions */
return emit_simple(emit, inst);
-
+ case TGSI_OPCODE_MOV:
+ return emit_mov(emit, inst);
case TGSI_OPCODE_EMIT:
return emit_vertex(emit, inst);
case TGSI_OPCODE_ENDPRIM:
while (adjust_mask) {
unsigned index = u_bit_scan(&adjust_mask);
+
+ /* skip the instruction if this vertex attribute is not being used */
+ if (emit->info.input_usage_mask[index] == 0)
+ continue;
+
unsigned tmp = emit->vs.adjusted_input[index];
struct tgsi_full_src_register input_src =
make_src_reg(TGSI_FILE_INPUT, index);
emit_src_register(emit, &tmp_src_x);
end_emit_instruction(emit);
- /* If we don't need to broadcast the color below, emit final color here */
- if (emit->key.fs.write_color0_to_n_cbufs <= 1) {
+ /* If we don't need to broadcast the color below or set fragments to
+ * white, emit final color here.
+ */
+ if (emit->key.fs.write_color0_to_n_cbufs <= 1 &&
+ !emit->key.fs.white_fragments) {
/* MOV output.color, tempcolor */
emit_instruction_op1(emit, VGPU10_OPCODE_MOV, &color_dst,
&color_src, FALSE); /* XXX saturate? */
}
+/**
+ * When we need to emit white for all fragments (for emulating XOR logicop
+ * mode), this function copies white into the temporary color output register.
+ */
+static void
+emit_set_color_white(struct svga_shader_emitter_v10 *emit,
+ unsigned fs_color_tmp_index)
+{
+ struct tgsi_full_dst_register color_dst =
+ make_dst_temp_reg(fs_color_tmp_index);
+ struct tgsi_full_src_register white =
+ make_immediate_reg_float(emit, 1.0f);
+
+ emit_instruction_op1(emit, VGPU10_OPCODE_MOV, &color_dst, &white, FALSE);
+}
+
+
/**
* Emit instructions for writing a single color output to multiple
* color buffers.
- * This is used when the TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS
+ * This is used when the TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS (or
+ * when key.fs.white_fragments is true).
* property is set and the number of render targets is greater than one.
* \param fs_color_tmp_index index of the temp register that holds the
* color to broadcast.
make_src_temp_reg(fs_color_tmp_index);
assert(emit->unit == PIPE_SHADER_FRAGMENT);
- assert(n > 1);
for (i = 0; i < n; i++) {
unsigned output_reg = emit->fs.color_out_index[i];
if (emit->key.fs.alpha_func != SVGA3D_CMP_ALWAYS) {
emit_alpha_test_instructions(emit, fs_color_tmp_index);
}
- if (emit->key.fs.write_color0_to_n_cbufs > 1) {
+ if (emit->key.fs.white_fragments) {
+ emit_set_color_white(emit, fs_color_tmp_index);
+ }
+ if (emit->key.fs.write_color0_to_n_cbufs > 1 ||
+ emit->key.fs.white_fragments) {
emit_broadcast_color_instructions(emit, fs_color_tmp_index);
}
}
tgsi_dump(tokens,0);
}
- new_tokens = util_pstipple_create_fragment_shader(tokens, &unit, 0);
+ new_tokens = util_pstipple_create_fragment_shader(tokens, &unit, 0,
+ TGSI_FILE_INPUT);
emit->fs.pstipple_sampler_unit = unit;
/* Setup texture state for stipple */
- emit->key.tex[unit].texture_target = PIPE_TEXTURE_2D;
+ emit->sampler_target[unit] = TGSI_TEXTURE_2D;
emit->key.tex[unit].swizzle_r = TGSI_SWIZZLE_X;
emit->key.tex[unit].swizzle_g = TGSI_SWIZZLE_Y;
emit->key.tex[unit].swizzle_b = TGSI_SWIZZLE_Z;
variant->pstipple_sampler_unit = emit->fs.pstipple_sampler_unit;
+ /* If there was exactly one write to a fragment shader output register
+ * and it came from a constant buffer, we know all fragments will have
+ * the same color (except for blending).
+ */
+ variant->constant_color_output =
+ emit->constant_color_output && emit->num_output_writes == 1;
+
/** keep track in the variant if flat interpolation is used
* for any of the varyings.
*/