summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2015-10-22 14:30:02 +1000
committerDave Airlie <airlied@redhat.com>2015-10-22 14:30:02 +1000
commit5201290a72e5492f786d377998f9fac8c4d432c2 (patch)
treeb978d12034c94613586afdfbc7bdcfafd4106500
parent700079c401234e1b556548d2205d807a072c22cd (diff)
virgl: overhaul shader handlingvirgl-mesa-submit-large-shaders
We failed to handle shaders that were longer than 64k, gputest pixmark_volplosion used one of these, so go back and add proper support for this, and break ABI to do so. This allows shaders to be sent in chunks to the host, and the host reassembles the chunks.
-rw-r--r--src/gallium/drivers/virgl/virgl_context.c18
-rw-r--r--src/gallium/drivers/virgl/virgl_encode.c116
-rw-r--r--src/gallium/drivers/virgl/virgl_protocol.h22
3 files changed, 112 insertions, 44 deletions
diff --git a/src/gallium/drivers/virgl/virgl_context.c b/src/gallium/drivers/virgl/virgl_context.c
index 57e16d1888e..d30ab18859e 100644
--- a/src/gallium/drivers/virgl/virgl_context.c
+++ b/src/gallium/drivers/virgl/virgl_context.c
@@ -487,7 +487,7 @@ static void *virgl_create_vs_state(struct pipe_context *ctx,
/* encode VS state */
ret = virgl_encode_shader_state(vctx, handle,
- VIRGL_OBJECT_VS, shader);
+ PIPE_SHADER_VERTEX, shader);
if (ret) {
return NULL;
}
@@ -506,7 +506,7 @@ static void *virgl_create_gs_state(struct pipe_context *ctx,
/* encode GS state */
ret = virgl_encode_shader_state(vctx, handle,
- VIRGL_OBJECT_GS, shader);
+ PIPE_SHADER_GEOMETRY, shader);
if (ret) {
return NULL;
}
@@ -524,7 +524,7 @@ static void *virgl_create_fs_state(struct pipe_context *ctx,
/* encode FS state */
ret = virgl_encode_shader_state(vctx, handle,
- VIRGL_OBJECT_FS, shader);
+ PIPE_SHADER_FRAGMENT, shader);
if (ret)
return NULL;
@@ -538,7 +538,7 @@ virgl_delete_fs_state(struct pipe_context *ctx,
uint32_t handle = (unsigned long)fs;
struct virgl_context *vctx = (struct virgl_context *)ctx;
- virgl_encode_delete_object(vctx, handle, VIRGL_OBJECT_FS);
+ virgl_encode_delete_object(vctx, handle, VIRGL_OBJECT_SHADER);
}
static void
@@ -548,7 +548,7 @@ virgl_delete_gs_state(struct pipe_context *ctx,
uint32_t handle = (unsigned long)gs;
struct virgl_context *vctx = (struct virgl_context *)ctx;
- virgl_encode_delete_object(vctx, handle, VIRGL_OBJECT_GS);
+ virgl_encode_delete_object(vctx, handle, VIRGL_OBJECT_SHADER);
}
static void
@@ -558,7 +558,7 @@ virgl_delete_vs_state(struct pipe_context *ctx,
uint32_t handle = (unsigned long)vs;
struct virgl_context *vctx = (struct virgl_context *)ctx;
- virgl_encode_delete_object(vctx, handle, VIRGL_OBJECT_VS);
+ virgl_encode_delete_object(vctx, handle, VIRGL_OBJECT_SHADER);
}
static void virgl_bind_vs_state(struct pipe_context *ctx,
@@ -567,7 +567,7 @@ static void virgl_bind_vs_state(struct pipe_context *ctx,
uint32_t handle = (unsigned long)vss;
struct virgl_context *vctx = (struct virgl_context *)ctx;
- virgl_encode_bind_object(vctx, handle, VIRGL_OBJECT_VS);
+ virgl_encode_bind_object(vctx, handle, VIRGL_OBJECT_SHADER);
}
static void virgl_bind_gs_state(struct pipe_context *ctx,
@@ -576,7 +576,7 @@ static void virgl_bind_gs_state(struct pipe_context *ctx,
uint32_t handle = (unsigned long)vss;
struct virgl_context *vctx = (struct virgl_context *)ctx;
- virgl_encode_bind_object(vctx, handle, VIRGL_OBJECT_GS);
+ virgl_encode_bind_object(vctx, handle, VIRGL_OBJECT_SHADER);
}
@@ -586,7 +586,7 @@ static void virgl_bind_fs_state(struct pipe_context *ctx,
uint32_t handle = (unsigned long)vss;
struct virgl_context *vctx = (struct virgl_context *)ctx;
- virgl_encode_bind_object(vctx, handle, VIRGL_OBJECT_FS);
+ virgl_encode_bind_object(vctx, handle, VIRGL_OBJECT_SHADER);
}
static void virgl_clear(struct pipe_context *ctx,
diff --git a/src/gallium/drivers/virgl/virgl_encode.c b/src/gallium/drivers/virgl/virgl_encode.c
index 1064821bcd8..99c7dc33de4 100644
--- a/src/gallium/drivers/virgl/virgl_encode.c
+++ b/src/gallium/drivers/virgl/virgl_encode.c
@@ -189,52 +189,114 @@ int virgl_encode_rasterizer_state(struct virgl_context *ctx,
return 0;
}
+static void virgl_emit_shader_header(struct virgl_context *ctx,
+ uint32_t handle, uint32_t len,
+ uint32_t type, uint32_t offlen,
+ uint32_t num_tokens)
+{
+ virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_CREATE_OBJECT, VIRGL_OBJECT_SHADER, len));
+ virgl_encoder_write_dword(ctx->cbuf, handle);
+ virgl_encoder_write_dword(ctx->cbuf, type);
+ virgl_encoder_write_dword(ctx->cbuf, offlen);
+ virgl_encoder_write_dword(ctx->cbuf, num_tokens);
+}
+
+static void virgl_emit_shader_streamout(struct virgl_context *ctx,
+ const struct pipe_stream_output_info *so_info)
+{
+ int num_outputs = 0;
+ int i;
+ uint32_t tmp;
+
+ if (so_info)
+ num_outputs = so_info->num_outputs;
+
+ virgl_encoder_write_dword(ctx->cbuf, num_outputs);
+ if (num_outputs) {
+ for (i = 0; i < 4; i++)
+ virgl_encoder_write_dword(ctx->cbuf, so_info->stride[i]);
+
+ for (i = 0; i < so_info->num_outputs; i++) {
+ tmp =
+ VIRGL_OBJ_SHADER_SO_OUTPUT_REGISTER_INDEX(so_info->output[i].register_index) |
+ VIRGL_OBJ_SHADER_SO_OUTPUT_START_COMPONENT(so_info->output[i].start_component) |
+ VIRGL_OBJ_SHADER_SO_OUTPUT_NUM_COMPONENTS(so_info->output[i].num_components) |
+ VIRGL_OBJ_SHADER_SO_OUTPUT_BUFFER(so_info->output[i].output_buffer) |
+ VIRGL_OBJ_SHADER_SO_OUTPUT_DST_OFFSET(so_info->output[i].dst_offset);
+ virgl_encoder_write_dword(ctx->cbuf, tmp);
+ virgl_encoder_write_dword(ctx->cbuf, 0);
+ }
+ }
+}
+
int virgl_encode_shader_state(struct virgl_context *ctx,
uint32_t handle,
uint32_t type,
const struct pipe_shader_state *shader)
{
- char *str;
+ char *str, *sptr;
uint32_t shader_len, len;
- int i;
int ret;
- uint32_t tmp;
int num_tokens = tgsi_num_tokens(shader->tokens);
int str_total_size = 65536;
-
+ int retry_size = 1;
+ uint32_t left_bytes, base_hdr_size, strm_hdr_size, thispass;
+ bool first_pass;
str = CALLOC(1, str_total_size);
if (!str)
return -1;
- ret = tgsi_dump_str(shader->tokens, TGSI_DUMP_FLOAT_AS_HEX, str, str_total_size);
- if (ret == -1) {
- fprintf(stderr, "Failed to translate shader in available space\n");
- FREE(str);
+ do {
+ int old_size;
+ ret = tgsi_dump_str(shader->tokens, TGSI_DUMP_FLOAT_AS_HEX, str, str_total_size);
+
+ if (ret == -1) {
+ fprintf(stderr, "Failed to translate shader in available space - trying again\n");
+ old_size = str_total_size;
+ str_total_size = 65536 * ++retry_size;
+ str = REALLOC(str, old_size, str_total_size);
+ if (!str)
+ return -1;
+ }
+ } while (ret == -1 && retry_size < 10);
+
+ if (ret == -1)
return -1;
- }
shader_len = strlen(str) + 1;
- len = ((shader_len + 3) / 4) + VIRGL_OBJ_SHADER_HDR_SIZE(shader->stream_output.num_outputs);
- virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_CREATE_OBJECT, type, len));
- virgl_encoder_write_dword(ctx->cbuf, handle);
- virgl_encoder_write_dword(ctx->cbuf, num_tokens);
- virgl_encoder_write_dword(ctx->cbuf, shader->stream_output.num_outputs);
- if (shader->stream_output.num_outputs) {
- for (i = 0; i < 4; i++)
- virgl_encoder_write_dword(ctx->cbuf, shader->stream_output.stride[i]);
+ left_bytes = shader_len;
+
+ base_hdr_size = 5;
+ strm_hdr_size = shader->stream_output.num_outputs ? shader->stream_output.num_outputs * 2 + 4 : 0;
+ first_pass = true;
+ sptr = str;
+ while (left_bytes) {
+ uint32_t length, offlen;
+ int hdr_len = base_hdr_size + (first_pass ? strm_hdr_size : 0);
+ if (ctx->cbuf->cdw + hdr_len + 1 > VIRGL_MAX_CMDBUF_DWORDS)
+ ctx->base.flush(&ctx->base, NULL, 0);
- for (i = 0; i < shader->stream_output.num_outputs; i++) {
- tmp =
- VIRGL_OBJ_SHADER_SO_OUTPUT_REGISTER_INDEX(shader->stream_output.output[i].register_index) |
- VIRGL_OBJ_SHADER_SO_OUTPUT_START_COMPONENT(shader->stream_output.output[i].start_component) |
- VIRGL_OBJ_SHADER_SO_OUTPUT_NUM_COMPONENTS(shader->stream_output.output[i].num_components) |
- VIRGL_OBJ_SHADER_SO_OUTPUT_BUFFER(shader->stream_output.output[i].output_buffer) |
- VIRGL_OBJ_SHADER_SO_OUTPUT_DST_OFFSET(shader->stream_output.output[i].dst_offset);
- virgl_encoder_write_dword(ctx->cbuf, tmp);
- }
+ thispass = (VIRGL_MAX_CMDBUF_DWORDS - ctx->cbuf->cdw - hdr_len - 1) * 4;
+
+ length = MIN2(thispass, left_bytes);
+ len = ((length + 3) / 4) + hdr_len;
+
+ if (first_pass)
+ offlen = VIRGL_OBJ_SHADER_OFFSET_VAL(shader_len);
+ else
+ offlen = VIRGL_OBJ_SHADER_OFFSET_VAL((uintptr_t)sptr - (uintptr_t)str) | VIRGL_OBJ_SHADER_OFFSET_CONT;
+
+ virgl_emit_shader_header(ctx, handle, len, type, offlen, num_tokens);
+
+ virgl_emit_shader_streamout(ctx, first_pass ? &shader->stream_output : NULL);
+
+ virgl_encoder_write_block(ctx->cbuf, (uint8_t *)sptr, length);
+
+ sptr += length;
+ first_pass = false;
+ left_bytes -= length;
}
- virgl_encoder_write_block(ctx->cbuf, (uint8_t *)str, shader_len);
FREE(str);
return 0;
diff --git a/src/gallium/drivers/virgl/virgl_protocol.h b/src/gallium/drivers/virgl/virgl_protocol.h
index fad93686bd2..82435e6a6a7 100644
--- a/src/gallium/drivers/virgl/virgl_protocol.h
+++ b/src/gallium/drivers/virgl/virgl_protocol.h
@@ -38,15 +38,13 @@ enum virgl_object_type {
VIRGL_OBJECT_BLEND,
VIRGL_OBJECT_RASTERIZER,
VIRGL_OBJECT_DSA,
- VIRGL_OBJECT_VS,
- VIRGL_OBJECT_FS,
+ VIRGL_OBJECT_SHADER,
VIRGL_OBJECT_VERTEX_ELEMENTS,
VIRGL_OBJECT_SAMPLER_VIEW,
VIRGL_OBJECT_SAMPLER_STATE,
VIRGL_OBJECT_SURFACE,
VIRGL_OBJECT_QUERY,
VIRGL_OBJECT_STREAMOUT_TARGET,
- VIRGL_OBJECT_GS,
VIRGL_MAX_OBJECTS,
};
@@ -207,17 +205,25 @@ enum virgl_context_cmd {
#define VIRGL_OBJ_CLEAR_STENCIL 8
/* shader object */
-#define VIRGL_OBJ_SHADER_HDR_SIZE(nso) (3 + ((nso) ? (nso) + 4 : 0))
+#define VIRGL_OBJ_SHADER_HDR_SIZE(nso) (5 + ((nso) ? (2 * nso) + 4 : 0))
#define VIRGL_OBJ_SHADER_HANDLE 1
-#define VIRGL_OBJ_SHADER_NUM_TOKENS 2
-#define VIRGL_OBJ_SHADER_SO_NUM_OUTPUTS 3
-#define VIRGL_OBJ_SHADER_SO_STRIDE(x) (4 + (x))
-#define VIRGL_OBJ_SHADER_SO_OUTPUT0(x) (8 + (x))
+#define VIRGL_OBJ_SHADER_TYPE 2
+#define VIRGL_OBJ_SHADER_OFFSET 3
+#define VIRGL_OBJ_SHADER_OFFSET_VAL(x) (((x) & 0x7fffffff) << 0)
+/* start contains full length in VAL - also implies continuations */
+/* continuation contains offset in VAL */
+#define VIRGL_OBJ_SHADER_OFFSET_CONT (0x1 << 31)
+#define VIRGL_OBJ_SHADER_NUM_TOKENS 4
+#define VIRGL_OBJ_SHADER_SO_NUM_OUTPUTS 5
+#define VIRGL_OBJ_SHADER_SO_STRIDE(x) (6 + (x))
+#define VIRGL_OBJ_SHADER_SO_OUTPUT0(x) (10 + (x * 2))
#define VIRGL_OBJ_SHADER_SO_OUTPUT_REGISTER_INDEX(x) (((x) & 0xff) << 0)
#define VIRGL_OBJ_SHADER_SO_OUTPUT_START_COMPONENT(x) (((x) & 0x3) << 8)
#define VIRGL_OBJ_SHADER_SO_OUTPUT_NUM_COMPONENTS(x) (((x) & 0x7) << 10)
#define VIRGL_OBJ_SHADER_SO_OUTPUT_BUFFER(x) (((x) & 0x7) << 13)
#define VIRGL_OBJ_SHADER_SO_OUTPUT_DST_OFFSET(x) (((x) & 0xffff) << 16)
+#define VIRGL_OBJ_SHADER_SO_OUTPUT0_SO(x) (11 + (x * 2))
+#define VIRGL_OBJ_SHADER_SO_OUTPUT_STREAM(x) (((x) & 0x03) << 0)
/* viewport state */
#define VIRGL_SET_VIEWPORT_STATE_SIZE(num_viewports) ((6 * num_viewports) + 1)