shader: lazy host shader variant compilation

Avoids compiling shader variants in the host driver if they will never
be used for rendering.

Wait to register shaders with the host GL driver until after shader
dependencies have been resolved and the selected set of variants is
known to be used for rendering.

The cost of this workaround is taht TGSI to GLSL conversion is still
performed for every variant (observed to happen twice for every
vertex/fragment shader in some cases), but this is expected to be much
cheaper than calling out to the host driver to compile unused variants.

Workaround for #180.

Signed-off-by: Ryan Neph <ryanneph@google.com>
Reviewed-by: Gert Wollny <gert.wollny@collabora.com>
macos/master
Ryan Neph 3 years ago committed by Gert Wollny
parent 2d99aa61c6
commit 956b719d03
  1. 72
      src/vrend_renderer.c

@ -416,6 +416,7 @@ struct vrend_shader {
struct vrend_strarray glsl_strings;
GLuint id;
uint32_t uid;
bool is_compiled;
struct vrend_shader_key key;
struct list_head programs;
};
@ -1115,6 +1116,20 @@ static void vrend_destroy_shader_selector(struct vrend_shader_selector *sel)
free(sel);
}
static inline int conv_shader_type(int type)
{
switch (type) {
case PIPE_SHADER_VERTEX: return GL_VERTEX_SHADER;
case PIPE_SHADER_FRAGMENT: return GL_FRAGMENT_SHADER;
case PIPE_SHADER_GEOMETRY: return GL_GEOMETRY_SHADER;
case PIPE_SHADER_TESS_CTRL: return GL_TESS_CONTROL_SHADER;
case PIPE_SHADER_TESS_EVAL: return GL_TESS_EVALUATION_SHADER;
case PIPE_SHADER_COMPUTE: return GL_COMPUTE_SHADER;
default:
return 0;
};
}
static bool vrend_compile_shader(struct vrend_sub_context *sub_ctx,
struct vrend_shader *shader)
{
@ -1123,6 +1138,8 @@ static bool vrend_compile_shader(struct vrend_sub_context *sub_ctx,
for (int i = 0; i < shader->glsl_strings.num_strings; i++)
shader_parts[i] = shader->glsl_strings.strings[i].buf;
shader->id = glCreateShader(conv_shader_type(shader->sel->type));
glShaderSource(shader->id, shader->glsl_strings.num_strings, shader_parts, NULL);
glCompileShader(shader->id);
glGetShaderiv(shader->id, GL_COMPILE_STATUS, &param);
@ -1130,11 +1147,13 @@ static bool vrend_compile_shader(struct vrend_sub_context *sub_ctx,
char infolog[65536];
int len;
glGetShaderInfoLog(shader->id, 65536, &len, infolog);
glDeleteShader(shader->id);
vrend_report_context_error(sub_ctx->parent, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0);
vrend_printf("shader failed to compile\n%s\n", infolog);
vrend_shader_dump(shader);
return false;
}
shader->is_compiled = true;
return true;
}
@ -3415,27 +3434,12 @@ static inline void vrend_fill_shader_key(struct vrend_sub_context *sub_ctx,
}
}
static inline int conv_shader_type(int type)
{
switch (type) {
case PIPE_SHADER_VERTEX: return GL_VERTEX_SHADER;
case PIPE_SHADER_FRAGMENT: return GL_FRAGMENT_SHADER;
case PIPE_SHADER_GEOMETRY: return GL_GEOMETRY_SHADER;
case PIPE_SHADER_TESS_CTRL: return GL_TESS_CONTROL_SHADER;
case PIPE_SHADER_TESS_EVAL: return GL_TESS_EVALUATION_SHADER;
case PIPE_SHADER_COMPUTE: return GL_COMPUTE_SHADER;
default:
return 0;
};
}
static int vrend_shader_create(struct vrend_context *ctx,
struct vrend_shader *shader,
struct vrend_shader_key *key)
{
static uint32_t uid;
shader->id = glCreateShader(conv_shader_type(shader->sel->type));
shader->uid = ++uid;
if (shader->sel->tokens) {
@ -3443,26 +3447,14 @@ static int vrend_shader_create(struct vrend_context *ctx,
shader->sel->req_local_mem, key, &shader->sel->sinfo, &shader->glsl_strings);
if (!ret) {
vrend_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) {
vrend_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;
ret = vrend_compile_shader(ctx->sub, shader);
if (ret == false) {
glDeleteShader(shader->id);
strarray_free(&shader->glsl_strings, true);
return -1;
}
}
return 0;
}
@ -4473,7 +4465,6 @@ void vrend_inject_tcs(struct vrend_sub_context *sub_ctx, int vertices_per_patch)
sub_ctx->shaders[PIPE_SHADER_TESS_CTRL] = sel;
sub_ctx->shaders[PIPE_SHADER_TESS_CTRL]->num_shaders = 1;
shader->id = glCreateShader(conv_shader_type(shader->sel->type));
vrend_compile_shader(sub_ctx, shader);
}
@ -4535,6 +4526,23 @@ vrend_select_program(struct vrend_sub_context *sub_ctx, const struct pipe_draw_i
sub_ctx->drawing = false;
for (uint i = 0; i < PIPE_SHADER_TYPES; i++) {
struct vrend_shader_selector *sel = shaders[i];
if (!sel)
continue;
struct vrend_shader *shader = sel->current;
if (shader && !shader->is_compiled) {//shader->sel->type == PIPE_SHADER_FRAGMENT || shader->sel->type == PIPE_SHADER_GEOMETRY) {
bool ret;
ret = vrend_compile_shader(sub_ctx, shader);
if (ret == false) {
strarray_free(&shader->glsl_strings, true);
return -1;
}
}
}
if (!shaders[PIPE_SHADER_VERTEX]->current ||
!shaders[PIPE_SHADER_FRAGMENT]->current ||
(shaders[PIPE_SHADER_GEOMETRY] && !shaders[PIPE_SHADER_GEOMETRY]->current) ||
@ -4879,9 +4887,15 @@ void vrend_launch_grid(struct vrend_context *ctx,
vrend_shader_select(sub_ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE], &cs_dirty);
if (!sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current) {
vrend_printf( "failure to compile shader variants: %s\n", ctx->debug_name);
vrend_printf( "failure to select compute shader variant: %s\n", ctx->debug_name);
return;
}
if (!sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->is_compiled) {
if(!vrend_compile_shader(sub_ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current)) {
vrend_printf( "failure to compile compute shader variant: %s\n", ctx->debug_name);
return;
}
}
if (sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->id != (GLuint)sub_ctx->prog_ids[PIPE_SHADER_COMPUTE]) {
prog = lookup_cs_shader_program(ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->id);
if (!prog) {

Loading…
Cancel
Save