[Mesa-dev] [PATCH] st/mesa: optionally apply texture swizzle to border color

Christoph Bumiller e0425955 at student.tuwien.ac.at
Sat Apr 13 07:31:57 PDT 2013


From: Christoph Bumiller <christoph.bumiller at speed.at>

This is the only sane solution for nv50 and nvc0 (really, trust me),
but since on other hardware the border colour is tightly coupled with
texture state they'd have to undo the swizzle, so I've added a cap.

The name of the cap could be changed to be more descriptive, like
PIPE_CAP_TEXTURE_SWIZZLE_AFFECTS_BORDER_COLOR.

The dependency of update_sampler on the texture updates was
introduced to avoid doing the apply_depthmode to the swizzle twice.

More detailed explanation of driver situation:

No, really, don't suggest doing this in the driver. The driver has
elegantly separated texture view and sampler states (which are each
a structure in a table in VRAM and should not be updated to avoid
performance loss), and table are bound to the independent (!) texture
and sampler slots in shaders which must be separately indexable
indirectly).
So, if I was to do this in the driver, I'd have to add separate sampler
state object instances for each texture view with appropriately swizzled
border color, and there's only 16 slots, so I'd be limited to 4 texture
units.
Not to mention the sheer insanity, ugliness and emotional pain incurred
when writing that code when it COULD be so easy and simple in the state
tracker where you know that textures and samplers are tightly coupled,
while in gallium I cannot assume that to be the case.
---
 src/gallium/docs/source/cso/sampler.rst          |    7 ++-
 src/gallium/docs/source/screen.rst               |    2 +
 src/gallium/drivers/freedreno/freedreno_screen.c |    1 +
 src/gallium/drivers/i915/i915_screen.c           |    1 +
 src/gallium/drivers/llvmpipe/lp_screen.c         |    2 +
 src/gallium/drivers/nv30/nv30_screen.c           |    1 +
 src/gallium/drivers/nv50/nv50_screen.c           |    1 +
 src/gallium/drivers/nvc0/nvc0_screen.c           |    1 +
 src/gallium/drivers/r300/r300_screen.c           |    1 +
 src/gallium/drivers/r600/r600_pipe.c             |    1 +
 src/gallium/drivers/radeonsi/radeonsi_pipe.c     |    1 +
 src/gallium/drivers/softpipe/sp_screen.c         |    2 +
 src/gallium/drivers/svga/svga_screen.c           |    2 +
 src/gallium/include/pipe/p_defines.h             |    3 +-
 src/mesa/state_tracker/st_atom.c                 |    2 +-
 src/mesa/state_tracker/st_atom_sampler.c         |   65 +++++++++++++++++++++-
 src/mesa/state_tracker/st_context.c              |    2 +
 src/mesa/state_tracker/st_context.h              |    1 +
 18 files changed, 89 insertions(+), 7 deletions(-)

diff --git a/src/gallium/docs/source/cso/sampler.rst b/src/gallium/docs/source/cso/sampler.rst
index 26ffc18..1911cea 100644
--- a/src/gallium/docs/source/cso/sampler.rst
+++ b/src/gallium/docs/source/cso/sampler.rst
@@ -101,7 +101,10 @@ max_lod
 border_color
     Color union used for texel coordinates that are outside the [0,width-1],
     [0, height-1] or [0, depth-1] ranges. Interpreted according to sampler
-    view format.
+    view format, unless the driver reports
+    PIPE_CAP_BORDER_COLOR_QUIRK, in which case this value is substituted for
+    the texture color exactly as specified, the sampler view format and swizzle
+    have no effect on it.
 max_anisotropy
     Maximum anistropy ratio to use when sampling from textures.  For example,
     if max_anistropy=4, a region of up to 1 by 4 texels will be sampled.
@@ -111,4 +114,4 @@ max_anisotropy
 seamless_cube_map
     If set, the bilinear filter of a cube map may take samples from adjacent
     cube map faces when sampled near a texture border to produce a seamless
-    look.
\ No newline at end of file
+    look.
diff --git a/src/gallium/docs/source/screen.rst b/src/gallium/docs/source/screen.rst
index 4b01d77..495398b 100644
--- a/src/gallium/docs/source/screen.rst
+++ b/src/gallium/docs/source/screen.rst
@@ -151,6 +151,8 @@ The integer capabilities:
   dedicated memory should return 1 and all software rasterizers should return 0.
 * ``PIPE_CAP_QUERY_PIPELINE_STATISTICS``: Whether PIPE_QUERY_PIPELINE_STATISTICS
   is supported.
+* ``PIPE_CAP_BORDER_COLOR_QUIRK``: Whether the sampler view's format and swizzle
+  affect the border color.
 
 
 .. _pipe_capf:
diff --git a/src/gallium/drivers/freedreno/freedreno_screen.c b/src/gallium/drivers/freedreno/freedreno_screen.c
index 283d07f..5b60401 100644
--- a/src/gallium/drivers/freedreno/freedreno_screen.c
+++ b/src/gallium/drivers/freedreno/freedreno_screen.c
@@ -200,6 +200,7 @@ fd_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
 	case PIPE_CAP_USER_VERTEX_BUFFERS:
 	case PIPE_CAP_USER_INDEX_BUFFERS:
 	case PIPE_CAP_QUERY_PIPELINE_STATISTICS:
+	case PIPE_CAP_BORDER_COLOR_QUIRK:
 		return 0;
 
 	/* Stream output. */
diff --git a/src/gallium/drivers/i915/i915_screen.c b/src/gallium/drivers/i915/i915_screen.c
index 54b2154..4c3d52f 100644
--- a/src/gallium/drivers/i915/i915_screen.c
+++ b/src/gallium/drivers/i915/i915_screen.c
@@ -213,6 +213,7 @@ i915_get_param(struct pipe_screen *screen, enum pipe_cap cap)
    case PIPE_CAP_QUERY_PIPELINE_STATISTICS:
    case PIPE_CAP_TEXTURE_MULTISAMPLE:
    case PIPE_CAP_MIN_MAP_BUFFER_ALIGNMENT:
+   case PIPE_CAP_BORDER_COLOR_QUIRK:
       return 0;
 
    case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT:
diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c
index ebcf680..9506162 100644
--- a/src/gallium/drivers/llvmpipe/lp_screen.c
+++ b/src/gallium/drivers/llvmpipe/lp_screen.c
@@ -138,6 +138,8 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
       return 1;
    case PIPE_CAP_TEXTURE_SWIZZLE:
       return 1;
+   case PIPE_CAP_BORDER_COLOR_QUIRK:
+      return 0;
    case PIPE_CAP_MAX_TEXTURE_2D_LEVELS:
       return LP_MAX_TEXTURE_2D_LEVELS;
    case PIPE_CAP_MAX_TEXTURE_3D_LEVELS:
diff --git a/src/gallium/drivers/nv30/nv30_screen.c b/src/gallium/drivers/nv30/nv30_screen.c
index e33710e..52a3ec9 100644
--- a/src/gallium/drivers/nv30/nv30_screen.c
+++ b/src/gallium/drivers/nv30/nv30_screen.c
@@ -123,6 +123,7 @@ nv30_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
    case PIPE_CAP_TEXTURE_BUFFER_OBJECTS:
    case PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
    case PIPE_CAP_QUERY_PIPELINE_STATISTICS:
+   case PIPE_CAP_BORDER_COLOR_QUIRK: /* TODO: check */
       return 0;
    case PIPE_CAP_VERTEX_BUFFER_OFFSET_4BYTE_ALIGNED_ONLY:
    case PIPE_CAP_VERTEX_BUFFER_STRIDE_4BYTE_ALIGNED_ONLY:
diff --git a/src/gallium/drivers/nv50/nv50_screen.c b/src/gallium/drivers/nv50/nv50_screen.c
index 55081be..39e0e63 100644
--- a/src/gallium/drivers/nv50/nv50_screen.c
+++ b/src/gallium/drivers/nv50/nv50_screen.c
@@ -161,6 +161,7 @@ nv50_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
    case PIPE_CAP_CONDITIONAL_RENDER:
    case PIPE_CAP_TEXTURE_BARRIER:
    case PIPE_CAP_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION:
+   case PIPE_CAP_BORDER_COLOR_QUIRK:
    case PIPE_CAP_START_INSTANCE:
       return 1;
    case PIPE_CAP_TGSI_CAN_COMPACT_VARYINGS:
diff --git a/src/gallium/drivers/nvc0/nvc0_screen.c b/src/gallium/drivers/nvc0/nvc0_screen.c
index ccdf2cd..4768e9d 100644
--- a/src/gallium/drivers/nvc0/nvc0_screen.c
+++ b/src/gallium/drivers/nvc0/nvc0_screen.c
@@ -153,6 +153,7 @@ nvc0_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
    case PIPE_CAP_CONDITIONAL_RENDER:
    case PIPE_CAP_TEXTURE_BARRIER:
    case PIPE_CAP_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION:
+   case PIPE_CAP_BORDER_COLOR_QUIRK:
    case PIPE_CAP_START_INSTANCE:
       return 1;
    case PIPE_CAP_TGSI_CAN_COMPACT_VARYINGS:
diff --git a/src/gallium/drivers/r300/r300_screen.c b/src/gallium/drivers/r300/r300_screen.c
index 3175b3b..f8bd5ce 100644
--- a/src/gallium/drivers/r300/r300_screen.c
+++ b/src/gallium/drivers/r300/r300_screen.c
@@ -162,6 +162,7 @@ static int r300_get_param(struct pipe_screen* pscreen, enum pipe_cap param)
         case PIPE_CAP_CUBE_MAP_ARRAY:
         case PIPE_CAP_TEXTURE_BUFFER_OBJECTS:
         case PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
+        case PIPE_CAP_BORDER_COLOR_QUIRK:
             return 0;
 
         /* SWTCL-only features. */
diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c
index 3f36e63..ec05732 100644
--- a/src/gallium/drivers/r600/r600_pipe.c
+++ b/src/gallium/drivers/r600/r600_pipe.c
@@ -611,6 +611,7 @@ static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param)
 	case PIPE_CAP_VERTEX_COLOR_CLAMPED:
 	case PIPE_CAP_USER_VERTEX_BUFFERS:
 	case PIPE_CAP_QUERY_PIPELINE_STATISTICS:
+	case PIPE_CAP_BORDER_COLOR_QUIRK:
 		return 0;
 
 	/* Stream output. */
diff --git a/src/gallium/drivers/radeonsi/radeonsi_pipe.c b/src/gallium/drivers/radeonsi/radeonsi_pipe.c
index 5c25b2f..b1f50bf 100644
--- a/src/gallium/drivers/radeonsi/radeonsi_pipe.c
+++ b/src/gallium/drivers/radeonsi/radeonsi_pipe.c
@@ -380,6 +380,7 @@ static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param)
 	case PIPE_CAP_CUBE_MAP_ARRAY:
 	case PIPE_CAP_TEXTURE_BUFFER_OBJECTS:
 	case PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
+	case PIPE_CAP_BORDER_COLOR_QUIRK:
 		return 0;
 
 	/* Stream output. */
diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c
index 6915f91..fb602ba 100644
--- a/src/gallium/drivers/softpipe/sp_screen.c
+++ b/src/gallium/drivers/softpipe/sp_screen.c
@@ -94,6 +94,8 @@ softpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
       return 1;
    case PIPE_CAP_TEXTURE_SWIZZLE:
       return 1;
+   case PIPE_CAP_BORDER_COLOR_QUIRK:
+      return 0;
    case PIPE_CAP_MAX_TEXTURE_2D_LEVELS:
       return SP_MAX_TEXTURE_2D_LEVELS;
    case PIPE_CAP_MAX_TEXTURE_3D_LEVELS:
diff --git a/src/gallium/drivers/svga/svga_screen.c b/src/gallium/drivers/svga/svga_screen.c
index 6213535..a8235b8 100644
--- a/src/gallium/drivers/svga/svga_screen.c
+++ b/src/gallium/drivers/svga/svga_screen.c
@@ -166,6 +166,8 @@ svga_get_param(struct pipe_screen *screen, enum pipe_cap param)
       return 1;
    case PIPE_CAP_TEXTURE_SWIZZLE:
       return 1;
+   case PIPE_CAP_BORDER_COLOR_QUIRK:
+      return 0;
    case PIPE_CAP_USER_VERTEX_BUFFERS:
    case PIPE_CAP_USER_INDEX_BUFFERS:
       return 0;
diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h
index c790660..35d2707 100644
--- a/src/gallium/include/pipe/p_defines.h
+++ b/src/gallium/include/pipe/p_defines.h
@@ -505,7 +505,8 @@ enum pipe_cap {
    PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT = 78,
    PIPE_CAP_TGSI_TEXCOORD = 79,
    PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER = 80,
-   PIPE_CAP_QUERY_PIPELINE_STATISTICS = 81
+   PIPE_CAP_QUERY_PIPELINE_STATISTICS = 81,
+   PIPE_CAP_BORDER_COLOR_QUIRK = 82
 };
 
 /**
diff --git a/src/mesa/state_tracker/st_atom.c b/src/mesa/state_tracker/st_atom.c
index 32bcc26..7d38392 100644
--- a/src/mesa/state_tracker/st_atom.c
+++ b/src/mesa/state_tracker/st_atom.c
@@ -55,10 +55,10 @@ static const struct st_tracked_state *atoms[] =
    &st_update_viewport,
    &st_update_scissor,
    &st_update_blend,
-   &st_update_sampler,
    &st_update_vertex_texture,
    &st_update_fragment_texture,
    &st_update_geometry_texture,
+   &st_update_sampler, /* depends on update_*_texture for swizzle */
    &st_update_framebuffer,
    &st_update_msaa,
    &st_update_vs_constants,
diff --git a/src/mesa/state_tracker/st_atom_sampler.c b/src/mesa/state_tracker/st_atom_sampler.c
index 3eba5b1..1a78144 100644
--- a/src/mesa/state_tracker/st_atom_sampler.c
+++ b/src/mesa/state_tracker/st_atom_sampler.c
@@ -123,6 +123,54 @@ gl_filter_to_img_filter(GLenum filter)
 }
 
 
+static INLINE unsigned
+get_sampler_view_swz(const struct pipe_sampler_view *view, unsigned component)
+{
+   switch (component) {
+   case 1: return view->swizzle_g;
+   case 2: return view->swizzle_b;
+   case 3: return view->swizzle_a;
+   default:
+      assert(component == 0);
+      return view->swizzle_r;
+   }
+}
+
+static void
+apply_swizzle(union pipe_color_union *dst, const union pipe_color_union *src,
+              const struct pipe_sampler_view *view, boolean is_integer)
+{
+   unsigned c;
+
+   if (is_integer) {
+      for (c = 0; c < 4; ++c) {
+         unsigned swz = get_sampler_view_swz(view, c);
+         switch (swz) {
+         case PIPE_SWIZZLE_RED:   dst->ui[c] = src->ui[0]; break;
+         case PIPE_SWIZZLE_GREEN: dst->ui[c] = src->ui[1]; break;
+         case PIPE_SWIZZLE_BLUE:  dst->ui[c] = src->ui[2]; break;
+         case PIPE_SWIZZLE_ALPHA: dst->ui[c] = src->ui[3]; break;
+         default:
+            dst->ui[c] = (swz == PIPE_SWIZZLE_ONE) ? 1 : 0;
+            break;
+         }
+      }
+   } else {
+      for (c = 0; c < 4; ++c) {
+         unsigned swz = get_sampler_view_swz(view, c);
+         switch (swz) {
+         case PIPE_SWIZZLE_RED:   dst->f[c] = src->f[0]; break;
+         case PIPE_SWIZZLE_GREEN: dst->f[c] = src->f[1]; break;
+         case PIPE_SWIZZLE_BLUE:  dst->f[c] = src->f[2]; break;
+         case PIPE_SWIZZLE_ALPHA: dst->f[c] = src->f[3]; break;
+         default:
+            dst->f[c] = (swz == PIPE_SWIZZLE_ONE) ? 1.0f : 0.0f;
+            break;
+         }
+      }
+   }
+}
+
 static void
 convert_sampler(struct st_context *st,
                 struct pipe_sampler_state *sampler,
@@ -172,8 +220,10 @@ convert_sampler(struct st_context *st,
        msamp->BorderColor.ui[1] ||
        msamp->BorderColor.ui[2] ||
        msamp->BorderColor.ui[3]) {
+      struct st_texture_object *stobj = st_texture_object(texobj);
       struct gl_texture_image *teximg;
       GLboolean is_integer = GL_FALSE;
+      union pipe_color_union border_color;
 
       teximg = texobj->Image[0][texobj->BaseLevel];
 
@@ -181,9 +231,18 @@ convert_sampler(struct st_context *st,
          is_integer = _mesa_is_enum_format_integer(teximg->InternalFormat);
       }
 
-      st_translate_color(&msamp->BorderColor,
-                         &sampler->border_color,
-                         teximg ? teximg->_BaseFormat : GL_RGBA, is_integer);
+      if (st->apply_texture_swizzle_to_border_color && stobj->sampler_view) {
+         st_translate_color(&msamp->BorderColor,
+                            &border_color,
+                            teximg ? teximg->_BaseFormat : GL_RGBA, is_integer);
+
+         apply_swizzle(&sampler->border_color, &border_color,
+                       stobj->sampler_view, is_integer);
+      } else {
+         st_translate_color(&msamp->BorderColor,
+                            &sampler->border_color,
+                            teximg ? teximg->_BaseFormat : GL_RGBA, is_integer);
+      }
    }
 
    sampler->max_anisotropy = (msamp->MaxAnisotropy == 1.0 ?
diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c
index 2042be3..a6aee69 100644
--- a/src/mesa/state_tracker/st_context.c
+++ b/src/mesa/state_tracker/st_context.c
@@ -188,6 +188,8 @@ st_create_context_priv( struct gl_context *ctx, struct pipe_context *pipe,
 
    st->needs_texcoord_semantic =
       screen->get_param(screen, PIPE_CAP_TGSI_TEXCOORD);
+   st->apply_texture_swizzle_to_border_color =
+      screen->get_param(screen, PIPE_CAP_BORDER_COLOR_QUIRK);
 
    /* GL limits and extensions */
    st_init_limits(st);
diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h
index 8786a03..807453e 100644
--- a/src/mesa/state_tracker/st_context.h
+++ b/src/mesa/state_tracker/st_context.h
@@ -87,6 +87,7 @@ struct st_context
    boolean prefer_blit_based_texture_transfer;
 
    boolean needs_texcoord_semantic;
+   boolean apply_texture_swizzle_to_border_color;
 
    /* On old libGL's for linux we need to invalidate the drawables
     * on glViewpport calls, this is set via a option.
-- 
1.7.3.4



More information about the mesa-dev mailing list