r300g: fix colormask with non-BGRA formats
authorMarek Olšák <maraeo@gmail.com>
Fri, 14 Sep 2012 03:34:23 +0000 (05:34 +0200)
committerMarek Olšák <maraeo@gmail.com>
Fri, 14 Sep 2012 03:55:00 +0000 (05:55 +0200)
NOTE: This is a candidate for the stable branches.

src/gallium/drivers/r300/r300_context.h
src/gallium/drivers/r300/r300_emit.c
src/gallium/drivers/r300/r300_state.c
src/gallium/drivers/r300/r300_texture.c

index 6a06442060398e463345abbd2b5e57f6c487b1f5..2c7b477685a7b67573485d08ad3dd730ab7809ab 100644 (file)
@@ -41,6 +41,16 @@ struct r300_fragment_shader;
 struct r300_vertex_shader;
 struct r300_stencilref_context;
 
+enum colormask_swizzle {
+    COLORMASK_BGRA,
+    COLORMASK_RGBA,
+    COLORMASK_RRRR,
+    COLORMASK_AAAA,
+    COLORMASK_GRRG,
+    COLORMASK_ARRA,
+    COLORMASK_NUM_SWIZZLES
+};
+
 struct r300_atom {
     /* Name, for debugging. */
     const char* name;
@@ -66,7 +76,7 @@ struct r300_aa_state {
 struct r300_blend_state {
     struct pipe_blend_state state;
 
-    uint32_t cb_clamp[8];
+    uint32_t cb_clamp[COLORMASK_NUM_SWIZZLES][8];
     uint32_t cb_noclamp[8];
     uint32_t cb_no_readwrite[8];
 };
@@ -320,6 +330,8 @@ struct r300_surface {
 
     /* Whether the CBZB clear is allowed on the surface. */
     boolean cbzb_allowed;
+
+    unsigned colormask_swizzle;
 };
 
 struct r300_texture_desc {
index 4c0daa6c56dd90045aa9cfd55b3d01881fea1e0d..1da6044eb87f21d91e9ecfad2da330b6e2303ec1 100644 (file)
@@ -45,10 +45,12 @@ void r300_emit_blend_state(struct r300_context* r300,
     CS_LOCALS(r300);
 
     if (fb->nr_cbufs) {
-        if (fb->cbufs[0]->format == PIPE_FORMAT_R16G16B16A16_FLOAT)
+        if (fb->cbufs[0]->format == PIPE_FORMAT_R16G16B16A16_FLOAT) {
             WRITE_CS_TABLE(blend->cb_noclamp, size);
-        else
-            WRITE_CS_TABLE(blend->cb_clamp, size);
+        } else {
+            unsigned swz = r300_surface(fb->cbufs[0])->colormask_swizzle;
+            WRITE_CS_TABLE(blend->cb_clamp[swz], size);
+        }
     } else {
         WRITE_CS_TABLE(blend->cb_no_readwrite, size);
     }
index 46a6bf669b73209ed46b7ac6857308e2a90e9c78..b43f330af98382740781da3479274317211ccd76 100644 (file)
@@ -169,15 +169,52 @@ static boolean blend_discard_if_src_alpha_color_1(unsigned srcRGB, unsigned srcA
             dstA == PIPE_BLENDFACTOR_ONE);
 }
 
+/* The hardware colormask is clunky a must be swizzled depending on the format.
+ * This was figured out by trial-and-error. */
 static unsigned bgra_cmask(unsigned mask)
 {
-    /* Gallium uses RGBA color ordering while R300 expects BGRA. */
-
     return ((mask & PIPE_MASK_R) << 2) |
            ((mask & PIPE_MASK_B) >> 2) |
            (mask & (PIPE_MASK_G | PIPE_MASK_A));
 }
 
+static unsigned rgba_cmask(unsigned mask)
+{
+    return mask & PIPE_MASK_RGBA;
+}
+
+static unsigned rrrr_cmask(unsigned mask)
+{
+    return (mask & PIPE_MASK_R) |
+           ((mask & PIPE_MASK_R) << 1) |
+           ((mask & PIPE_MASK_R) << 2) |
+           ((mask & PIPE_MASK_R) << 3);
+}
+
+static unsigned aaaa_cmask(unsigned mask)
+{
+    return ((mask & PIPE_MASK_A) >> 3) |
+           ((mask & PIPE_MASK_A) >> 2) |
+           ((mask & PIPE_MASK_A) >> 1) |
+           (mask & PIPE_MASK_A);
+}
+
+static unsigned grrg_cmask(unsigned mask)
+{
+    return ((mask & PIPE_MASK_R) << 1) |
+           ((mask & PIPE_MASK_R) << 2) |
+           ((mask & PIPE_MASK_G) >> 1) |
+           ((mask & PIPE_MASK_G) << 2);
+}
+
+static unsigned arra_cmask(unsigned mask)
+{
+    return ((mask & PIPE_MASK_R) << 1) |
+           ((mask & PIPE_MASK_R) << 2) |
+           ((mask & PIPE_MASK_A) >> 3) |
+           (mask & PIPE_MASK_A);
+}
+
 /* Create a new blend state based on the CSO blend state.
  *
  * This encompasses alpha blending, logic/raster ops, and blend dithering. */
@@ -190,9 +227,9 @@ static void* r300_create_blend_state(struct pipe_context* pipe,
     uint32_t blend_control_noclamp = 0;    /* R300_RB3D_CBLEND: 0x4e04 */
     uint32_t alpha_blend_control = 0; /* R300_RB3D_ABLEND: 0x4e08 */
     uint32_t alpha_blend_control_noclamp = 0; /* R300_RB3D_ABLEND: 0x4e08 */
-    uint32_t color_channel_mask = 0;  /* R300_RB3D_COLOR_CHANNEL_MASK: 0x4e0c */
     uint32_t rop = 0;                 /* R300_RB3D_ROPCNTL: 0x4e18 */
     uint32_t dither = 0;              /* R300_RB3D_DITHER_CTL: 0x4e50 */
+    int i;
     CB_LOCALS;
 
     blend->state = *state;
@@ -331,20 +368,6 @@ static void* r300_create_blend_state(struct pipe_context* pipe,
                 (state->logicop_func) << R300_RB3D_ROPCNTL_ROP_SHIFT;
     }
 
-    /* Color channel masks for all MRTs. */
-    color_channel_mask = bgra_cmask(state->rt[0].colormask);
-    if (r300screen->caps.is_r500 && state->independent_blend_enable) {
-        if (state->rt[1].blend_enable) {
-            color_channel_mask |= bgra_cmask(state->rt[1].colormask) << 4;
-        }
-        if (state->rt[2].blend_enable) {
-            color_channel_mask |= bgra_cmask(state->rt[2].colormask) << 8;
-        }
-        if (state->rt[3].blend_enable) {
-            color_channel_mask |= bgra_cmask(state->rt[3].colormask) << 12;
-        }
-    }
-
     /* Neither fglrx nor classic r300 ever set this, regardless of dithering
      * state. Since it's an optional implementation detail, we can leave it
      * out and never dither.
@@ -358,14 +381,27 @@ static void* r300_create_blend_state(struct pipe_context* pipe,
     */
 
     /* Build a command buffer. */
-    BEGIN_CB(blend->cb_clamp, 8);
-    OUT_CB_REG(R300_RB3D_ROPCNTL, rop);
-    OUT_CB_REG_SEQ(R300_RB3D_CBLEND, 3);
-    OUT_CB(blend_control);
-    OUT_CB(alpha_blend_control);
-    OUT_CB(color_channel_mask);
-    OUT_CB_REG(R300_RB3D_DITHER_CTL, dither);
-    END_CB;
+    {
+        unsigned (*func[COLORMASK_NUM_SWIZZLES])(unsigned) = {
+            bgra_cmask,
+            rgba_cmask,
+            rrrr_cmask,
+            aaaa_cmask,
+            grrg_cmask,
+            arra_cmask
+        };
+
+        for (i = 0; i < COLORMASK_NUM_SWIZZLES; i++) {
+            BEGIN_CB(blend->cb_clamp[i], 8);
+            OUT_CB_REG(R300_RB3D_ROPCNTL, rop);
+            OUT_CB_REG_SEQ(R300_RB3D_CBLEND, 3);
+            OUT_CB(blend_control);
+            OUT_CB(alpha_blend_control);
+            OUT_CB(func[i](state->rt[0].colormask));
+            OUT_CB_REG(R300_RB3D_DITHER_CTL, dither);
+            END_CB;
+        }
+    }
 
     /* Build a command buffer. */
     BEGIN_CB(blend->cb_noclamp, 8);
@@ -373,7 +409,7 @@ static void* r300_create_blend_state(struct pipe_context* pipe,
     OUT_CB_REG_SEQ(R300_RB3D_CBLEND, 3);
     OUT_CB(blend_control_noclamp);
     OUT_CB(alpha_blend_control_noclamp);
-    OUT_CB(color_channel_mask);
+    OUT_CB(rgba_cmask(state->rt[0].colormask));
     OUT_CB_REG(R300_RB3D_DITHER_CTL, dither);
     END_CB;
 
index 6901722f6c1594f85260c3ce119aa0e0f6cedcbe..39cca78ebce39ec5685e2a2e2242bf1945e875a9 100644 (file)
@@ -704,10 +704,87 @@ static uint32_t r300_translate_out_fmt(enum pipe_format format)
     }
 }
 
+static uint32_t r300_translate_colormask_swizzle(enum pipe_format format)
+{
+    switch (format) {
+    case PIPE_FORMAT_A8_UNORM:
+    case PIPE_FORMAT_A8_SNORM:
+    case PIPE_FORMAT_A16_UNORM:
+    case PIPE_FORMAT_A16_SNORM:
+    case PIPE_FORMAT_A16_FLOAT:
+    case PIPE_FORMAT_A32_FLOAT:
+        return COLORMASK_AAAA;
+
+    case PIPE_FORMAT_I8_UNORM:
+    case PIPE_FORMAT_I8_SNORM:
+    case PIPE_FORMAT_L8_UNORM:
+    case PIPE_FORMAT_L8_SNORM:
+    case PIPE_FORMAT_R8_UNORM:
+    case PIPE_FORMAT_R8_SNORM:
+    case PIPE_FORMAT_R32_FLOAT:
+    case PIPE_FORMAT_L32_FLOAT:
+    case PIPE_FORMAT_I32_FLOAT:
+        return COLORMASK_RRRR;
+
+    case PIPE_FORMAT_L8A8_SNORM:
+    case PIPE_FORMAT_L8A8_UNORM:
+    case PIPE_FORMAT_L16A16_UNORM:
+    case PIPE_FORMAT_L16A16_SNORM:
+    case PIPE_FORMAT_L16A16_FLOAT:
+    case PIPE_FORMAT_L32A32_FLOAT:
+        return COLORMASK_ARRA;
+
+    case PIPE_FORMAT_R8G8_SNORM:
+    case PIPE_FORMAT_R8G8_UNORM:
+    case PIPE_FORMAT_R16G16_UNORM:
+    case PIPE_FORMAT_R16G16_SNORM:
+    case PIPE_FORMAT_R16G16_FLOAT:
+    case PIPE_FORMAT_R32G32_FLOAT:
+        return COLORMASK_GRRG;
+
+    case PIPE_FORMAT_B5G6R5_UNORM:
+    case PIPE_FORMAT_B5G5R5A1_UNORM:
+    case PIPE_FORMAT_B5G5R5X1_UNORM:
+    case PIPE_FORMAT_B4G4R4A4_UNORM:
+    case PIPE_FORMAT_B4G4R4X4_UNORM:
+    case PIPE_FORMAT_B8G8R8A8_UNORM:
+    /*case PIPE_FORMAT_B8G8R8A8_SNORM:*/
+    case PIPE_FORMAT_B8G8R8X8_UNORM:
+    /*case PIPE_FORMAT_B8G8R8X8_SNORM:*/
+    case PIPE_FORMAT_B10G10R10A2_UNORM:
+        return COLORMASK_BGRA;
+
+    case PIPE_FORMAT_R8G8B8X8_UNORM:
+    /*case PIPE_FORMAT_R8G8B8X8_SNORM:*/
+    case PIPE_FORMAT_R8G8B8A8_UNORM:
+    case PIPE_FORMAT_R8G8B8A8_SNORM:
+    case PIPE_FORMAT_R10G10B10A2_UNORM:
+    case PIPE_FORMAT_R10G10B10X2_SNORM:
+    case PIPE_FORMAT_R16_UNORM:
+    case PIPE_FORMAT_R16G16B16A16_UNORM:
+    case PIPE_FORMAT_R16_SNORM:
+    case PIPE_FORMAT_R16G16B16A16_SNORM:
+    case PIPE_FORMAT_R16_FLOAT:
+    case PIPE_FORMAT_R16G16B16A16_FLOAT:
+    case PIPE_FORMAT_R32G32B32A32_FLOAT:
+    case PIPE_FORMAT_L16_UNORM:
+    case PIPE_FORMAT_L16_SNORM:
+    case PIPE_FORMAT_L16_FLOAT:
+    case PIPE_FORMAT_I16_UNORM:
+    case PIPE_FORMAT_I16_SNORM:
+    case PIPE_FORMAT_I16_FLOAT:
+        return COLORMASK_RGBA;
+
+    default:
+        return ~0; /* Unsupported. */
+    }
+}
+
 boolean r300_is_colorbuffer_format_supported(enum pipe_format format)
 {
     return r300_translate_colorformat(format) != ~0 &&
-           r300_translate_out_fmt(format) != ~0;
+           r300_translate_out_fmt(format) != ~0 &&
+           r300_translate_colormask_swizzle(format) != ~0;
 }
 
 boolean r300_is_zs_format_supported(enum pipe_format format)
@@ -827,6 +904,8 @@ static void r300_texture_setup_fb_state(struct r300_surface *surf)
                 R300_COLOR_TILE(tex->tex.macrotile[level]) |
                 R300_COLOR_MICROTILE(tex->tex.microtile);
         surf->format = r300_translate_out_fmt(surf->base.format);
+        surf->colormask_swizzle =
+            r300_translate_colormask_swizzle(surf->base.format);
     }
 }