diff --git a/src/vrend_decode.c b/src/vrend_decode.c index b3ae095..42ec832 100644 --- a/src/vrend_decode.c +++ b/src/vrend_decode.c @@ -68,7 +68,7 @@ static int vrend_decode_create_shader(struct vrend_decode_ctx *ctx, struct pipe_stream_output_info so_info; uint i; int ret; - uint32_t shader_offset; + uint32_t shader_offset, req_local_mem = 0; unsigned num_tokens, num_so_outputs, offlen; uint8_t *shd_text; uint32_t type; @@ -79,12 +79,18 @@ static int vrend_decode_create_shader(struct vrend_decode_ctx *ctx, type = get_buf_entry(ctx, VIRGL_OBJ_SHADER_TYPE); num_tokens = get_buf_entry(ctx, VIRGL_OBJ_SHADER_NUM_TOKENS); offlen = get_buf_entry(ctx, VIRGL_OBJ_SHADER_OFFSET); - num_so_outputs = get_buf_entry(ctx, VIRGL_OBJ_SHADER_SO_NUM_OUTPUTS); - if (length < VIRGL_OBJ_SHADER_HDR_SIZE(num_so_outputs)) - return EINVAL; - if (num_so_outputs > PIPE_MAX_SO_OUTPUTS) - return EINVAL; + if (type == PIPE_SHADER_COMPUTE) { + req_local_mem = get_buf_entry(ctx, VIRGL_OBJ_SHADER_SO_NUM_OUTPUTS); + num_so_outputs = 0; + } else { + num_so_outputs = get_buf_entry(ctx, VIRGL_OBJ_SHADER_SO_NUM_OUTPUTS); + if (length < VIRGL_OBJ_SHADER_HDR_SIZE(num_so_outputs)) + return EINVAL; + + if (num_so_outputs > PIPE_MAX_SO_OUTPUTS) + return EINVAL; + } shader_offset = 6; if (num_so_outputs) { @@ -109,7 +115,7 @@ static int vrend_decode_create_shader(struct vrend_decode_ctx *ctx, memset(&so_info, 0, sizeof(so_info)); shd_text = get_buf_ptr(ctx, shader_offset); - ret = vrend_create_shader(ctx->grctx, handle, &so_info, (const char *)shd_text, offlen, num_tokens, type, length - shader_offset + 1); + ret = vrend_create_shader(ctx->grctx, handle, &so_info, req_local_mem, (const char *)shd_text, offlen, num_tokens, type, length - shader_offset + 1); return ret; } diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index 576cecb..63862d5 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -291,6 +291,7 @@ struct vrend_shader_selector { struct vrend_shader *current; struct tgsi_token *tokens; + uint32_t req_local_mem; char *tmp_buf; uint32_t buf_len; uint32_t buf_offset; @@ -439,6 +440,7 @@ struct vrend_sub_context { bool vbo_dirty; bool shader_dirty; + bool cs_shader_dirty; bool sampler_state_dirty; bool stencil_state_dirty; bool image_state_dirty; @@ -605,6 +607,7 @@ static inline const char *pipe_shader_to_prefix(int shader_type) case PIPE_SHADER_GEOMETRY: return "gs"; case PIPE_SHADER_TESS_CTRL: return "tc"; case PIPE_SHADER_TESS_EVAL: return "te"; + case PIPE_SHADER_COMPUTE: return "cs"; default: return NULL; }; @@ -1173,6 +1176,43 @@ static void bind_image_locs(struct vrend_linked_shader_program *sprog, sprog->images_used_mask[id] = mask; } +static struct vrend_linked_shader_program *add_cs_shader_program(struct vrend_context *ctx, + struct vrend_shader *cs) +{ + struct vrend_linked_shader_program *sprog = CALLOC_STRUCT(vrend_linked_shader_program); + GLuint prog_id; + GLint lret; + prog_id = glCreateProgram(); + glAttachShader(prog_id, cs->id); + glLinkProgram(prog_id); + + glGetProgramiv(prog_id, GL_LINK_STATUS, &lret); + if (lret == GL_FALSE) { + char infolog[65536]; + int len; + glGetProgramInfoLog(prog_id, 65536, &len, infolog); + fprintf(stderr,"got error linking\n%s\n", infolog); + /* dump shaders */ + report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0); + fprintf(stderr,"compute shader: %d GLSL\n%s\n", cs->id, cs->glsl_prog); + glDeleteProgram(prog_id); + free(sprog); + return NULL; + } + sprog->ss[PIPE_SHADER_COMPUTE] = cs; + + list_add(&sprog->sl[PIPE_SHADER_COMPUTE], &cs->programs); + sprog->id = prog_id; + list_addtail(&sprog->head, &ctx->sub->programs); + + bind_sampler_locs(sprog, PIPE_SHADER_COMPUTE); + bind_ubo_locs(sprog, PIPE_SHADER_COMPUTE); + bind_ssbo_locs(sprog, PIPE_SHADER_COMPUTE); + bind_const_locs(sprog, PIPE_SHADER_COMPUTE); + bind_image_locs(sprog, PIPE_SHADER_COMPUTE); + return sprog; +} + static struct vrend_linked_shader_program *add_shader_program(struct vrend_context *ctx, struct vrend_shader *vs, struct vrend_shader *fs, @@ -1344,6 +1384,19 @@ static struct vrend_linked_shader_program *add_shader_program(struct vrend_conte return sprog; } +static struct vrend_linked_shader_program *lookup_cs_shader_program(struct vrend_context *ctx, + GLuint cs_id) +{ + struct vrend_linked_shader_program *ent; + LIST_FOR_EACH_ENTRY(ent, &ctx->sub->programs, head) { + if (!ent->ss[PIPE_SHADER_COMPUTE]) + continue; + if (ent->ss[PIPE_SHADER_COMPUTE]->id == cs_id) + return ent; + } + return NULL; +} + static struct vrend_linked_shader_program *lookup_shader_program(struct vrend_context *ctx, GLuint vs_id, GLuint fs_id, @@ -1356,7 +1409,8 @@ static struct vrend_linked_shader_program *lookup_shader_program(struct vrend_co LIST_FOR_EACH_ENTRY(ent, &ctx->sub->programs, head) { if (ent->dual_src_linked != dual_src) continue; - + if (ent->ss[PIPE_SHADER_COMPUTE]) + continue; if (ent->ss[PIPE_SHADER_VERTEX]->id != vs_id) continue; if (ent->ss[PIPE_SHADER_FRAGMENT]->id != fs_id) @@ -1381,7 +1435,7 @@ static void vrend_destroy_program(struct vrend_linked_shader_program *ent) glDeleteProgram(ent->id); list_del(&ent->head); - for (i = PIPE_SHADER_VERTEX; i <= PIPE_SHADER_TESS_EVAL; i++) { + for (i = PIPE_SHADER_VERTEX; i <= PIPE_SHADER_COMPUTE; i++) { if (ent->ss[i]) list_del(&ent->sl[i]); free(ent->shadow_samp_mask_locs[i]); @@ -2701,6 +2755,7 @@ static inline int conv_shader_type(int type) 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; }; @@ -2718,7 +2773,7 @@ static int vrend_shader_create(struct vrend_context *ctx, shader->id = glCreateShader(conv_shader_type(shader->sel->type)); shader->compiled_fs_id = 0; - shader->glsl_prog = vrend_convert_shader(&ctx->shader_cfg, shader->sel->tokens, 0, &key, &shader->sel->sinfo); + shader->glsl_prog = vrend_convert_shader(&ctx->shader_cfg, shader->sel->tokens, shader->sel->req_local_mem, &key, &shader->sel->sinfo); if (!shader->glsl_prog) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0); glDeleteShader(shader->id); @@ -2787,6 +2842,7 @@ static int vrend_shader_select(struct vrend_context *ctx, static void *vrend_create_shader_state(UNUSED struct vrend_context *ctx, const struct pipe_stream_output_info *so_info, + uint32_t req_local_mem, unsigned pipe_shader_type) { struct vrend_shader_selector *sel = CALLOC_STRUCT(vrend_shader_selector); @@ -2794,6 +2850,7 @@ static void *vrend_create_shader_state(UNUSED struct vrend_context *ctx, if (!sel) return NULL; + sel->req_local_mem = req_local_mem; sel->type = pipe_shader_type; sel->sinfo.so_info = *so_info; pipe_reference_init(&sel->reference, 1); @@ -2819,6 +2876,7 @@ static int vrend_finish_shader(struct vrend_context *ctx, int vrend_create_shader(struct vrend_context *ctx, uint32_t handle, const struct pipe_stream_output_info *so_info, + uint32_t req_local_mem, const char *shd_text, uint32_t offlen, uint32_t num_tokens, uint32_t type, uint32_t pkt_length) { @@ -2828,7 +2886,7 @@ int vrend_create_shader(struct vrend_context *ctx, bool finished = false; int ret; - if (type > PIPE_SHADER_TESS_EVAL) + if (type > PIPE_SHADER_COMPUTE) return EINVAL; if (!has_feature(feat_geometry_shader) && @@ -2855,7 +2913,7 @@ int vrend_create_shader(struct vrend_context *ctx, } if (new_shader) { - sel = vrend_create_shader_state(ctx, so_info, type); + sel = vrend_create_shader_state(ctx, so_info, req_local_mem, type); if (sel == NULL) return ENOMEM; @@ -2964,11 +3022,14 @@ void vrend_bind_shader(struct vrend_context *ctx, { struct vrend_shader_selector *sel; - if (type > PIPE_SHADER_TESS_EVAL) + if (type > PIPE_SHADER_COMPUTE) return; if (handle == 0) { - ctx->sub->shader_dirty = true; + if (type == PIPE_SHADER_COMPUTE) + ctx->sub->cs_shader_dirty = true; + else + ctx->sub->shader_dirty = true; vrend_shader_state_reference(&ctx->sub->shaders[type], NULL); return; } @@ -2981,7 +3042,10 @@ void vrend_bind_shader(struct vrend_context *ctx, return; if (ctx->sub->shaders[sel->type] != sel) { - ctx->sub->shader_dirty = true; + if (type == PIPE_SHADER_COMPUTE) + ctx->sub->cs_shader_dirty = true; + else + ctx->sub->shader_dirty = true; ctx->sub->prog_ids[sel->type] = 0; } @@ -5057,6 +5121,7 @@ static void vrend_destroy_sub_context(struct vrend_sub_context *sub) vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_GEOMETRY], NULL); vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_TESS_CTRL], NULL); vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_TESS_EVAL], NULL); + vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_COMPUTE], NULL); vrend_free_programs(sub); for (i = 0; i < PIPE_SHADER_TYPES; i++) { @@ -5110,6 +5175,7 @@ bool vrend_destroy_context(struct vrend_context *ctx) vrend_set_num_sampler_views(ctx, PIPE_SHADER_GEOMETRY, 0, 0); vrend_set_num_sampler_views(ctx, PIPE_SHADER_TESS_CTRL, 0, 0); vrend_set_num_sampler_views(ctx, PIPE_SHADER_TESS_EVAL, 0, 0); + vrend_set_num_sampler_views(ctx, PIPE_SHADER_COMPUTE, 0, 0); vrend_set_streamout_targets(ctx, 0, 0, NULL); vrend_set_num_vbo(ctx, 0); diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h index fe05fcc..a0766dd 100644 --- a/src/vrend_renderer.h +++ b/src/vrend_renderer.h @@ -112,6 +112,7 @@ const struct vrend_format_table *vrend_get_format_table_entry(enum virgl_formats int vrend_create_shader(struct vrend_context *ctx, uint32_t handle, const struct pipe_stream_output_info *stream_output, + uint32_t req_local_mem, const char *shd_text, uint32_t offlen, uint32_t num_tokens, uint32_t type, uint32_t pkt_length);