virgl: limit command length to 16 bits
[mesa.git] / src / gallium / drivers / virgl / virgl_encode.c
index c09eb5a6382d06395cff8a026ae3f254e022d1c4..fe390ea93fe797d919b1c13fce6e806875c315c6 100644 (file)
@@ -37,6 +37,8 @@
 #include "virgl_resource.h"
 #include "virgl_screen.h"
 
+#define VIRGL_ENCODE_MAX_DWORDS MIN2(VIRGL_MAX_CMDBUF_DWORDS, VIRGL_CMD0_MAX_DWORDS)
+
 static int virgl_encoder_write_cmd_dword(struct virgl_context *ctx,
                                         uint32_t dword)
 {
@@ -49,18 +51,25 @@ static int virgl_encoder_write_cmd_dword(struct virgl_context *ctx,
    return 0;
 }
 
-static void virgl_encoder_write_res(struct virgl_context *ctx,
-                                    struct virgl_resource *res)
+static void virgl_encoder_emit_resource(struct virgl_screen *vs,
+                                        struct virgl_cmd_buf *buf,
+                                        struct virgl_resource *res)
 {
-   struct virgl_winsys *vws = virgl_screen(ctx->base.screen)->vws;
-
+   struct virgl_winsys *vws = vs->vws;
    if (res && res->hw_res)
-      vws->emit_res(vws, ctx->cbuf, res->hw_res, TRUE);
+      vws->emit_res(vws, buf, res->hw_res, TRUE);
    else {
-      virgl_encoder_write_dword(ctx->cbuf, 0);
+      virgl_encoder_write_dword(buf, 0);
    }
 }
 
+static void virgl_encoder_write_res(struct virgl_context *ctx,
+                                    struct virgl_resource *res)
+{
+   struct virgl_screen *vs = virgl_screen(ctx->base.screen);
+   virgl_encoder_emit_resource(vs, ctx->cbuf, res);
+}
+
 int virgl_encode_bind_object(struct virgl_context *ctx,
                             uint32_t handle, uint32_t object)
 {
@@ -154,7 +163,7 @@ int virgl_encode_rasterizer_state(struct virgl_context *ctx,
    virgl_encoder_write_dword(ctx->cbuf, handle);
 
    tmp = VIRGL_OBJ_RS_S0_FLATSHADE(state->flatshade) |
-      VIRGL_OBJ_RS_S0_DEPTH_CLIP(state->depth_clip) |
+      VIRGL_OBJ_RS_S0_DEPTH_CLIP(state->depth_clip_near) |
       VIRGL_OBJ_RS_S0_CLIP_HALFZ(state->clip_halfz) |
       VIRGL_OBJ_RS_S0_RASTERIZER_DISCARD(state->rasterizer_discard) |
       VIRGL_OBJ_RS_S0_FLATSHADE_FIRST(state->flatshade_first) |
@@ -261,7 +270,8 @@ int virgl_encode_shader_state(struct virgl_context *ctx,
 
       bret = tgsi_dump_str(tokens, TGSI_DUMP_FLOAT_AS_HEX, str, str_total_size);
       if (bret == false) {
-         fprintf(stderr, "Failed to translate shader in available space - trying again\n");
+         if (virgl_debug & VIRGL_DEBUG_VERBOSE)
+            debug_printf("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);
@@ -273,6 +283,9 @@ int virgl_encode_shader_state(struct virgl_context *ctx,
    if (bret == false)
       return -1;
 
+   if (virgl_debug & VIRGL_DEBUG_TGSI)
+      debug_printf("TGSI:\n---8<---\n%s\n---8<---\n", str);
+
    shader_len = strlen(str) + 1;
 
    left_bytes = shader_len;
@@ -284,10 +297,10 @@ int virgl_encode_shader_state(struct virgl_context *ctx,
    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)
+      if (ctx->cbuf->cdw + hdr_len + 1 >= VIRGL_ENCODE_MAX_DWORDS)
          ctx->base.flush(&ctx->base, NULL, 0);
 
-      thispass = (VIRGL_MAX_CMDBUF_DWORDS - ctx->cbuf->cdw - hdr_len - 1) * 4;
+      thispass = (VIRGL_ENCODE_MAX_DWORDS - ctx->cbuf->cdw - hdr_len - 1) * 4;
 
       length = MIN2(thispass, left_bytes);
       len = ((length + 3) / 4) + hdr_len;
@@ -498,23 +511,24 @@ int virgl_encoder_create_so_target(struct virgl_context *ctx,
    return 0;
 }
 
-static void virgl_encoder_iw_emit_header_1d(struct virgl_context *ctx,
-                                           struct virgl_resource *res,
-                                           unsigned level, unsigned usage,
-                                           const struct pipe_box *box,
-                                           unsigned stride, unsigned layer_stride)
+static void virgl_encoder_transfer3d_common(struct virgl_screen *vs,
+                                            struct virgl_cmd_buf *buf,
+                                            struct virgl_transfer *xfer)
 {
-   virgl_encoder_write_res(ctx, res);
-   virgl_encoder_write_dword(ctx->cbuf, level);
-   virgl_encoder_write_dword(ctx->cbuf, usage);
-   virgl_encoder_write_dword(ctx->cbuf, stride);
-   virgl_encoder_write_dword(ctx->cbuf, layer_stride);
-   virgl_encoder_write_dword(ctx->cbuf, box->x);
-   virgl_encoder_write_dword(ctx->cbuf, box->y);
-   virgl_encoder_write_dword(ctx->cbuf, box->z);
-   virgl_encoder_write_dword(ctx->cbuf, box->width);
-   virgl_encoder_write_dword(ctx->cbuf, box->height);
-   virgl_encoder_write_dword(ctx->cbuf, box->depth);
+   struct pipe_transfer *transfer = &xfer->base;
+   struct virgl_resource *res = virgl_resource(transfer->resource);
+
+   virgl_encoder_emit_resource(vs, buf, res);
+   virgl_encoder_write_dword(buf, transfer->level);
+   virgl_encoder_write_dword(buf, transfer->usage);
+   virgl_encoder_write_dword(buf, 0);
+   virgl_encoder_write_dword(buf, 0);
+   virgl_encoder_write_dword(buf, transfer->box.x);
+   virgl_encoder_write_dword(buf, transfer->box.y);
+   virgl_encoder_write_dword(buf, transfer->box.z);
+   virgl_encoder_write_dword(buf, transfer->box.width);
+   virgl_encoder_write_dword(buf, transfer->box.height);
+   virgl_encoder_write_dword(buf, transfer->box.depth);
 }
 
 int virgl_encoder_inline_write(struct virgl_context *ctx,
@@ -526,10 +540,16 @@ int virgl_encoder_inline_write(struct virgl_context *ctx,
 {
    uint32_t size = (stride ? stride : box->width) * box->height;
    uint32_t length, thispass, left_bytes;
-   struct pipe_box mybox = *box;
+   struct virgl_transfer transfer;
+   struct virgl_screen *vs = virgl_screen(ctx->base.screen);
+
+   transfer.base.resource = &res->u.b;
+   transfer.base.level = level;
+   transfer.base.usage = usage;
+   transfer.base.box = *box;
 
    length = 11 + (size + 3) / 4;
-   if ((ctx->cbuf->cdw + length + 1) > VIRGL_MAX_CMDBUF_DWORDS) {
+   if ((ctx->cbuf->cdw + length + 1) > VIRGL_ENCODE_MAX_DWORDS) {
       if (box->height > 1 || box->depth > 1) {
          debug_printf("inline transfer failed due to multi dimensions and too large\n");
          assert(0);
@@ -538,19 +558,19 @@ int virgl_encoder_inline_write(struct virgl_context *ctx,
 
    left_bytes = size;
    while (left_bytes) {
-      if (ctx->cbuf->cdw + 12 >= VIRGL_MAX_CMDBUF_DWORDS)
+      if (ctx->cbuf->cdw + 12 >= VIRGL_ENCODE_MAX_DWORDS)
          ctx->base.flush(&ctx->base, NULL, 0);
 
-      thispass = (VIRGL_MAX_CMDBUF_DWORDS - ctx->cbuf->cdw - 12) * 4;
+      thispass = (VIRGL_ENCODE_MAX_DWORDS - ctx->cbuf->cdw - 12) * 4;
 
       length = MIN2(thispass, left_bytes);
 
-      mybox.width = length;
+      transfer.base.box.width = length;
       virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_RESOURCE_INLINE_WRITE, 0, ((length + 3) / 4) + 11));
-      virgl_encoder_iw_emit_header_1d(ctx, res, level, usage, &mybox, stride, layer_stride);
+      virgl_encoder_transfer3d_common(vs, ctx->cbuf, &transfer);
       virgl_encoder_write_block(ctx->cbuf, data, length);
       left_bytes -= length;
-      mybox.x += length;
+      transfer.base.box.x += length;
       data += length;
    }
    return 0;
@@ -945,6 +965,31 @@ int virgl_encode_set_shader_buffers(struct virgl_context *ctx,
          virgl_encoder_write_dword(ctx->cbuf, buffers[i].buffer_offset);
          virgl_encoder_write_dword(ctx->cbuf, buffers[i].buffer_size);
          virgl_encoder_write_res(ctx, res);
+         virgl_resource_dirty(res, 0);
+      } else {
+         virgl_encoder_write_dword(ctx->cbuf, 0);
+         virgl_encoder_write_dword(ctx->cbuf, 0);
+         virgl_encoder_write_dword(ctx->cbuf, 0);
+      }
+   }
+   return 0;
+}
+
+int virgl_encode_set_hw_atomic_buffers(struct virgl_context *ctx,
+                                       unsigned start_slot, unsigned count,
+                                       const struct pipe_shader_buffer *buffers)
+{
+   int i;
+   virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_SET_ATOMIC_BUFFERS, 0, VIRGL_SET_ATOMIC_BUFFER_SIZE(count)));
+
+   virgl_encoder_write_dword(ctx->cbuf, start_slot);
+   for (i = 0; i < count; i++) {
+      if (buffers) {
+         struct virgl_resource *res = virgl_resource(buffers[i].buffer);
+         virgl_encoder_write_dword(ctx->cbuf, buffers[i].buffer_offset);
+         virgl_encoder_write_dword(ctx->cbuf, buffers[i].buffer_size);
+         virgl_encoder_write_res(ctx, res);
+         virgl_resource_dirty(res, 0);
       } else {
          virgl_encoder_write_dword(ctx->cbuf, 0);
          virgl_encoder_write_dword(ctx->cbuf, 0);
@@ -972,6 +1017,7 @@ int virgl_encode_set_shader_images(struct virgl_context *ctx,
          virgl_encoder_write_dword(ctx->cbuf, images[i].u.buf.offset);
          virgl_encoder_write_dword(ctx->cbuf, images[i].u.buf.size);
          virgl_encoder_write_res(ctx, res);
+         virgl_resource_dirty(res, images[i].u.tex.level);
       } else {
          virgl_encoder_write_dword(ctx->cbuf, 0);
          virgl_encoder_write_dword(ctx->cbuf, 0);
@@ -1017,3 +1063,43 @@ int virgl_encode_texture_barrier(struct virgl_context *ctx,
    virgl_encoder_write_dword(ctx->cbuf, flags);
    return 0;
 }
+
+int virgl_encode_host_debug_flagstring(struct virgl_context *ctx,
+                                       const char *flagstring)
+{
+   unsigned long slen = strlen(flagstring) + 1;
+   uint32_t sslen;
+   uint32_t string_length;
+
+   if (!slen)
+      return 0;
+
+   if (slen > 4 * 0xffff) {
+      debug_printf("VIRGL: host debug flag string too long, will be truncated\n");
+      slen = 4 * 0xffff;
+   }
+
+   sslen = (uint32_t )(slen + 3) / 4;
+   string_length = (uint32_t)MIN2(sslen * 4, slen);
+
+   virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_SET_DEBUG_FLAGS, 0, sslen));
+   virgl_encoder_write_block(ctx->cbuf, (const uint8_t *)flagstring, string_length);
+   return 0;
+}
+
+int virgl_encode_get_query_result_qbo(struct virgl_context *ctx,
+                                      uint32_t handle,
+                                      struct virgl_resource *res, boolean wait,
+                                      uint32_t result_type,
+                                      uint32_t offset,
+                                      uint32_t index)
+{
+   virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_GET_QUERY_RESULT_QBO, 0, VIRGL_QUERY_RESULT_QBO_SIZE));
+   virgl_encoder_write_dword(ctx->cbuf, handle);
+   virgl_encoder_write_res(ctx, res);
+   virgl_encoder_write_dword(ctx->cbuf, wait ? 1 : 0);
+   virgl_encoder_write_dword(ctx->cbuf, result_type);
+   virgl_encoder_write_dword(ctx->cbuf, offset);
+   virgl_encoder_write_dword(ctx->cbuf, index);
+   return 0;
+}