shader: Enable support for passing clipdistances as TGSI array

Since TGSI is vector based it passes clip and cull distances as
values or arrays of vec4 values, but the glsl shader wants to access it
as arrays of scalars. To work around this handle the FS input just like
the outputs, i.e. introduce an array of temporaries vec4 and copy the
data there.

For all other shader types the access to the values only needs to take
account of the possibility of indirect adressing or an array offset.

Signed-off-by: Gert Wollny <gert.wollny@collabora.com>
Reviewed-By: Gurchetan Singh <gurchetansingh@chromium.org>
macos/master
Gert Wollny 6 years ago committed by Gert Wollny
parent f23da8e47a
commit bb76c1aec7
  1. 186
      src/vrend_shader.c

@ -207,6 +207,7 @@ struct dump_ctx {
struct vrend_shader_key *key;
int num_in_clip_dist;
int num_clip_dist;
int fs_uses_clipdist_input;
int glsl_ver_required;
int color_in_mask;
/* only used when cull is enabled */
@ -735,6 +736,27 @@ static int lookup_image_array(struct dump_ctx *ctx, int index)
return -1;
}
static boolean
iter_inputs(struct tgsi_iterate_context *iter,
struct tgsi_full_declaration *decl )
{
struct dump_ctx *ctx = (struct dump_ctx *)iter;
switch (decl->Declaration.File) {
case TGSI_FILE_INPUT:
for (uint32_t j = 0; j < ctx->num_inputs; j++) {
if (ctx->inputs[j].name == decl->Semantic.Name &&
ctx->inputs[j].sid == decl->Semantic.Index &&
ctx->inputs[j].first == decl->Range.First)
return true;
}
ctx->inputs[ctx->num_inputs].name = decl->Semantic.Name;
ctx->inputs[ctx->num_inputs].first = decl->Range.First;
ctx->inputs[ctx->num_inputs].last = decl->Range.Last;
ctx->num_inputs++;
}
return true;
}
static boolean
iter_declaration(struct tgsi_iterate_context *iter,
struct tgsi_full_declaration *decl )
@ -892,15 +914,19 @@ iter_declaration(struct tgsi_iterate_context *iter,
ctx->inputs[i].glsl_predefined_no_emit = true;
ctx->inputs[i].glsl_no_index = true;
ctx->inputs[i].glsl_gl_block = true;
ctx->num_in_clip_dist += 4;
ctx->num_in_clip_dist += 4 * (ctx->inputs[i].last - ctx->inputs[i].first + 1);
ctx->shader_req_bits |= SHADER_REQ_CLIP_DISTANCE;
if (ctx->inputs[i].last != ctx->inputs[i].first)
ctx->guest_sent_io_arrays = true;
break;
} else if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) {
name_prefix = "gl_ClipDistance";
ctx->inputs[i].glsl_predefined_no_emit = true;
ctx->inputs[i].glsl_no_index = true;
ctx->num_in_clip_dist += 4;
ctx->num_in_clip_dist += 4 * (ctx->inputs[i].last - ctx->inputs[i].first + 1);
ctx->shader_req_bits |= SHADER_REQ_CLIP_DISTANCE;
if (ctx->inputs[i].last != ctx->inputs[i].first)
ctx->guest_sent_io_arrays = true;
break;
}
/* fallthrough */
@ -1042,12 +1068,14 @@ iter_declaration(struct tgsi_iterate_context *iter,
name_prefix = "gl_ClipDistance";
ctx->outputs[i].glsl_predefined_no_emit = true;
ctx->outputs[i].glsl_no_index = true;
ctx->num_clip_dist += 4;
ctx->num_clip_dist += 4 * (ctx->outputs[i].last - ctx->outputs[i].first + 1);
if (iter->processor.Processor == TGSI_PROCESSOR_VERTEX &&
(ctx->key->gs_present || ctx->key->tcs_present))
require_glsl_ver(ctx, 150);
if (iter->processor.Processor == TGSI_PROCESSOR_TESS_CTRL)
ctx->outputs[i].glsl_gl_block = true;
if (ctx->outputs[i].last != ctx->outputs[i].first)
ctx->guest_sent_io_arrays = true;
break;
case TGSI_SEMANTIC_CLIPVERTEX:
name_prefix = "gl_ClipVertex";
@ -1654,9 +1682,14 @@ static void emit_so_movs(struct dump_ctx *ctx)
if (ctx->so->output[i].register_index >= 255)
continue;
if (ctx->outputs[ctx->so->output[i].register_index].name == TGSI_SEMANTIC_CLIPDIST) {
emit_buff(ctx, "tfout%d = %s(clip_dist_temp[%d]%s);\n", i, outtype, ctx->outputs[ctx->so->output[i].register_index].sid,
writemask);
if (output->name == TGSI_SEMANTIC_CLIPDIST) {
if (output->first == output->last)
emit_buff(ctx, "tfout%d = %s(clip_dist_temp[%d]%s);\n", i, outtype, output->sid,
writemask);
else
emit_buff(ctx, "tfout%d = %s(clip_dist_temp[%d]%s);\n", i, outtype,
output->sid + ctx->so->output[i].register_index - output->first,
writemask);
} else {
if (ctx->write_so_outputs[i]) {
char out_var[255];
@ -2339,16 +2372,27 @@ create_swizzled_clipdist(struct dump_ctx *ctx,
bool gl_in,
const char *stypeprefix,
const char *prefix,
const char *arrayname)
const char *arrayname, int offset)
{
char clipdistvec[4][64] = {};
int idx;
char clip_indirect[32] = "";
bool has_prev_vals = (ctx->key->prev_stage_num_cull_out + ctx->key->prev_stage_num_clip_out) > 0;
int num_culls = has_prev_vals ? ctx->key->prev_stage_num_cull_out : 0;
int num_clips = has_prev_vals ? ctx->key->prev_stage_num_clip_out : ctx->num_in_clip_dist;
int base_idx = ctx->inputs[input_idx].sid * 4;
/* With arrays enabled , but only when gl_ClipDistance or gl_CullDistance are emitted (>4)
* then we need to add indirect addressing */
if (src->Register.Indirect && ((num_clips > 4 && base_idx < num_clips) || num_culls > 4))
snprintf(clip_indirect, 32, "4*addr%d +", src->Indirect.Index);
else if (src->Register.Index != offset)
snprintf(clip_indirect, 32, "4*%d +", src->Register.Index - offset);
for (unsigned cc = 0; cc < 4; cc++) {
const char *cc_name = ctx->inputs[input_idx].glsl_name;
idx = ctx->inputs[input_idx].sid * 4;
int idx = base_idx;
if (cc == 0)
idx += src->Register.SwizzleX;
else if (cc == 1)
@ -2372,13 +2416,40 @@ create_swizzled_clipdist(struct dump_ctx *ctx,
idx = 0;
}
if (gl_in)
snprintf(clipdistvec[cc], 64, "%sgl_in%s.%s[%d]", prefix, arrayname, cc_name, idx);
snprintf(clipdistvec[cc], 64, "%sgl_in%s.%s[%s %d]", prefix, arrayname, cc_name, clip_indirect, idx);
else
snprintf(clipdistvec[cc], 64, "%s%s%s[%d]", prefix, arrayname, cc_name, idx);
snprintf(clipdistvec[cc], 64, "%s%s%s[%s %d]", prefix, arrayname, cc_name, clip_indirect, idx);
}
snprintf(result, 255, "%s(vec4(%s,%s,%s,%s))", stypeprefix, clipdistvec[0], clipdistvec[1], clipdistvec[2], clipdistvec[3]);
}
static
void load_clipdist_fs(struct dump_ctx *ctx,
char *result,
const struct tgsi_full_src_register *src,
int input_idx,
bool gl_in,
const char *stypeprefix,
int offset)
{
char clip_indirect[32] = "";
int base_idx = ctx->inputs[input_idx].sid;
/* With arrays enabled , but only when gl_ClipDistance or gl_CullDistance are emitted (>4)
* then we need to add indirect addressing */
if (src->Register.Indirect)
snprintf(clip_indirect, 32, "addr%d + %d", src->Indirect.Index, base_idx);
else
snprintf(clip_indirect, 32, "%d + %d", src->Register.Index - offset, base_idx);
if (gl_in)
snprintf(result, 255, "%s(clip_dist_temp[%s])", stypeprefix, clip_indirect);
else
snprintf(result, 255, "%s(clip_dist_temp[%s])", stypeprefix, clip_indirect);
}
static enum vrend_type_qualifier get_coord_prefix(int resource, bool *is_ms)
{
switch(resource) {
@ -2816,7 +2887,14 @@ get_destination_info(struct dump_ctx *ctx,
if (ctx->glsl_ver_required >= 140 && ctx->outputs[j].name == TGSI_SEMANTIC_CLIPVERTEX) {
snprintf(dsts[i], 255, "clipv_tmp");
} else if (ctx->outputs[j].name == TGSI_SEMANTIC_CLIPDIST) {
snprintf(dsts[i], 255, "clip_dist_temp[%d]", ctx->outputs[j].sid);
char clip_indirect[32] = "";
if (ctx->outputs[j].first != ctx->outputs[j].last) {
if (dst_reg->Register.Indirect)
snprintf(clip_indirect, sizeof(clip_indirect), "+ addr%d", dst_reg->Indirect.Index);
else
snprintf(clip_indirect, sizeof(clip_indirect), "+ %d", dst_reg->Register.Index - ctx->outputs[j].first);
}
snprintf(dsts[i], 255, "clip_dist_temp[%d %s]", ctx->outputs[j].sid, clip_indirect);
} else if (ctx->outputs[j].name == TGSI_SEMANTIC_TESSOUTER ||
ctx->outputs[j].name == TGSI_SEMANTIC_TESSINNER ||
ctx->outputs[j].name == TGSI_SEMANTIC_SAMPLEMASK) {
@ -3102,7 +3180,7 @@ get_source_info(struct dump_ctx *ctx,
else if (ctx->inputs[j].glsl_gl_block) {
/* GS input clipdist requires a conversion */
if (ctx->inputs[j].name == TGSI_SEMANTIC_CLIPDIST) {
create_swizzled_clipdist(ctx, srcs[i], src, j, true, get_string(stypeprefix), prefix, arrayname);
create_swizzled_clipdist(ctx, srcs[i], src, j, true, get_string(stypeprefix), prefix, arrayname, ctx->inputs[j].first);
} else {
snprintf(srcs[i], 255, "%s(vec4(%sgl_in%s.%s)%s)", get_string(stypeprefix), prefix, arrayname, ctx->inputs[j].glsl_name, swizzle);
}
@ -3112,7 +3190,10 @@ get_source_info(struct dump_ctx *ctx,
else if (ctx->inputs[j].name == TGSI_SEMANTIC_FACE)
snprintf(srcs[i], 255, "%s(%s ? 1.0 : -1.0)", get_string(stypeprefix), ctx->inputs[j].glsl_name);
else if (ctx->inputs[j].name == TGSI_SEMANTIC_CLIPDIST) {
create_swizzled_clipdist(ctx, srcs[i], src, j, false, get_string(stypeprefix), prefix, arrayname);
if (ctx->prog_type == TGSI_PROCESSOR_FRAGMENT)
load_clipdist_fs(ctx, srcs[i], src, j, false, get_string(stypeprefix), ctx->inputs[j].first);
else
create_swizzled_clipdist(ctx, srcs[i], src, j, false, get_string(stypeprefix), prefix, arrayname, ctx->inputs[j].first);
} else {
enum vrend_type_qualifier srcstypeprefix = stypeprefix;
if ((stype == TGSI_TYPE_UNSIGNED || stype == TGSI_TYPE_SIGNED) &&
@ -3147,7 +3228,14 @@ get_source_info(struct dump_ctx *ctx,
srcstypeprefix = TYPE_CONVERSION_NONE;
if (ctx->outputs[j].glsl_gl_block) {
if (ctx->outputs[j].name == TGSI_SEMANTIC_CLIPDIST) {
snprintf(srcs[i], 255, "clip_dist_temp[%d]", ctx->outputs[j].sid);
char clip_indirect[32] = "";
if (ctx->outputs[j].first != ctx->outputs[j].last) {
if (src->Register.Indirect)
snprintf(clip_indirect, sizeof(clip_indirect), "+ addr%d", src->Indirect.Index);
else
snprintf(clip_indirect, sizeof(clip_indirect), "+ %d", src->Register.Index - ctx->outputs[j].first);
}
snprintf(srcs[i], 255, "clip_dist_temp[%d%s]", ctx->outputs[j].sid, clip_indirect);
}
} else if (ctx->outputs[j].name == TGSI_SEMANTIC_GENERIC) {
struct vrend_shader_io *io = ctx->generic_output_range.used ? &ctx->generic_output_range.io : &ctx->outputs[j];
@ -3541,6 +3629,47 @@ void rewrite_io_ranged(struct dump_ctx *ctx)
}
static
void emit_fs_clipdistance_load(struct dump_ctx *ctx)
{
int i;
if (!ctx->fs_uses_clipdist_input)
return;
int prev_num = ctx->key->prev_stage_num_clip_out + ctx->key->prev_stage_num_cull_out;
int ndists;
const char *prefix="";
if (ctx->prog_type == PIPE_SHADER_TESS_CTRL)
prefix = "gl_out[gl_InvocationID].";
ndists = ctx->num_in_clip_dist;
if (prev_num > 0)
ndists = prev_num;
for (i = 0; i < ndists; i++) {
int clipidx = i < 4 ? 0 : 1;
char swiz = i & 3;
char wm = 0;
switch (swiz) {
default:
case 0: wm = 'x'; break;
case 1: wm = 'y'; break;
case 2: wm = 'z'; break;
case 3: wm = 'w'; break;
}
bool is_cull = false;
if (prev_num > 0) {
if (i >= ctx->key->prev_stage_num_clip_out && i < prev_num)
is_cull = true;
}
const char *clip_cull = is_cull ? "Cull" : "Clip";
emit_buff(ctx, "clip_dist_temp[%d].%c = %sgl_%sDistance[%d];\n", clipidx, wm, prefix, clip_cull,
is_cull ? i - ctx->key->prev_stage_num_clip_out : i);
}
}
static boolean
iter_instruction(struct tgsi_iterate_context *iter,
@ -3571,6 +3700,8 @@ iter_instruction(struct tgsi_iterate_context *iter,
emit_buf(ctx, "void main(void)\n{\n");
if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) {
emit_color_select(ctx);
if (ctx->fs_uses_clipdist_input)
emit_fs_clipdistance_load(ctx);
}
if (ctx->so)
prepare_so_movs(ctx);
@ -4917,10 +5048,15 @@ static void emit_ios_fs(struct dump_ctx *ctx)
if (ctx->num_in_clip_dist) {
if (ctx->key->prev_stage_num_clip_out) {
emit_hdrf(ctx, "in float gl_ClipDistance[%d];\n", ctx->key->prev_stage_num_clip_out);
} else if (ctx->num_in_clip_dist > 4 && !ctx->key->prev_stage_num_cull_out) {
emit_hdrf(ctx, "in float gl_ClipDistance[%d];\n", ctx->num_in_clip_dist);
}
if (ctx->key->prev_stage_num_cull_out) {
emit_hdrf(ctx, "in float gl_CullDistance[%d];\n", ctx->key->prev_stage_num_cull_out);
}
if(ctx->fs_uses_clipdist_input)
emit_hdr(ctx, "vec4 clip_dist_temp[2];\n");
}
}
@ -5271,6 +5407,22 @@ static boolean analyze_instruction(struct tgsi_iterate_context *iter,
ctx->integer_memory = true;
}
if (!ctx->fs_uses_clipdist_input && (ctx->prog_type == TGSI_PROCESSOR_FRAGMENT)) {
for (int i = 0; i < inst->Instruction.NumSrcRegs; ++i) {
if (inst->Src[i].Register.File == TGSI_FILE_INPUT) {
int idx = inst->Src[i].Register.Index;
for (unsigned j = 0; j < ctx->num_inputs; ++j) {
if (ctx->inputs[j].first <= idx && ctx->inputs[j].last >= idx &&
ctx->inputs[j].name == TGSI_SEMANTIC_CLIPDIST) {
ctx->fs_uses_clipdist_input = true;
break;
}
}
}
}
}
return true;
}
@ -5288,11 +5440,15 @@ bool vrend_convert_shader(struct vrend_context *rctx,
memset(&ctx, 0, sizeof(struct dump_ctx));
/* First pass to deal with edge cases. */
if (ctx.prog_type == TGSI_PROCESSOR_FRAGMENT)
ctx.iter.iterate_declaration = iter_inputs;
ctx.iter.iterate_instruction = analyze_instruction;
bret = tgsi_iterate_shader(tokens, &ctx.iter);
if (bret == false)
return false;
ctx.num_inputs = 0;
ctx.iter.prolog = prolog;
ctx.iter.iterate_instruction = iter_instruction;
ctx.iter.iterate_declaration = iter_declaration;

Loading…
Cancel
Save