vrend,shader: Inject a TC shader if it is missing on GLES

On D-GL a program may contain a TE shader but no TC shader. On  GLES either
both or none of TES and TCS need to be available. So if the guest sends a
shader program without a TCS, inject a passthrough shader using the
patch parameters given in the GL code.

Closes #84

Signed-off-by: Gert Wollny <gert.wollny@collabora.com>
Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>
macos/master
Gert Wollny 6 years ago
parent f9f7bd64f7
commit faf23ce917
  1. 68
      src/vrend_renderer.c
  2. 208
      src/vrend_shader.c
  3. 9
      src/vrend_shader.h

@ -271,6 +271,9 @@ struct global_renderer_state {
pipe_thread sync_thread;
virgl_gl_context sync_context;
/* Needed on GLES to inject a TCS */
float tess_factors[6];
};
static struct global_renderer_state vrend_state;
@ -2993,7 +2996,7 @@ static inline void vrend_fill_shader_key(struct vrend_context *ctx,
if (!ctx->shader_cfg.use_gles)
next_type = PIPE_SHADER_TESS_EVAL;
else
report_context_error(ctx, VIRGL_ERROR_CTX_GLES_HAVE_TES_BUT_MISS_TCS, 0);
next_type = PIPE_SHADER_TESS_CTRL;
} else
next_type = PIPE_SHADER_FRAGMENT;
break;
@ -3037,20 +3040,23 @@ static int vrend_shader_create(struct vrend_context *ctx,
struct vrend_shader_key key)
{
if (!shader->sel->tokens) {
report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0);
return -1;
}
shader->id = glCreateShader(conv_shader_type(shader->sel->type));
shader->compiled_fs_id = 0;
if (shader->sel->tokens) {
bool ret = vrend_convert_shader(ctx, &ctx->shader_cfg, shader->sel->tokens,
shader->sel->req_local_mem, &key, &shader->sel->sinfo, &shader->glsl_strings);
if (!ret) {
report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0);
report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, shader->sel->type);
glDeleteShader(shader->id);
return -1;
}
} else if (!ctx->shader_cfg.use_gles && shader->sel->type != TGSI_PROCESSOR_TESS_CTRL) {
report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, shader->sel->type);
glDeleteShader(shader->id);
return -1;
}
shader->key = key;
if (1) {//shader->sel->type == PIPE_SHADER_FRAGMENT || shader->sel->type == PIPE_SHADER_GEOMETRY) {
bool ret;
@ -3967,6 +3973,38 @@ static void vrend_draw_bind_objects(struct vrend_context *ctx, bool new_program)
}
}
static
void vrend_inject_tcs(struct vrend_context *ctx, int vertices_per_patch)
{
struct pipe_stream_output_info so_info;
memset(&so_info, 0, sizeof(so_info));
struct vrend_shader_selector *sel = vrend_create_shader_state(ctx,
&so_info,
false, PIPE_SHADER_TESS_CTRL);
struct vrend_shader *shader;
shader = CALLOC_STRUCT(vrend_shader);
vrend_fill_shader_key(ctx, sel->type, &shader->key);
shader->sel = sel;
list_inithead(&shader->programs);
strarray_alloc(&shader->glsl_strings, SHADER_MAX_STRINGS);
vrend_shader_create_passthrough_tcs(ctx, &ctx->shader_cfg,
ctx->sub->shaders[PIPE_SHADER_VERTEX]->tokens,
&shader->key, vrend_state.tess_factors, &sel->sinfo,
&shader->glsl_strings, vertices_per_patch);
// Need to add inject the selected shader to the shader selector and then the code below
// can continue
sel->tokens = NULL;
sel->current = shader;
ctx->sub->shaders[PIPE_SHADER_TESS_CTRL] = sel;
ctx->sub->shaders[PIPE_SHADER_TESS_CTRL]->num_shaders = 1;
shader->id = glCreateShader(conv_shader_type(shader->sel->type));
vrend_compile_shader(ctx, shader);
}
int vrend_draw_vbo(struct vrend_context *ctx,
const struct pipe_draw_info *info,
uint32_t cso, uint32_t indirect_handle,
@ -4040,8 +4078,16 @@ int vrend_draw_vbo(struct vrend_context *ctx,
}
vrend_shader_select(ctx, ctx->sub->shaders[PIPE_SHADER_VERTEX], &vs_dirty);
if (ctx->sub->shaders[PIPE_SHADER_TESS_CTRL])
if (ctx->sub->shaders[PIPE_SHADER_TESS_CTRL] && ctx->sub->shaders[PIPE_SHADER_TESS_CTRL]->tokens)
vrend_shader_select(ctx, ctx->sub->shaders[PIPE_SHADER_TESS_CTRL], &tcs_dirty);
else if (vrend_state.use_gles && ctx->sub->shaders[PIPE_SHADER_TESS_EVAL]) {
VREND_DEBUG(dbg_shader, ctx, "Need to inject a TCS\n");
vrend_inject_tcs(ctx, info->vertices_per_patch);
vrend_shader_select(ctx, ctx->sub->shaders[PIPE_SHADER_VERTEX], &vs_dirty);
}
if (ctx->sub->shaders[PIPE_SHADER_TESS_EVAL])
vrend_shader_select(ctx, ctx->sub->shaders[PIPE_SHADER_TESS_EVAL], &tes_dirty);
if (ctx->sub->shaders[PIPE_SHADER_GEOMETRY])
@ -7092,9 +7138,13 @@ void vrend_set_min_samples(struct vrend_context *ctx, unsigned min_samples)
void vrend_set_tess_state(UNUSED struct vrend_context *ctx, const float tess_factors[6])
{
if (has_feature(feat_tessellation) && !vrend_state.use_gles) {
if (has_feature(feat_tessellation)) {
if (!vrend_state.use_gles) {
glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, tess_factors);
glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, &tess_factors[4]);
} else {
memcpy(vrend_state.tess_factors, tess_factors, 6 * sizeof (float));
}
}
}

@ -6298,7 +6298,7 @@ static bool allocate_strbuffers(struct dump_ctx* ctx)
return true;
}
static bool set_strbuffers(struct vrend_context *rctx, struct dump_ctx* ctx,
static void set_strbuffers(struct vrend_context *rctx, struct dump_ctx* ctx,
struct vrend_strarray *shader)
{
strarray_addstrbuf(shader, &ctx->glsl_ver_ext);
@ -6512,3 +6512,209 @@ bool vrend_patch_vertex_shader_interpolants(struct vrend_context *rctx,
return true;
}
static boolean
iter_vs_declaration(struct tgsi_iterate_context *iter,
struct tgsi_full_declaration *decl)
{
struct dump_ctx *ctx = (struct dump_ctx *)iter;
const char *shader_in_prefix = "vso";
const char *shader_out_prefix = "tco";
const char *name_prefix = "";
unsigned i;
unsigned mask_temp;
// Generate a shader that passes through all VS outputs
if (decl->Declaration.File == TGSI_FILE_OUTPUT) {
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 &&
ctx->inputs[j].usage_mask == decl->Declaration.UsageMask &&
((!decl->Declaration.Array && ctx->inputs[j].array_id == 0) ||
(ctx->inputs[j].array_id == decl->Array.ArrayID)))
return true;
}
i = ctx->num_inputs++;
ctx->inputs[i].name = decl->Semantic.Name;
ctx->inputs[i].sid = decl->Semantic.Index;
ctx->inputs[i].interpolate = decl->Interp.Interpolate;
ctx->inputs[i].location = decl->Interp.Location;
ctx->inputs[i].first = decl->Range.First;
ctx->inputs[i].layout_location = 0;
ctx->inputs[i].last = decl->Range.Last;
ctx->inputs[i].array_id = decl->Declaration.Array ? decl->Array.ArrayID : 0;
ctx->inputs[i].usage_mask = mask_temp = decl->Declaration.UsageMask;
u_bit_scan_consecutive_range(&mask_temp, &ctx->inputs[i].swizzle_offset, &ctx->inputs[i].num_components);
ctx->inputs[i].glsl_predefined_no_emit = false;
ctx->inputs[i].glsl_no_index = false;
ctx->inputs[i].override_no_wm = ctx->inputs[i].num_components == 1;
ctx->inputs[i].glsl_gl_block = false;
switch (ctx->inputs[i].name) {
case TGSI_SEMANTIC_PSIZE:
name_prefix = "gl_PointSize";
ctx->inputs[i].glsl_predefined_no_emit = true;
ctx->inputs[i].glsl_no_index = true;
ctx->inputs[i].override_no_wm = true;
ctx->inputs[i].glsl_gl_block = true;
ctx->shader_req_bits |= SHADER_REQ_PSIZE;
break;
case TGSI_SEMANTIC_CLIPDIST:
name_prefix = "gl_ClipDistance";
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->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;
case TGSI_SEMANTIC_POSITION:
name_prefix = "gl_Position";
ctx->inputs[i].glsl_predefined_no_emit = true;
ctx->inputs[i].glsl_no_index = true;
ctx->inputs[i].glsl_gl_block = true;
break;
case TGSI_SEMANTIC_PATCH:
case TGSI_SEMANTIC_GENERIC:
if (ctx->inputs[i].first != ctx->inputs[i].last ||
ctx->inputs[i].array_id > 0) {
ctx->guest_sent_io_arrays = true;
if (!ctx->cfg->use_gles)
ctx->shader_req_bits |= SHADER_REQ_ARRAYS_OF_ARRAYS;
}
break;
default:
break;
}
memcpy(&ctx->outputs[i], &ctx->inputs[i], sizeof(struct vrend_shader_io));
if (ctx->inputs[i].glsl_no_index) {
snprintf(ctx->inputs[i].glsl_name, 128, "%s", name_prefix);
snprintf(ctx->outputs[i].glsl_name, 128, "%s", name_prefix);
} else {
if (ctx->inputs[i].name == TGSI_SEMANTIC_FOG){
ctx->inputs[i].usage_mask = 0xf;
ctx->inputs[i].num_components = 4;
ctx->inputs[i].swizzle_offset = 0;
ctx->inputs[i].override_no_wm = false;
snprintf(ctx->inputs[i].glsl_name, 64, "%s_f%d", shader_in_prefix, ctx->inputs[i].sid);
snprintf(ctx->outputs[i].glsl_name, 64, "%s_f%d", shader_out_prefix, ctx->inputs[i].sid);
} else if (ctx->inputs[i].name == TGSI_SEMANTIC_COLOR) {
snprintf(ctx->inputs[i].glsl_name, 64, "%s_c%d", shader_in_prefix, ctx->inputs[i].sid);
snprintf(ctx->outputs[i].glsl_name, 64, "%s_c%d", shader_out_prefix, ctx->inputs[i].sid);
} else if (ctx->inputs[i].name == TGSI_SEMANTIC_GENERIC) {
snprintf(ctx->inputs[i].glsl_name, 64, "%s_g%dA%d_%x",
shader_in_prefix, ctx->inputs[i].sid,
ctx->inputs[i].array_id, ctx->inputs[i].usage_mask);
snprintf(ctx->outputs[i].glsl_name, 64, "%s_g%dA%d_%x",
shader_out_prefix, ctx->inputs[i].sid,
ctx->inputs[i].array_id, ctx->inputs[i].usage_mask);
} else if (ctx->inputs[i].name == TGSI_SEMANTIC_PATCH) {
snprintf(ctx->inputs[i].glsl_name, 64, "%s_p%dA%d_%x",
shader_in_prefix, ctx->inputs[i].sid,
ctx->inputs[i].array_id, ctx->inputs[i].usage_mask);
snprintf(ctx->outputs[i].glsl_name, 64, "%s_p%dA%d_%x",
shader_out_prefix, ctx->inputs[i].sid,
ctx->inputs[i].array_id, ctx->inputs[i].usage_mask);
} else {
snprintf(ctx->outputs[i].glsl_name, 64, "%s_%d", shader_in_prefix, ctx->inputs[i].first);
snprintf(ctx->inputs[i].glsl_name, 64, "%s_%d", shader_out_prefix, ctx->inputs[i].first);
}
}
}
return true;
}
bool vrend_shader_create_passthrough_tcs(struct vrend_context *rctx,
struct vrend_shader_cfg *cfg,
struct tgsi_token *vs_tokens,
struct vrend_shader_key *key,
const float tess_factors[6],
struct vrend_shader_info *sinfo,
struct vrend_strarray *shader,
int vertices_per_patch)
{
struct dump_ctx ctx;
memset(&ctx, 0, sizeof(struct dump_ctx));
ctx.prog_type = TGSI_PROCESSOR_TESS_CTRL;
ctx.cfg = cfg;
ctx.key = key;
ctx.iter.iterate_declaration = iter_vs_declaration;
ctx.ssbo_array_base = 0xffffffff;
ctx.ssbo_atomic_array_base = 0xffffffff;
ctx.has_sample_input = false;
if (!allocate_strbuffers(&ctx))
goto fail;
tgsi_iterate_shader(vs_tokens, &ctx.iter);
/* What is the default on GL? */
ctx.tcs_vertices_out = vertices_per_patch;
ctx.num_outputs = ctx.num_inputs;
handle_io_arrays(&ctx);
emit_header(&ctx);
emit_ios(&ctx);
emit_buf(&ctx, "void main() {\n");
for (unsigned int i = 0; i < ctx.num_inputs; ++i) {
const char *out_prefix = "";
const char *in_prefix = "";
const char *postfix = "";
if (ctx.inputs[i].glsl_gl_block) {
out_prefix = "gl_out[gl_InvocationID].";
in_prefix = "gl_in[gl_InvocationID].";
} else {
postfix = "[gl_InvocationID]";
}
if (ctx.inputs[i].first == ctx.inputs[i].last) {
emit_buff(&ctx, "%s%s%s = %s%s%s;\n",
out_prefix, ctx.outputs[i].glsl_name, postfix,
in_prefix, ctx.inputs[i].glsl_name, postfix);
} else {
unsigned size = ctx.inputs[i].last == ctx.inputs[i].first + 1;
for (unsigned int k = 0; k < size; ++k) {
emit_buff(&ctx, "%s%s%s[%d] = %s%s%s[%d];\n",
out_prefix, ctx.outputs[i].glsl_name, postfix, k,
in_prefix, ctx.inputs[i].glsl_name, postfix, k);
}
}
}
for (int i = 0; i < 4; ++i)
emit_buff(&ctx, "gl_TessLevelOuter[%d] = %f;\n", i, tess_factors[i]);
for (int i = 0; i < 2; ++i)
emit_buff(&ctx, "gl_TessLevelInner[%d] = %f;\n", i, tess_factors[i + 4]);
emit_buf(&ctx, "}\n");
fill_sinfo(&ctx, sinfo);
set_strbuffers(rctx, &ctx, shader);
return true;
fail:
strbuf_free(&ctx.glsl_main);
strbuf_free(&ctx.glsl_hdr);
strbuf_free(&ctx.glsl_ver_ext);
free(ctx.so_names);
free(ctx.temp_ranges);
return false;
}

@ -157,4 +157,13 @@ const char *vrend_shader_samplertypeconv(bool use_gles, int sampler_type, int *i
char vrend_shader_samplerreturnconv(enum tgsi_return_type type);
int shader_lookup_sampler_array(struct vrend_shader_info *sinfo, int index);
bool vrend_shader_create_passthrough_tcs(struct vrend_context *ctx,
struct vrend_shader_cfg *cfg,
struct tgsi_token *vs_info,
struct vrend_shader_key *key,
const float tess_factors[6],
struct vrend_shader_info *sinfo,
struct vrend_strarray *shader,
int vertices_per_patch);
#endif

Loading…
Cancel
Save