From ba30df1bdce1654d736154c90e64e6c5f4047e4a Mon Sep 17 00:00:00 2001 From: Antonio Caggiano Date: Mon, 25 Oct 2021 17:38:38 +0200 Subject: [PATCH] shader: Link shader command Add a new command associated to glLinkProgram. With this we should be able to compile and link shaders when requested by the user. Together with the command we expect an array of shader handles attached to the program, where each position of the array corresponds to a pipe shader type. Signed-off-by: Antonio Caggiano Reviewed-by: Gert Wollny --- src/virgl_protocol.h | 10 ++++++++++ src/vrend_debug.c | 1 + src/vrend_decode.c | 18 ++++++++++++++++++ src/vrend_renderer.c | 31 ++++++++++++++++++++++++++++++- src/vrend_renderer.h | 2 ++ tests/test_virgl_cmd.c | 9 +++++++++ tests/testvirgl_encode.c | 12 ++++++++++++ tests/testvirgl_encode.h | 1 + 8 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/virgl_protocol.h b/src/virgl_protocol.h index c1797d9..dc1bafa 100644 --- a/src/virgl_protocol.h +++ b/src/virgl_protocol.h @@ -116,6 +116,7 @@ enum virgl_context_cmd { VIRGL_CCMD_PIPE_RESOURCE_SET_TYPE, VIRGL_CCMD_GET_MEMORY_INFO, VIRGL_CCMD_SEND_STRING_MARKER, + VIRGL_CCMD_LINK_SHADER, VIRGL_MAX_COMMANDS }; @@ -673,4 +674,13 @@ enum vrend_tweak_type { #define VIRGL_SEND_STRING_MARKER_STRING_SIZE 1 #define VIRGL_SEND_STRING_MARKER_OFFSET 2 +/* link shader program */ +#define VIRGL_LINK_SHADER_SIZE 6 +#define VIRGL_LINK_SHADER_VERTEX_HANDLE 1 +#define VIRGL_LINK_SHADER_FRAGMENT_HANDLE 2 +#define VIRGL_LINK_SHADER_GEOMETRY_HANDLE 3 +#define VIRGL_LINK_SHADER_TESS_CTRL_HANDLE 4 +#define VIRGL_LINK_SHADER_TESS_EVAL_HANDLE 5 +#define VIRGL_LINK_SHADER_COMPUTE_HANDLE 6 + #endif diff --git a/src/vrend_debug.c b/src/vrend_debug.c index a0ab7bc..8c1cd93 100644 --- a/src/vrend_debug.c +++ b/src/vrend_debug.c @@ -81,6 +81,7 @@ static const char *command_names[VIRGL_MAX_COMMANDS] = { "PIPE_RESOURCE_SET_TYPE", "GET_MEMORY_INFO", "SEND_STRING_MARKER", + "LINK_SHADER", }; static const char *object_type_names[VIRGL_MAX_OBJECTS] = { diff --git a/src/vrend_decode.c b/src/vrend_decode.c index 934c8b0..a55d542 100644 --- a/src/vrend_decode.c +++ b/src/vrend_decode.c @@ -1155,6 +1155,23 @@ static int vrend_decode_destroy_sub_ctx(struct vrend_context *ctx, const uint32_ return 0; } +static int vrend_decode_link_shader(struct vrend_context *ctx, const uint32_t *buf, uint32_t length) +{ + if (length != VIRGL_LINK_SHADER_SIZE) + return EINVAL; + + uint32_t handles[PIPE_SHADER_TYPES]; + handles[PIPE_SHADER_VERTEX] = get_buf_entry(buf, VIRGL_LINK_SHADER_VERTEX_HANDLE); + handles[PIPE_SHADER_FRAGMENT] = get_buf_entry(buf, VIRGL_LINK_SHADER_FRAGMENT_HANDLE); + handles[PIPE_SHADER_GEOMETRY] = get_buf_entry(buf, VIRGL_LINK_SHADER_GEOMETRY_HANDLE); + handles[PIPE_SHADER_TESS_CTRL] = get_buf_entry(buf, VIRGL_LINK_SHADER_TESS_CTRL_HANDLE); + handles[PIPE_SHADER_TESS_EVAL] = get_buf_entry(buf, VIRGL_LINK_SHADER_TESS_EVAL_HANDLE); + handles[PIPE_SHADER_COMPUTE] = get_buf_entry(buf, VIRGL_LINK_SHADER_COMPUTE_HANDLE); + + vrend_link_program(ctx, handles); + return 0; +} + static int vrend_decode_bind_shader(struct vrend_context *ctx, const uint32_t *buf, uint32_t length) { uint32_t handle, type; @@ -1654,6 +1671,7 @@ static const vrend_decode_callback decode_table[VIRGL_MAX_COMMANDS] = { [VIRGL_CCMD_PIPE_RESOURCE_SET_TYPE] = vrend_decode_pipe_resource_set_type, [VIRGL_CCMD_GET_MEMORY_INFO] = vrend_decode_get_memory_info, [VIRGL_CCMD_SEND_STRING_MARKER] = vrend_decode_send_string_marker, + [VIRGL_CCMD_LINK_SHADER] = vrend_decode_link_shader, }; static int vrend_decode_ctx_submit_cmd(struct virgl_context *ctx, diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index a5a66b9..355a76f 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -4798,6 +4798,35 @@ vrend_select_program(struct vrend_sub_context *sub_ctx, ubyte vertices_per_patch return new_program; } +void vrend_link_program(struct vrend_context *ctx, uint32_t *handles) +{ + /* Pre-compiling compute shaders needs some additional work */ + if (handles[PIPE_SHADER_COMPUTE]) + return; + + struct vrend_shader_selector *prev_handles[PIPE_SHADER_TYPES]; + memset(prev_handles, 0, sizeof(prev_handles)); + uint32_t prev_shader_ids[PIPE_SHADER_TYPES]; + memcpy(prev_shader_ids, ctx->sub->prog_ids, PIPE_SHADER_TYPES * sizeof(uint32_t)); + struct vrend_linked_shader_program *prev_prog = ctx->sub->prog; + + for (uint32_t type = 0; type < PIPE_SHADER_TYPES; ++type) { + vrend_shader_state_reference(&prev_handles[type], ctx->sub->shaders[type]); + vrend_bind_shader(ctx, handles[type], type); + } + + ctx->sub->shader_dirty = true; + ctx->sub->cs_shader_dirty = true; + + /* undo state changes */ + for (uint32_t type = 0; type < PIPE_SHADER_TYPES; ++type) { + vrend_shader_state_reference(&ctx->sub->shaders[type], prev_handles[type]); + vrend_shader_state_reference(&prev_handles[type], NULL); + } + memcpy(ctx->sub->prog_ids, prev_shader_ids, PIPE_SHADER_TYPES * sizeof(uint32_t)); + ctx->sub->prog = prev_prog; +} + int vrend_draw_vbo(struct vrend_context *ctx, const struct pipe_draw_info *info, uint32_t cso, uint32_t indirect_handle, @@ -10536,7 +10565,7 @@ static void vrend_renderer_fill_caps_v2(int gl_ver, int gles_ver, union virgl_c * this value to avoid regressions when a guest with a new mesa version is * run on an old virgl host. Use it also to indicate non-cap fixes on the * host that help enable features in the guest. */ - caps->v2.host_feature_check_version = 6; + caps->v2.host_feature_check_version = 7; /* Forward host GL_RENDERER to the guest. */ strncpy(caps->v2.renderer, renderer, sizeof(caps->v2.renderer) - 1); diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h index 69f17d8..e6f84cc 100644 --- a/src/vrend_renderer.h +++ b/src/vrend_renderer.h @@ -145,6 +145,8 @@ int vrend_create_shader(struct vrend_context *ctx, const char *shd_text, uint32_t offlen, uint32_t num_tokens, uint32_t type, uint32_t pkt_length); +void vrend_link_program(struct vrend_context *ctx, uint32_t *handles); + void vrend_bind_shader(struct vrend_context *ctx, uint32_t type, uint32_t handle); diff --git a/tests/test_virgl_cmd.c b/tests/test_virgl_cmd.c index 3c2fd24..4c8d689 100644 --- a/tests/test_virgl_cmd.c +++ b/tests/test_virgl_cmd.c @@ -372,6 +372,15 @@ START_TEST(virgl_test_render_simple) virgl_encode_bind_shader(&ctx, fs_handle, PIPE_SHADER_FRAGMENT); } + /* link shader */ + { + uint32_t handles[PIPE_SHADER_TYPES]; + memset(handles, 0, sizeof(handles)); + handles[PIPE_SHADER_VERTEX] = vs_handle; + handles[PIPE_SHADER_FRAGMENT] = fs_handle; + virgl_encode_link_shader(&ctx, handles); + } + /* set blend state */ { struct pipe_blend_state blend; diff --git a/tests/testvirgl_encode.c b/tests/testvirgl_encode.c index f44a640..38ad5e1 100644 --- a/tests/testvirgl_encode.c +++ b/tests/testvirgl_encode.c @@ -942,6 +942,18 @@ int virgl_encoder_destroy_sub_ctx(struct virgl_context *ctx, uint32_t sub_ctx_id return 0; } +int virgl_encode_link_shader(struct virgl_context *ctx, uint32_t *handles) +{ + virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_LINK_SHADER, 0, VIRGL_LINK_SHADER_SIZE)); + virgl_encoder_write_dword(ctx->cbuf, handles[PIPE_SHADER_VERTEX]); + virgl_encoder_write_dword(ctx->cbuf, handles[PIPE_SHADER_FRAGMENT]); + virgl_encoder_write_dword(ctx->cbuf, handles[PIPE_SHADER_GEOMETRY]); + virgl_encoder_write_dword(ctx->cbuf, handles[PIPE_SHADER_TESS_CTRL]); + virgl_encoder_write_dword(ctx->cbuf, handles[PIPE_SHADER_TESS_EVAL]); + virgl_encoder_write_dword(ctx->cbuf, handles[PIPE_SHADER_COMPUTE]); + return 0; +} + int virgl_encode_bind_shader(struct virgl_context *ctx, uint32_t handle, uint32_t type) { diff --git a/tests/testvirgl_encode.h b/tests/testvirgl_encode.h index c5bd9c1..cd1ab2b 100644 --- a/tests/testvirgl_encode.h +++ b/tests/testvirgl_encode.h @@ -258,6 +258,7 @@ int virgl_encoder_render_condition(struct virgl_context *ctx, int virgl_encoder_set_sub_ctx(struct virgl_context *ctx, uint32_t sub_ctx_id); int virgl_encoder_create_sub_ctx(struct virgl_context *ctx, uint32_t sub_ctx_id); int virgl_encoder_destroy_sub_ctx(struct virgl_context *ctx, uint32_t sub_ctx_id); +int virgl_encode_link_shader(struct virgl_context *ctx, uint32_t *handles); int virgl_encode_bind_shader(struct virgl_context *ctx, uint32_t handle, uint32_t type); #endif