swr: implement clipPlanes/clipVertex/clipDistance/cullDistance
authorTim Rowley <timothy.o.rowley@intel.com>
Wed, 25 May 2016 23:49:34 +0000 (18:49 -0500)
committerTim Rowley <timothy.o.rowley@intel.com>
Thu, 9 Jun 2016 18:28:35 +0000 (13:28 -0500)
v2: only load the clip vertex once

v3: fix clip enable logic, add cullDistance

v4: remove duplicate fields in vs jit key, fix test of clip fixup needed

v5: fix clipdistance linkage for slot!=0,4

v6: support clip+cull; passes most piglit clip (failures understood)

Reviewed-by: Bruce Cherniak <bruce.cherniak@intel.com>
docs/GL3.txt
src/gallium/drivers/swr/swr_context.h
src/gallium/drivers/swr/swr_screen.cpp
src/gallium/drivers/swr/swr_shader.cpp
src/gallium/drivers/swr/swr_shader.h
src/gallium/drivers/swr/swr_state.cpp

index e8d401dfd93c759bf260657c66a4884a4567463e..4ba0366ed6411d74ca5e7aded9f7a11d98f54b12 100644 (file)
@@ -211,7 +211,7 @@ GL 4.5, GLSL 4.50:
   GL_ARB_ES3_1_compatibility                            DONE (nvc0, radeonsi)
   GL_ARB_clip_control                                   DONE (i965, nv50, nvc0, r600, radeonsi, llvmpipe, softpipe, swr)
   GL_ARB_conditional_render_inverted                    DONE (i965, nv50, nvc0, r600, radeonsi, llvmpipe, softpipe, swr)
-  GL_ARB_cull_distance                                  DONE (i965, nv50, nvc0, llvmpipe, softpipe)
+  GL_ARB_cull_distance                                  DONE (i965, nv50, nvc0, llvmpipe, softpipe, swr)
   GL_ARB_derivative_control                             DONE (i965, nv50, nvc0, r600, radeonsi)
   GL_ARB_direct_state_access                            DONE (all drivers)
   GL_ARB_get_texture_sub_image                          DONE (all drivers)
index a7383bbad286cb9bbe00c05617fbcd8f23a16004..75ecae334d57624ea1577d9b3ee96c8e952245a2 100644 (file)
@@ -89,6 +89,8 @@ struct swr_draw_context {
    swr_jit_texture texturesFS[PIPE_MAX_SHADER_SAMPLER_VIEWS];
    swr_jit_sampler samplersFS[PIPE_MAX_SAMPLERS];
 
+   float userClipPlanes[PIPE_MAX_CLIP_PLANES][4];
+
    SWR_SURFACE_STATE renderTargets[SWR_NUM_ATTACHMENTS];
 };
 
index ca3920240fb380ee7d32de3a4286ef585788c445..af82c93fadccc0eebebdaf15a6f0bc6da400da45 100644 (file)
@@ -333,6 +333,8 @@ swr_get_param(struct pipe_screen *screen, enum pipe_cap param)
    case PIPE_CAP_TEXTURE_FLOAT_LINEAR:
    case PIPE_CAP_TEXTURE_HALF_FLOAT_LINEAR:
       return 1;
+   case PIPE_CAP_CULL_DISTANCE:
+      return 1;
    case PIPE_CAP_TGSI_TXQS:
    case PIPE_CAP_FORCE_PERSAMPLE_INTERP:
    case PIPE_CAP_SHAREABLE_SHADERS:
@@ -358,7 +360,6 @@ swr_get_param(struct pipe_screen *screen, enum pipe_cap param)
    case PIPE_CAP_PCI_DEVICE:
    case PIPE_CAP_PCI_FUNCTION:
    case PIPE_CAP_FRAMEBUFFER_NO_ATTACHMENT:
-   case PIPE_CAP_CULL_DISTANCE:
    case PIPE_CAP_PRIMITIVE_RESTART_FOR_PATCHES:
    case PIPE_CAP_TGSI_VOTE:
       return 0;
index f26467e078e8f9e995679cafaa1b2faa06dd16f9..8af0700cb04c7555b127566d3368ba711195ea80 100644 (file)
@@ -40,6 +40,9 @@
 #include "swr_state.h"
 #include "swr_screen.h"
 
+static unsigned
+locate_linkage(ubyte name, ubyte index, struct tgsi_shader_info *info);
+
 bool operator==(const swr_jit_fs_key &lhs, const swr_jit_fs_key &rhs)
 {
    return !memcmp(&lhs, &rhs, sizeof(lhs));
@@ -119,6 +122,11 @@ swr_generate_vs_key(struct swr_jit_vs_key &key,
 {
    memset(&key, 0, sizeof(key));
 
+   key.clip_plane_mask =
+      swr_vs->info.base.clipdist_writemask ?
+      swr_vs->info.base.clipdist_writemask & ctx->rasterizer->clip_plane_enable :
+      ctx->rasterizer->clip_plane_enable;
+
    swr_generate_sampler_key(swr_vs->info, ctx, PIPE_SHADER_VERTEX, key);
 }
 
@@ -251,6 +259,63 @@ BuilderSWR::CompileVS(struct swr_context *ctx, swr_jit_vs_key &key)
       }
    }
 
+   if (ctx->rasterizer->clip_plane_enable ||
+       swr_vs->info.base.culldist_writemask) {
+      unsigned clip_mask = ctx->rasterizer->clip_plane_enable;
+
+      unsigned cv = 0;
+      if (swr_vs->info.base.writes_clipvertex) {
+         cv = 1 + locate_linkage(TGSI_SEMANTIC_CLIPVERTEX, 0,
+                                 &swr_vs->info.base);
+      } else {
+         for (int i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) {
+            if (swr_vs->info.base.output_semantic_name[i] == TGSI_SEMANTIC_POSITION &&
+                swr_vs->info.base.output_semantic_index[i] == 0) {
+               cv = i;
+               break;
+            }
+         }
+      }
+      LLVMValueRef cx = LLVMBuildLoad(gallivm->builder, outputs[cv][0], "");
+      LLVMValueRef cy = LLVMBuildLoad(gallivm->builder, outputs[cv][1], "");
+      LLVMValueRef cz = LLVMBuildLoad(gallivm->builder, outputs[cv][2], "");
+      LLVMValueRef cw = LLVMBuildLoad(gallivm->builder, outputs[cv][3], "");
+
+      for (unsigned val = 0; val < PIPE_MAX_CLIP_PLANES; val++) {
+         // clip distance overrides user clip planes
+         if ((swr_vs->info.base.clipdist_writemask & clip_mask & (1 << val)) ||
+             ((swr_vs->info.base.culldist_writemask << swr_vs->info.base.num_written_clipdistance) & (1 << val))) {
+            unsigned cv = 1 + locate_linkage(TGSI_SEMANTIC_CLIPDIST, val < 4 ? 0 : 1,
+                                             &swr_vs->info.base);
+            if (val < 4) {
+               LLVMValueRef dist = LLVMBuildLoad(gallivm->builder, outputs[cv][val], "");
+               STORE(unwrap(dist), vtxOutput, {0, 0, VERTEX_CLIPCULL_DIST_LO_SLOT, val});
+            } else {
+               LLVMValueRef dist = LLVMBuildLoad(gallivm->builder, outputs[cv][val - 4], "");
+               STORE(unwrap(dist), vtxOutput, {0, 0, VERTEX_CLIPCULL_DIST_HI_SLOT, val - 4});
+            }
+            continue;
+         }
+
+         if (!(clip_mask & (1 << val)))
+            continue;
+
+         Value *px = LOAD(GEP(hPrivateData, {0, swr_draw_context_userClipPlanes, val, 0}));
+         Value *py = LOAD(GEP(hPrivateData, {0, swr_draw_context_userClipPlanes, val, 1}));
+         Value *pz = LOAD(GEP(hPrivateData, {0, swr_draw_context_userClipPlanes, val, 2}));
+         Value *pw = LOAD(GEP(hPrivateData, {0, swr_draw_context_userClipPlanes, val, 3}));
+         Value *dist = FADD(FMUL(unwrap(cx), VBROADCAST(px)),
+                            FADD(FMUL(unwrap(cy), VBROADCAST(py)),
+                                 FADD(FMUL(unwrap(cz), VBROADCAST(pz)),
+                                      FMUL(unwrap(cw), VBROADCAST(pw)))));
+
+         if (val < 4)
+            STORE(dist, vtxOutput, {0, 0, VERTEX_CLIPCULL_DIST_LO_SLOT, val});
+         else
+            STORE(dist, vtxOutput, {0, 0, VERTEX_CLIPCULL_DIST_HI_SLOT, val - 4});
+      }
+   }
+
    RET_VOID();
 
    gallivm_verify_function(gallivm, wrap(pFunction));
index 1b604b5a3c235848f70e00a50d30524a6a559f69..ccdda445119f0b3733d0c470953577dd36e1c491 100644 (file)
@@ -56,6 +56,7 @@ struct swr_jit_fs_key : swr_jit_sampler_key {
 };
 
 struct swr_jit_vs_key : swr_jit_sampler_key {
+   unsigned clip_plane_mask; // from rasterizer state & vs_info
 };
 
 namespace std
index f50537f3a61018361768636c096995269ff26ab2..3eeb98d0261b52b45349d8eb9aedf9e3345f818c 100644 (file)
@@ -849,7 +849,9 @@ swr_update_derived(struct pipe_context *pipe,
    }
 
    /* Raster state */
-   if (ctx->dirty & (SWR_NEW_RASTERIZER | SWR_NEW_FRAMEBUFFER)) {
+   if (ctx->dirty & (SWR_NEW_RASTERIZER |
+                     SWR_NEW_VS | // clipping
+                     SWR_NEW_FRAMEBUFFER)) {
       pipe_rasterizer_state *rasterizer = ctx->rasterizer;
       pipe_framebuffer_state *fb = &ctx->framebuffer;
 
@@ -906,6 +908,14 @@ swr_update_derived(struct pipe_context *pipe,
 
       rastState->depthClipEnable = rasterizer->depth_clip;
 
+      rastState->clipDistanceMask =
+         ctx->vs->info.base.num_written_clipdistance ?
+         ctx->vs->info.base.clipdist_writemask & rasterizer->clip_plane_enable :
+         rasterizer->clip_plane_enable;
+
+      rastState->cullDistanceMask =
+         ctx->vs->info.base.culldist_writemask << ctx->vs->info.base.num_written_clipdistance;
+
       SwrSetRastState(ctx->swrContext, rastState);
    }
 
@@ -1067,6 +1077,7 @@ swr_update_derived(struct pipe_context *pipe,
 
    /* VertexShader */
    if (ctx->dirty & (SWR_NEW_VS |
+                     SWR_NEW_RASTERIZER | // for clip planes
                      SWR_NEW_SAMPLER |
                      SWR_NEW_SAMPLER_VIEW |
                      SWR_NEW_FRAMEBUFFER)) {
@@ -1341,6 +1352,18 @@ swr_update_derived(struct pipe_context *pipe,
       }
    }
 
+   if (ctx->dirty & SWR_NEW_CLIP) {
+      // shader exporting clip distances overrides all user clip planes
+      if (ctx->rasterizer->clip_plane_enable &&
+          !ctx->vs->info.base.num_written_clipdistance)
+      {
+         swr_draw_context *pDC = &ctx->swrDC;
+         memcpy(pDC->userClipPlanes,
+                ctx->clip.ucp,
+                sizeof(pDC->userClipPlanes));
+      }
+   }
+
    uint32_t linkage = ctx->vs->linkageMask;
    if (ctx->rasterizer->sprite_coord_enable)
       linkage |= (1 << ctx->vs->info.base.num_outputs);