lima: avoid situations when scissor minx > maxx or miny > maxy
authorVasily Khoruzhick <anarsoul@gmail.com>
Fri, 3 Apr 2020 09:17:06 +0000 (02:17 -0700)
committerMarge Bot <eric+marge@anholt.net>
Sun, 5 Apr 2020 18:52:11 +0000 (18:52 +0000)
Clip scissor to viewport and then to framebuffer to avoid that since
hardware can't handle this case.

Reviewed-by: Qiang Yu <yuq825@gmail.com>
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4427>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4427>

src/gallium/drivers/lima/lima_context.h
src/gallium/drivers/lima/lima_draw.c

index 5cda47287c29b043ac78f578239923124de13752..f74554e812c4dc1ce7e80c93ef5a761d739d6ddd 100644 (file)
@@ -191,6 +191,7 @@ struct lima_context {
    struct lima_context_framebuffer framebuffer;
    struct lima_context_viewport_state viewport;
    struct pipe_scissor_state scissor;
+   struct pipe_scissor_state clipped_scissor;
    struct lima_vs_shader_state *vs;
    struct lima_fs_shader_state *fs;
    struct lima_vertex_element_state *vertex_elements;
index 9b6d972eb1ddd314c5f95787ccc71b4089b6a4bd..294210709f7bc12358d5520e7d96b2c202ea3faf 100644 (file)
 
 #include <drm-uapi/lima_drm.h>
 
+static void
+lima_clip_scissor_to_viewport(struct lima_context *ctx)
+{
+   struct lima_context_framebuffer *fb = &ctx->framebuffer;
+   struct pipe_scissor_state *cscissor = &ctx->clipped_scissor;
+   int viewport_left, viewport_right, viewport_bottom, viewport_top;
+
+   if (ctx->rasterizer && ctx->rasterizer->base.scissor) {
+      struct pipe_scissor_state *scissor = &ctx->scissor;
+      cscissor->minx = scissor->minx;
+      cscissor->maxx = scissor->maxx;
+      cscissor->miny = scissor->miny;
+      cscissor->maxy = scissor->maxy;
+   } else {
+      cscissor->minx = 0;
+      cscissor->maxx = fb->base.width;
+      cscissor->miny = 0;
+      cscissor->maxy = fb->base.height;
+   }
+
+   viewport_left = MAX2(ctx->viewport.left, 0);
+   cscissor->minx = MAX2(cscissor->minx, viewport_left);
+   viewport_right = MIN2(ctx->viewport.right, fb->base.width);
+   cscissor->maxx = MIN2(cscissor->maxx, viewport_right);
+   if (cscissor->minx > cscissor->maxx)
+      cscissor->minx = cscissor->maxx;
+
+   viewport_bottom = MAX2(ctx->viewport.bottom, 0);
+   cscissor->miny = MAX2(cscissor->miny, viewport_bottom);
+   viewport_top = MIN2(ctx->viewport.top, fb->base.height);
+   cscissor->maxy = MIN2(cscissor->maxy, viewport_top);
+   if (cscissor->miny > cscissor->maxy)
+      cscissor->miny = cscissor->maxy;
+}
+
 static bool
 lima_is_scissor_zero(struct lima_context *ctx)
 {
-   if (!ctx->rasterizer || !ctx->rasterizer->base.scissor)
-      return false;
+   struct pipe_scissor_state *cscissor = &ctx->clipped_scissor;
 
-   struct pipe_scissor_state *scissor = &ctx->scissor;
-   return
-      scissor->minx == scissor->maxx
-      && scissor->miny == scissor->maxy;
+   return cscissor->minx == cscissor->maxx || cscissor->miny == cscissor->maxy;
 }
 
 static void
@@ -268,14 +299,8 @@ lima_pack_vs_cmd(struct lima_context *ctx, const struct pipe_draw_info *info)
 static void
 lima_pack_plbu_cmd(struct lima_context *ctx, const struct pipe_draw_info *info)
 {
-   struct lima_context_framebuffer *fb = &ctx->framebuffer;
    struct lima_vs_shader_state *vs = ctx->vs;
-   unsigned minx, maxx, miny, maxy;
-
-   /* If it's zero scissor, we skip adding all other commands */
-   if (lima_is_scissor_zero(ctx))
-      return;
-
+   struct pipe_scissor_state *cscissor = &ctx->clipped_scissor;
    struct lima_job *job = lima_job_get(ctx);
    PLBU_CMD_BEGIN(&job->plbu_cmd_array, 32);
 
@@ -317,26 +342,12 @@ lima_pack_plbu_cmd(struct lima_context *ctx, const struct pipe_draw_info *info)
     * - we should set it only for the first draw that enabled the scissor and for
     *   latter draw only if scissor is dirty
     */
-   if (ctx->rasterizer->base.scissor) {
-      struct pipe_scissor_state *scissor = &ctx->scissor;
-      minx = scissor->minx;
-      maxx = scissor->maxx;
-      miny = scissor->miny;
-      maxy = scissor->maxy;
-   } else {
-      minx = 0;
-      maxx = fb->base.width;
-      miny = 0;
-      maxy = fb->base.height;
-   }
 
-   minx = MAX2(minx, ctx->viewport.left);
-   maxx = MIN2(maxx, ctx->viewport.right);
-   miny = MAX2(miny, ctx->viewport.bottom);
-   maxy = MIN2(maxy, ctx->viewport.top);
+   assert(cscissor->minx < cscissor->maxx && cscissor->miny < cscissor->maxy);
+   PLBU_CMD_SCISSORS(cscissor->minx, cscissor->maxx, cscissor->miny, cscissor->maxy);
 
-   PLBU_CMD_SCISSORS(minx, maxx, miny, maxy);
-   lima_damage_rect_union(&job->damage_rect, minx, maxx, miny, maxy);
+   lima_damage_rect_union(&job->damage_rect, cscissor->minx, cscissor->maxx,
+                          cscissor->miny, cscissor->maxy);
 
    PLBU_CMD_UNKNOWN1();
 
@@ -1001,9 +1012,7 @@ lima_draw_vbo_update(struct pipe_context *pctx,
 
    lima_update_varying(ctx, info);
 
-   /* If it's zero scissor, don't build vs cmd list */
-   if (!lima_is_scissor_zero(ctx))
-      lima_pack_vs_cmd(ctx, info);
+   lima_pack_vs_cmd(ctx, info);
 
    if (ctx->dirty & LIMA_CONTEXT_DIRTY_CONST_BUFF &&
        ctx->const_buffer[PIPE_SHADER_FRAGMENT].dirty) {
@@ -1111,6 +1120,10 @@ lima_draw_vbo(struct pipe_context *pctx,
       return;
    }
 
+   lima_clip_scissor_to_viewport(ctx);
+   if (lima_is_scissor_zero(ctx))
+      return;
+
    if (!lima_update_vs_state(ctx) || !lima_update_fs_state(ctx))
       return;