i965: Start adding support for the Sandybridge CC unit.
authorEric Anholt <eric@anholt.net>
Fri, 29 Jan 2010 19:18:26 +0000 (11:18 -0800)
committerEric Anholt <eric@anholt.net>
Thu, 25 Feb 2010 18:53:06 +0000 (10:53 -0800)
src/mesa/drivers/dri/i965/Makefile
src/mesa/drivers/dri/i965/brw_context.h
src/mesa/drivers/dri/i965/brw_defines.h
src/mesa/drivers/dri/i965/brw_state.h
src/mesa/drivers/dri/i965/brw_state_cache.c
src/mesa/drivers/dri/i965/brw_state_upload.c
src/mesa/drivers/dri/i965/brw_structs.h
src/mesa/drivers/dri/i965/gen6_cc.c [new file with mode: 0644]
src/mesa/drivers/dri/i965/gen6_depthstencil.c [new file with mode: 0644]

index 7758a792fde9f6c9ca0cfa51042fac090165c0a7..7ce794d3aa8664ee5fe4abd9c31fdcbf936a2a2c 100644 (file)
@@ -84,7 +84,9 @@ DRIVER_SOURCES = \
        brw_wm_pass2.c \
        brw_wm_sampler_state.c \
        brw_wm_state.c \
-       brw_wm_surface_state.c 
+       brw_wm_surface_state.c \
+       gen6_cc.c \
+       gen6_depthstencil.c
 
 C_SOURCES = \
        $(COMMON_SOURCES) \
index 21c4cd38a728df7aab6498716580d85d8b0abc48..ea89d4f6fa82477d47463d4885e794d085e7bdae 100644 (file)
@@ -282,6 +282,9 @@ struct brw_vs_ouput_sizes {
 
 
 enum brw_cache_id {
+   BRW_BLEND_STATE,
+   BRW_DEPTH_STENCIL_STATE,
+   BRW_COLOR_CALC_STATE,
    BRW_CC_VP,
    BRW_CC_UNIT,
    BRW_WM_PROG,
@@ -354,6 +357,9 @@ struct brw_tracked_state {
 
 /* Flags for brw->state.cache.
  */
+#define CACHE_NEW_BLEND_STATE            (1<<BRW_BLEND_STATE)
+#define CACHE_NEW_DEPTH_STENCIL_STATE    (1<<BRW_DEPTH_STENCIL_STATE)
+#define CACHE_NEW_COLOR_CALC_STATE       (1<<BRW_COLOR_CALC_STATE)
 #define CACHE_NEW_CC_VP                  (1<<BRW_CC_VP)
 #define CACHE_NEW_CC_UNIT                (1<<BRW_CC_UNIT)
 #define CACHE_NEW_WM_PROG                (1<<BRW_WM_PROG)
@@ -643,9 +649,16 @@ struct brw_context
 
 
    struct {
+      /* gen4 */
       dri_bo *prog_bo;
-      dri_bo *state_bo;
       dri_bo *vp_bo;
+
+      /* gen6 */
+      dri_bo *blend_state_bo;
+      dri_bo *depth_stencil_state_bo;
+      dri_bo *color_calc_state_bo;
+
+      dri_bo *state_bo;
    } cc;
 
    struct {
index afdc5a1d85dbd1a449fad6d9168ce740778a3469..5d3b0a8b7a0e8dedb173400e537377f7d6cdd6e9 100644 (file)
 # define BRW_VE1_COMPONENT_3_SHIFT     16
 # define BRW_VE1_DST_OFFSET_SHIFT      0
 
+#define CMD_3D_CC_STATE_POINTERS      0x780e /* GEN6+ */
 #define CMD_INDEX_BUFFER              0x780a
 #define CMD_VF_STATISTICS_965         0x780b
 #define CMD_VF_STATISTICS_GM45        0x680b
index a24a02100c00fd6cb179935cdffda4371fc06b5a..5112cd8016a1c8f87d8c8fbe9ad1e4b77a321136 100644 (file)
@@ -91,6 +91,10 @@ const struct brw_tracked_state brw_indices;
 const struct brw_tracked_state brw_vertices;
 const struct brw_tracked_state brw_index_buffer;
 const struct brw_tracked_state gen6_binding_table_pointers;
+const struct brw_tracked_state gen6_blend_state;
+const struct brw_tracked_state gen6_cc_state_pointers;
+const struct brw_tracked_state gen6_color_calc_state;
+const struct brw_tracked_state gen6_depth_stencil_state;
 
 /**
  * Use same key for WM and VS surfaces.
index 4bb98d8d5d5417c976f7d6e32b324ab210d93c00..c08cb45b75c1b8e701cce7774d608c191149be47 100644 (file)
@@ -390,6 +390,7 @@ brw_init_non_surface_cache(struct brw_context *brw)
    brw_init_cache_id(cache, "GS_UNIT", BRW_GS_UNIT);
 
    brw_init_cache_id(cache, "GS_PROG", BRW_GS_PROG);
+   brw_init_cache_id(cache, "BLEND_STATE", BRW_BLEND_STATE);
 }
 
 
index afa940962f9149a243028e540ae9daf628dbbb00..ed9e18f33c68904e8655b6ff0b6036076fe58fb7 100644 (file)
@@ -122,9 +122,13 @@ const struct brw_tracked_state *gen6_atoms[] =
    &brw_recalculate_urb_fence,
 
    &brw_cc_vp,
-   &brw_cc_unit,
 
 #endif
+   &gen6_blend_state,          /* must do before cc unit */
+   &gen6_color_calc_state,     /* must do before cc unit */
+   &gen6_depth_stencil_state,  /* must do before cc unit */
+   &gen6_cc_state_pointers,
+
    &brw_vs_surfaces,           /* must do before unit */
    &brw_wm_constant_surface,   /* must do before wm surfaces/bind bo */
    &brw_wm_surfaces,           /* must do before samplers and unit */
@@ -282,6 +286,7 @@ static struct dirty_bit_map brw_bits[] = {
 };
 
 static struct dirty_bit_map cache_bits[] = {
+   DEFINE_BIT(CACHE_NEW_BLEND_STATE),
    DEFINE_BIT(CACHE_NEW_CC_VP),
    DEFINE_BIT(CACHE_NEW_CC_UNIT),
    DEFINE_BIT(CACHE_NEW_WM_PROG),
index 66d4127271afced963587ad21919ee639f496c0c..10c0c62202703e906e1725264e085102b200e7cd 100644 (file)
@@ -658,7 +658,105 @@ struct brw_clip_unit_state
    GLfloat viewport_ymax;  
 };
 
+struct gen6_blend_state
+{
+   struct {
+      GLuint dest_blend_factor:5;
+      GLuint source_blend_factor:5;
+      GLuint pad3:1;
+      GLuint blend_func:3;
+      GLuint pad2:1;
+      GLuint ia_dest_blend_factor:5;
+      GLuint ia_source_blend_factor:5;
+      GLuint pad1:1;
+      GLuint ia_blend_func:3;
+      GLuint pad0:1;
+      GLuint ia_blend_enable:1;
+      GLuint blend_enable:1;
+   } blend0;
+
+   struct {
+      GLuint post_blend_clamp_enable:1;
+      GLuint pre_blend_clamp_enable:1;
+      GLuint clamp_range:2;
+      GLuint pad0:4;
+      GLuint x_dither_offset:2;
+      GLuint y_dither_offset:2;
+      GLuint dither_enable:1;
+      GLuint alpha_test_func:3;
+      GLuint alpha_test_enable:1;
+      GLuint pad1:1;
+      GLuint logic_op_func:4;
+      GLuint logic_op_enable:1;
+      GLuint pad2:1;
+      GLuint write_disable_b:1;
+      GLuint write_disable_g:1;
+      GLuint write_disable_r:1;
+      GLuint write_disable_a:1;
+      GLuint pad3:1;
+      GLuint alpha_to_coverage_dither:1;
+      GLuint alpha_to_one:1;
+      GLuint alpha_to_coverage:1;
+   } blend1;
+};
 
+struct gen6_color_calc_state
+{
+   struct {
+      GLuint alpha_test_format:1;
+      GLuint pad0:14;
+      GLuint round_disable:1;
+      GLuint bf_stencil_ref:8;
+      GLuint stencil_ref:8;
+   } cc0;
+
+   union {
+      GLfloat alpha_ref_f;
+      struct {
+        GLuint ui:8;
+        GLuint pad0:24;
+      } alpha_ref_fi;
+   } cc1;
+
+   GLfloat constant_r;
+   GLfloat constant_g;
+   GLfloat constant_b;
+   GLfloat constant_a;
+};
+
+struct gen6_depth_stencil_state
+{
+   struct {
+      GLuint pad0:3;
+      GLuint bf_stencil_pass_depth_pass_op:3;
+      GLuint bf_stencil_pass_depth_fail_op:3;
+      GLuint bf_stencil_fail_op:3;
+      GLuint bf_stencil_func:3;
+      GLuint bf_stencil_enable:1;
+      GLuint pad1:2;
+      GLuint stencil_write_enable:1;
+      GLuint stencil_pass_depth_pass_op:3;
+      GLuint stencil_pass_depth_fail_op:3;
+      GLuint stencil_fail_op:3;
+      GLuint stencil_func:3;
+      GLuint stencil_enable:1;
+   } ds0;
+
+   struct {
+      GLuint bf_stencil_write_mask:8;
+      GLuint bf_stencil_test_mask:8;
+      GLuint stencil_write_mask:8;
+      GLuint stencil_test_mask:8;
+   } ds1;
+
+   struct {
+      GLuint pad0:25;
+      GLuint depth_write_enable:1;
+      GLuint depth_test_func:3;
+      GLuint pad1:1;
+      GLuint depth_test_enable:1;
+   } ds2;
+};
 
 struct brw_cc_unit_state
 {
@@ -752,8 +850,6 @@ struct brw_cc_unit_state
    } cc7;
 };
 
-
-
 struct brw_sf_unit_state
 {
    struct thread0 thread0;
diff --git a/src/mesa/drivers/dri/i965/gen6_cc.c b/src/mesa/drivers/dri/i965/gen6_cc.c
new file mode 100644 (file)
index 0000000..b1b6dc7
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include "brw_context.h"
+#include "brw_state.h"
+#include "brw_defines.h"
+#include "brw_util.h"
+#include "intel_batchbuffer.h"
+#include "main/macros.h"
+#include "main/enums.h"
+
+struct brw_blend_state_key {
+   GLboolean color_blend, alpha_enabled;
+
+   GLenum logic_op;
+
+   GLenum blend_eq_rgb, blend_eq_a;
+   GLenum blend_src_rgb, blend_src_a;
+   GLenum blend_dst_rgb, blend_dst_a;
+
+   GLenum alpha_func;
+
+   GLboolean dither;
+};
+
+static void
+blend_state_populate_key(struct brw_context *brw,
+                        struct brw_blend_state_key *key)
+{
+   GLcontext *ctx = &brw->intel.ctx;
+
+   memset(key, 0, sizeof(*key));
+
+   /* _NEW_COLOR */
+   if (ctx->Color._LogicOpEnabled)
+      key->logic_op = ctx->Color.LogicOp;
+   else
+      key->logic_op = GL_COPY;
+
+   /* _NEW_COLOR */
+   key->color_blend = ctx->Color.BlendEnabled;
+   if (key->color_blend) {
+      key->blend_eq_rgb = ctx->Color.BlendEquationRGB;
+      key->blend_eq_a = ctx->Color.BlendEquationA;
+      key->blend_src_rgb = ctx->Color.BlendSrcRGB;
+      key->blend_dst_rgb = ctx->Color.BlendDstRGB;
+      key->blend_src_a = ctx->Color.BlendSrcA;
+      key->blend_dst_a = ctx->Color.BlendDstA;
+   }
+
+   /* _NEW_COLOR */
+   key->alpha_enabled = ctx->Color.AlphaEnabled;
+   if (key->alpha_enabled) {
+      key->alpha_func = ctx->Color.AlphaFunc;
+   }
+
+   /* _NEW_COLOR */
+   key->dither = ctx->Color.DitherFlag;
+}
+
+/**
+ * Creates the state cache entry for the given CC unit key.
+ */
+static drm_intel_bo *
+blend_state_create_from_key(struct brw_context *brw,
+                           struct brw_blend_state_key *key)
+{
+   struct gen6_blend_state blend;
+   drm_intel_bo *bo;
+
+   memset(&blend, 0, sizeof(blend));
+
+   if (key->logic_op != GL_COPY) {
+      blend.blend1.logic_op_enable = 1;
+      blend.blend1.logic_op_func = intel_translate_logic_op(key->logic_op);
+   } else if (key->color_blend) {
+      GLenum eqRGB = key->blend_eq_rgb;
+      GLenum eqA = key->blend_eq_a;
+      GLenum srcRGB = key->blend_src_rgb;
+      GLenum dstRGB = key->blend_dst_rgb;
+      GLenum srcA = key->blend_src_a;
+      GLenum dstA = key->blend_dst_a;
+
+      if (eqRGB == GL_MIN || eqRGB == GL_MAX) {
+        srcRGB = dstRGB = GL_ONE;
+      }
+
+      if (eqA == GL_MIN || eqA == GL_MAX) {
+        srcA = dstA = GL_ONE;
+      }
+
+      blend.blend0.dest_blend_factor = brw_translate_blend_factor(dstRGB);
+      blend.blend0.source_blend_factor = brw_translate_blend_factor(srcRGB);
+      blend.blend0.blend_func = brw_translate_blend_equation(eqRGB);
+
+      blend.blend0.ia_dest_blend_factor = brw_translate_blend_factor(dstA);
+      blend.blend0.ia_source_blend_factor = brw_translate_blend_factor(srcA);
+      blend.blend0.ia_blend_func = brw_translate_blend_equation(eqA);
+
+      blend.blend0.blend_enable = 1;
+      blend.blend0.ia_blend_enable = (srcA != srcRGB ||
+                                     dstA != dstRGB ||
+                                     eqA != eqRGB);
+   }
+
+   if (key->alpha_enabled) {
+      blend.blend1.alpha_test_enable = 1;
+      blend.blend1.alpha_test_func = intel_translate_compare_func(key->alpha_func);
+
+   }
+
+   if (key->dither) {
+      blend.blend1.dither_enable = 1;
+      blend.blend1.y_dither_offset = 0;
+      blend.blend1.x_dither_offset = 0;
+   }
+
+   bo = brw_upload_cache(&brw->cache, BRW_BLEND_STATE,
+                        key, sizeof(*key),
+                        NULL, 0,
+                        &blend, sizeof(blend));
+
+   return bo;
+}
+
+static void
+prepare_blend_state(struct brw_context *brw)
+{
+   struct brw_blend_state_key key;
+
+   blend_state_populate_key(brw, &key);
+
+   drm_intel_bo_unreference(brw->cc.blend_state_bo);
+   brw->cc.blend_state_bo = brw_search_cache(&brw->cache, BRW_BLEND_STATE,
+                                            &key, sizeof(key),
+                                            NULL, 0,
+                                            NULL);
+
+   if (brw->cc.blend_state_bo == NULL)
+      brw->cc.blend_state_bo = blend_state_create_from_key(brw, &key);
+}
+
+const struct brw_tracked_state gen6_blend_state = {
+   .dirty = {
+      .mesa = _NEW_COLOR,
+      .brw = 0,
+      .cache = 0,
+   },
+   .prepare = prepare_blend_state,
+};
+
+struct brw_color_calc_state_key {
+   GLubyte blend_constant_color[4];
+   GLclampf alpha_ref;
+   GLubyte stencil_ref[2];
+};
+
+static void
+color_calc_state_populate_key(struct brw_context *brw,
+                             struct brw_color_calc_state_key *key)
+{
+   GLcontext *ctx = &brw->intel.ctx;
+
+   memset(key, 0, sizeof(*key));
+
+   /* _NEW_STENCIL */
+   if (ctx->Stencil._Enabled) {
+      const unsigned back = ctx->Stencil._BackFace;
+
+      key->stencil_ref[0] = ctx->Stencil.Ref[0];
+      if (ctx->Stencil._TestTwoSide)
+        key->stencil_ref[1] = ctx->Stencil.Ref[back];
+   }
+
+   /* _NEW_COLOR */
+   if (ctx->Color.AlphaEnabled)
+      key->alpha_ref = ctx->Color.AlphaRef;
+
+   key->blend_constant_color[0] = ctx->Color.BlendColor[0];
+   key->blend_constant_color[1] = ctx->Color.BlendColor[1];
+   key->blend_constant_color[2] = ctx->Color.BlendColor[2];
+   key->blend_constant_color[3] = ctx->Color.BlendColor[3];
+}
+
+/**
+ * Creates the state cache entry for the given CC state key.
+ */
+static drm_intel_bo *
+color_calc_state_create_from_key(struct brw_context *brw,
+                                struct brw_color_calc_state_key *key)
+{
+   struct gen6_color_calc_state cc;
+   drm_intel_bo *bo;
+
+   memset(&cc, 0, sizeof(cc));
+
+   cc.cc0.alpha_test_format = BRW_ALPHATEST_FORMAT_UNORM8;
+   UNCLAMPED_FLOAT_TO_UBYTE(cc.cc1.alpha_ref_fi.ui, key->alpha_ref);
+
+   cc.cc0.stencil_ref = key->stencil_ref[0];
+   cc.cc0.bf_stencil_ref = key->stencil_ref[1];
+
+   cc.constant_r = key->blend_constant_color[0];
+   cc.constant_g = key->blend_constant_color[1];
+   cc.constant_b = key->blend_constant_color[2];
+   cc.constant_a = key->blend_constant_color[3];
+
+   bo = brw_upload_cache(&brw->cache, BRW_COLOR_CALC_STATE,
+                        key, sizeof(*key),
+                        NULL, 0,
+                        &cc, sizeof(cc));
+
+   return bo;
+}
+
+static void
+prepare_color_calc_state(struct brw_context *brw)
+{
+   struct brw_color_calc_state_key key;
+
+   color_calc_state_populate_key(brw, &key);
+
+   drm_intel_bo_unreference(brw->cc.state_bo);
+   brw->cc.state_bo = brw_search_cache(&brw->cache, BRW_COLOR_CALC_STATE,
+                                      &key, sizeof(key),
+                                      NULL, 0,
+                                      NULL);
+
+   if (brw->cc.state_bo == NULL)
+      brw->cc.state_bo = color_calc_state_create_from_key(brw, &key);
+}
+
+const struct brw_tracked_state gen6_color_calc_state = {
+   .dirty = {
+      .mesa = _NEW_COLOR,
+      .brw = 0,
+      .cache = 0,
+   },
+   .prepare = prepare_color_calc_state,
+};
+
+static void upload_cc_state_pointers(struct brw_context *brw)
+{
+   struct intel_context *intel = &brw->intel;
+
+   BEGIN_BATCH(4);
+   OUT_BATCH(CMD_3D_CC_STATE_POINTERS << 16 | (4 - 2));
+   OUT_RELOC(brw->cc.state_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, 1);
+   OUT_RELOC(brw->cc.blend_state_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, 1);
+   OUT_RELOC(brw->cc.depth_stencil_state_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, 1);
+   ADVANCE_BATCH();
+}
+
+
+static void prepare_cc_state_pointers(struct brw_context *brw)
+{
+   brw_add_validated_bo(brw, brw->cc.state_bo);
+   brw_add_validated_bo(brw, brw->cc.blend_state_bo);
+   brw_add_validated_bo(brw, brw->cc.depth_stencil_state_bo);
+}
+
+const struct brw_tracked_state gen6_cc_state_pointers = {
+   .dirty = {
+      .mesa = 0,
+      .brw = BRW_NEW_BATCH,
+      .cache = (CACHE_NEW_BLEND_STATE |
+               CACHE_NEW_COLOR_CALC_STATE |
+               CACHE_NEW_DEPTH_STENCIL_STATE)
+   },
+   .prepare = prepare_cc_state_pointers,
+   .emit = upload_cc_state_pointers,
+};
diff --git a/src/mesa/drivers/dri/i965/gen6_depthstencil.c b/src/mesa/drivers/dri/i965/gen6_depthstencil.c
new file mode 100644 (file)
index 0000000..9609271
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include "brw_context.h"
+#include "brw_state.h"
+#include "brw_defines.h"
+#include "brw_util.h"
+#include "main/macros.h"
+#include "main/enums.h"
+
+struct brw_depth_stencil_state_key {
+   GLenum depth_func;
+   GLboolean depth_test, depth_write;
+   GLboolean stencil, stencil_two_side;
+   GLenum stencil_func[2], stencil_fail_op[2];
+   GLenum stencil_pass_depth_fail_op[2], stencil_pass_depth_pass_op[2];
+   GLubyte stencil_write_mask[2], stencil_test_mask[2];
+};
+
+static void
+depth_stencil_state_populate_key(struct brw_context *brw,
+                                struct brw_depth_stencil_state_key *key)
+{
+   GLcontext *ctx = &brw->intel.ctx;
+   const unsigned back = ctx->Stencil._BackFace;
+
+   memset(key, 0, sizeof(*key));
+
+   /* _NEW_STENCIL */
+   key->stencil = ctx->Stencil._Enabled;
+   key->stencil_two_side = ctx->Stencil._TestTwoSide;
+
+   if (key->stencil) {
+      key->stencil_func[0] = ctx->Stencil.Function[0];
+      key->stencil_fail_op[0] = ctx->Stencil.FailFunc[0];
+      key->stencil_pass_depth_fail_op[0] = ctx->Stencil.ZFailFunc[0];
+      key->stencil_pass_depth_pass_op[0] = ctx->Stencil.ZPassFunc[0];
+      key->stencil_write_mask[0] = ctx->Stencil.WriteMask[0];
+      key->stencil_test_mask[0] = ctx->Stencil.ValueMask[0];
+   }
+   if (key->stencil_two_side) {
+      key->stencil_func[1] = ctx->Stencil.Function[back];
+      key->stencil_fail_op[1] = ctx->Stencil.FailFunc[back];
+      key->stencil_pass_depth_fail_op[1] = ctx->Stencil.ZFailFunc[back];
+      key->stencil_pass_depth_pass_op[1] = ctx->Stencil.ZPassFunc[back];
+      key->stencil_write_mask[1] = ctx->Stencil.WriteMask[back];
+      key->stencil_test_mask[1] = ctx->Stencil.ValueMask[back];
+   }
+
+   key->depth_test = ctx->Depth.Test;
+   if (key->depth_test) {
+      key->depth_func = ctx->Depth.Func;
+      key->depth_write = ctx->Depth.Mask;
+   }
+}
+
+/**
+ * Creates the state cache entry for the given DEPTH_STENCIL_STATE state key.
+ */
+static dri_bo *
+depth_stencil_state_create_from_key(struct brw_context *brw,
+                                   struct brw_depth_stencil_state_key *key)
+{
+   struct gen6_depth_stencil_state ds;
+   dri_bo *bo;
+
+   memset(&ds, 0, sizeof(ds));
+
+   /* _NEW_STENCIL */
+   if (key->stencil) {
+      ds.ds0.stencil_enable = 1;
+      ds.ds0.stencil_func =
+        intel_translate_compare_func(key->stencil_func[0]);
+      ds.ds0.stencil_fail_op =
+        intel_translate_stencil_op(key->stencil_fail_op[0]);
+      ds.ds0.stencil_pass_depth_fail_op =
+        intel_translate_stencil_op(key->stencil_pass_depth_fail_op[0]);
+      ds.ds0.stencil_pass_depth_pass_op =
+        intel_translate_stencil_op(key->stencil_pass_depth_pass_op[0]);
+      ds.ds1.stencil_write_mask = key->stencil_write_mask[0];
+      ds.ds1.stencil_test_mask = key->stencil_test_mask[0];
+
+      if (key->stencil_two_side) {
+        ds.ds0.bf_stencil_enable = 1;
+        ds.ds0.bf_stencil_func =
+           intel_translate_compare_func(key->stencil_func[1]);
+        ds.ds0.bf_stencil_fail_op =
+           intel_translate_stencil_op(key->stencil_fail_op[1]);
+        ds.ds0.bf_stencil_pass_depth_fail_op =
+           intel_translate_stencil_op(key->stencil_pass_depth_fail_op[1]);
+        ds.ds0.bf_stencil_pass_depth_pass_op =
+           intel_translate_stencil_op(key->stencil_pass_depth_pass_op[1]);
+        ds.ds1.bf_stencil_write_mask = key->stencil_write_mask[1];
+        ds.ds1.bf_stencil_test_mask = key->stencil_test_mask[1];
+      }
+
+      /* Not really sure about this:
+       */
+      if (key->stencil_write_mask[0] ||
+         (key->stencil_two_side && key->stencil_write_mask[1]))
+        ds.ds0.stencil_write_enable = 1;
+   }
+
+   /* _NEW_DEPTH */
+   if (key->depth_test) {
+      ds.ds2.depth_test_enable = 1;
+      ds.ds2.depth_test_func = intel_translate_compare_func(key->depth_func);
+      ds.ds2.depth_write_enable = key->depth_write;
+   }
+
+   bo = brw_upload_cache(&brw->cache, BRW_DEPTH_STENCIL_STATE,
+                        key, sizeof(*key),
+                        NULL, 0,
+                        &ds, sizeof(ds));
+
+   return bo;
+}
+
+static void
+prepare_depth_stencil_state(struct brw_context *brw)
+{
+   struct brw_depth_stencil_state_key key;
+
+   depth_stencil_state_populate_key(brw, &key);
+
+   dri_bo_unreference(brw->cc.depth_stencil_state_bo);
+   brw->cc.depth_stencil_state_bo = brw_search_cache(&brw->cache,
+                                                    BRW_DEPTH_STENCIL_STATE,
+                                                    &key, sizeof(key),
+                                                    NULL, 0,
+                                                    NULL);
+
+   if (brw->cc.depth_stencil_state_bo == NULL)
+      brw->cc.depth_stencil_state_bo =
+        depth_stencil_state_create_from_key(brw, &key);
+}
+
+const struct brw_tracked_state gen6_depth_stencil_state = {
+   .dirty = {
+      .mesa = _NEW_DEPTH | _NEW_STENCIL,
+      .brw = 0,
+      .cache = 0,
+   },
+   .prepare = prepare_depth_stencil_state,
+};