mesa: add/update comments in _mesa_copy_buffer_subdata()
[mesa.git] / src / mesa / drivers / dri / i965 / brw_wm_surface_state.c
index 3b59b0b98e15455c1d930df63c2d7ae4432175a6..dedf59437c9513dd00acada3b76069901e46f3f3 100644 (file)
                    
 
 #include "main/mtypes.h"
-#include "main/texstore.h"
+#include "main/samplerobj.h"
 #include "program/prog_parameter.h"
 
 #include "intel_mipmap_tree.h"
 #include "intel_batchbuffer.h"
 #include "intel_tex.h"
 #include "intel_fbo.h"
+#include "intel_buffer_objects.h"
 
 #include "brw_context.h"
 #include "brw_state.h"
 #include "brw_defines.h"
+#include "brw_wm.h"
 
-
-static GLuint translate_tex_target( GLenum target )
+GLuint
+translate_tex_target(GLenum target)
 {
    switch (target) {
    case GL_TEXTURE_1D: 
+   case GL_TEXTURE_1D_ARRAY_EXT:
       return BRW_SURFACE_1D;
 
    case GL_TEXTURE_RECTANGLE_NV: 
       return BRW_SURFACE_2D;
 
    case GL_TEXTURE_2D: 
+   case GL_TEXTURE_2D_ARRAY_EXT:
+   case GL_TEXTURE_EXTERNAL_OES:
       return BRW_SURFACE_2D;
 
    case GL_TEXTURE_3D: 
@@ -68,92 +73,553 @@ static GLuint translate_tex_target( GLenum target )
    }
 }
 
-static uint32_t brw_format_for_mesa_format[MESA_FORMAT_COUNT] =
-{
-   [MESA_FORMAT_L8] = BRW_SURFACEFORMAT_L8_UNORM,
-   [MESA_FORMAT_I8] = BRW_SURFACEFORMAT_I8_UNORM,
-   [MESA_FORMAT_A8] = BRW_SURFACEFORMAT_A8_UNORM,
-   [MESA_FORMAT_AL88] = BRW_SURFACEFORMAT_L8A8_UNORM,
-   [MESA_FORMAT_AL1616] = BRW_SURFACEFORMAT_L16A16_UNORM,
-   [MESA_FORMAT_R8] = BRW_SURFACEFORMAT_R8_UNORM,
-   [MESA_FORMAT_R16] = BRW_SURFACEFORMAT_R16_UNORM,
-   [MESA_FORMAT_RG88] = BRW_SURFACEFORMAT_R8G8_UNORM,
-   [MESA_FORMAT_RG1616] = BRW_SURFACEFORMAT_R16G16_UNORM,
-   [MESA_FORMAT_ARGB8888] = BRW_SURFACEFORMAT_B8G8R8A8_UNORM,
-   [MESA_FORMAT_XRGB8888] = BRW_SURFACEFORMAT_B8G8R8X8_UNORM,
-   [MESA_FORMAT_RGB565] = BRW_SURFACEFORMAT_B5G6R5_UNORM,
-   [MESA_FORMAT_ARGB1555] = BRW_SURFACEFORMAT_B5G5R5A1_UNORM,
-   [MESA_FORMAT_ARGB4444] = BRW_SURFACEFORMAT_B4G4R4A4_UNORM,
-   [MESA_FORMAT_YCBCR_REV] = BRW_SURFACEFORMAT_YCRCB_NORMAL,
-   [MESA_FORMAT_YCBCR] = BRW_SURFACEFORMAT_YCRCB_SWAPUVY,
-   [MESA_FORMAT_RGB_FXT1] = BRW_SURFACEFORMAT_FXT1,
-   [MESA_FORMAT_RGBA_FXT1] = BRW_SURFACEFORMAT_FXT1,
-   [MESA_FORMAT_RGB_DXT1] = BRW_SURFACEFORMAT_DXT1_RGB,
-   [MESA_FORMAT_RGBA_DXT1] = BRW_SURFACEFORMAT_BC1_UNORM,
-   [MESA_FORMAT_RGBA_DXT3] = BRW_SURFACEFORMAT_BC2_UNORM,
-   [MESA_FORMAT_RGBA_DXT5] = BRW_SURFACEFORMAT_BC3_UNORM,
-   [MESA_FORMAT_SRGB_DXT1] = BRW_SURFACEFORMAT_DXT1_RGB_SRGB,
-   [MESA_FORMAT_SRGBA_DXT1] = BRW_SURFACEFORMAT_BC1_UNORM_SRGB,
-   [MESA_FORMAT_SRGBA_DXT3] = BRW_SURFACEFORMAT_BC2_UNORM_SRGB,
-   [MESA_FORMAT_SRGBA_DXT5] = BRW_SURFACEFORMAT_BC3_UNORM_SRGB,
-   [MESA_FORMAT_SARGB8] = BRW_SURFACEFORMAT_B8G8R8A8_UNORM_SRGB,
-   [MESA_FORMAT_SLA8] = BRW_SURFACEFORMAT_L8A8_UNORM_SRGB,
-   [MESA_FORMAT_SL8] = BRW_SURFACEFORMAT_L8_UNORM_SRGB,
-   [MESA_FORMAT_DUDV8] = BRW_SURFACEFORMAT_R8G8_SNORM,
-   [MESA_FORMAT_SIGNED_RGBA8888_REV] = BRW_SURFACEFORMAT_R8G8B8A8_SNORM,
+struct surface_format_info {
+   bool exists;
+   int sampling;
+   int filtering;
+   int shadow_compare;
+   int chroma_key;
+   int render_target;
+   int alpha_blend;
+   int input_vb;
+   int streamed_output_vb;
+   int color_processing;
+};
+
+/* This macro allows us to write the table almost as it appears in the PRM,
+ * while restructuring it to turn it into the C code we want.
+ */
+#define SF(sampl, filt, shad, ck, rt, ab, vb, so, color, sf) \
+   [sf] = { true, sampl, filt, shad, ck, rt, ab, vb, so, color },
+
+#define Y 0
+#define x 999
+/**
+ * This is the table of support for surface (texture, renderbuffer, and vertex
+ * buffer, but not depthbuffer) formats across the various hardware generations.
+ *
+ * The table is formatted to match the documentation, except that the docs have
+ * this ridiculous mapping of Y[*+~^#&] for "supported on DevWhatever".  To put
+ * it in our table, here's the mapping:
+ *
+ * Y*: 45
+ * Y+: 45 (g45/gm45)
+ * Y~: 50 (gen5)
+ * Y^: 60 (gen6)
+ * Y#: 70 (gen7)
+ *
+ * See page 88 of the Sandybridge PRM VOL4_Part1 PDF.
+ */
+const struct surface_format_info surface_formats[] = {
+/* smpl filt shad CK  RT  AB  VB  SO  color */
+   SF( Y, 50,  x,  x,  Y,  Y,  Y,  Y,  x, BRW_SURFACEFORMAT_R32G32B32A32_FLOAT)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  Y,  x, BRW_SURFACEFORMAT_R32G32B32A32_SINT)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  Y,  x, BRW_SURFACEFORMAT_R32G32B32A32_UINT)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32G32B32A32_UNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32G32B32A32_SNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R64G64_FLOAT)
+   SF( Y, 50,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_R32G32B32X32_FLOAT)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32G32B32A32_SSCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32G32B32A32_USCALED)
+   SF( Y, 50,  x,  x,  x,  x,  Y,  Y,  x, BRW_SURFACEFORMAT_R32G32B32_FLOAT)
+   SF( Y,  x,  x,  x,  x,  x,  Y,  Y,  x, BRW_SURFACEFORMAT_R32G32B32_SINT)
+   SF( Y,  x,  x,  x,  x,  x,  Y,  Y,  x, BRW_SURFACEFORMAT_R32G32B32_UINT)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32G32B32_UNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32G32B32_SNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32G32B32_SSCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32G32B32_USCALED)
+   SF( Y,  Y,  x,  x,  Y, 45,  Y,  x, 60, BRW_SURFACEFORMAT_R16G16B16A16_UNORM)
+   SF( Y,  Y,  x,  x,  Y, 60,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16B16A16_SNORM)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16B16A16_SINT)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16B16A16_UINT)
+   SF( Y,  Y,  x,  x,  Y,  Y,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16B16A16_FLOAT)
+   SF( Y, 50,  x,  x,  Y,  Y,  Y,  Y,  x, BRW_SURFACEFORMAT_R32G32_FLOAT)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  Y,  x, BRW_SURFACEFORMAT_R32G32_SINT)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  Y,  x, BRW_SURFACEFORMAT_R32G32_UINT)
+   SF( Y, 50,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_R32_FLOAT_X8X24_TYPELESS)
+   SF( Y,  x,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_X32_TYPELESS_G8X24_UINT)
+   SF( Y, 50,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_L32A32_FLOAT)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32G32_UNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32G32_SNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R64_FLOAT)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_R16G16B16X16_UNORM)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_R16G16B16X16_FLOAT)
+   SF( Y, 50,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_A32X32_FLOAT)
+   SF( Y, 50,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_L32X32_FLOAT)
+   SF( Y, 50,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_I32X32_FLOAT)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16B16A16_SSCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16B16A16_USCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32G32_SSCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32G32_USCALED)
+   SF( Y,  Y,  x,  Y,  Y,  Y,  Y,  x, 60, BRW_SURFACEFORMAT_B8G8R8A8_UNORM)
+   SF( Y,  Y,  x,  x,  Y,  Y,  x,  x,  x, BRW_SURFACEFORMAT_B8G8R8A8_UNORM_SRGB)
+/* smpl filt shad CK  RT  AB  VB  SO  color */
+   SF( Y,  Y,  x,  x,  Y,  Y,  Y,  x, 60, BRW_SURFACEFORMAT_R10G10B10A2_UNORM)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x, 60, BRW_SURFACEFORMAT_R10G10B10A2_UNORM_SRGB)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R10G10B10A2_UINT)
+   SF( Y,  Y,  x,  x,  x,  Y,  Y,  x,  x, BRW_SURFACEFORMAT_R10G10B10_SNORM_A2_UNORM)
+   SF( Y,  Y,  x,  x,  Y,  Y,  Y,  x, 60, BRW_SURFACEFORMAT_R8G8B8A8_UNORM)
+   SF( Y,  Y,  x,  x,  Y,  Y,  x,  x, 60, BRW_SURFACEFORMAT_R8G8B8A8_UNORM_SRGB)
+   SF( Y,  Y,  x,  x,  Y, 60,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8B8A8_SNORM)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8B8A8_SINT)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8B8A8_UINT)
+   SF( Y,  Y,  x,  x,  Y, 45,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16_UNORM)
+   SF( Y,  Y,  x,  x,  Y, 60,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16_SNORM)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16_SINT)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16_UINT)
+   SF( Y,  Y,  x,  x,  Y,  Y,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16_FLOAT)
+   SF( Y,  Y,  x,  x,  Y,  Y,  x,  x, 60, BRW_SURFACEFORMAT_B10G10R10A2_UNORM)
+   SF( Y,  Y,  x,  x,  Y,  Y,  x,  x, 60, BRW_SURFACEFORMAT_B10G10R10A2_UNORM_SRGB)
+   SF( Y,  Y,  x,  x,  Y,  Y,  Y,  x,  x, BRW_SURFACEFORMAT_R11G11B10_FLOAT)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  Y,  x, BRW_SURFACEFORMAT_R32_SINT)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  Y,  x, BRW_SURFACEFORMAT_R32_UINT)
+   SF( Y, 50,  Y,  x,  Y,  Y,  Y,  Y,  x, BRW_SURFACEFORMAT_R32_FLOAT)
+   SF( Y, 50,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_R24_UNORM_X8_TYPELESS)
+   SF( Y,  x,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_X24_TYPELESS_G8_UINT)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_L16A16_UNORM)
+   SF( Y, 50,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_I24X8_UNORM)
+   SF( Y, 50,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_L24X8_UNORM)
+   SF( Y, 50,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_A24X8_UNORM)
+   SF( Y, 50,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_I32_FLOAT)
+   SF( Y, 50,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_L32_FLOAT)
+   SF( Y, 50,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_A32_FLOAT)
+   SF( Y,  Y,  x,  Y,  x,  x,  x,  x, 60, BRW_SURFACEFORMAT_B8G8R8X8_UNORM)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_B8G8R8X8_UNORM_SRGB)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_R8G8B8X8_UNORM)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_R8G8B8X8_UNORM_SRGB)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_R9G9B9E5_SHAREDEXP)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_B10G10R10X2_UNORM)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_L16A16_FLOAT)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32_UNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32_SNORM)
+/* smpl filt shad CK  RT  AB  VB  SO  color */
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R10G10B10X2_USCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8B8A8_SSCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8B8A8_USCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16_SSCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16_USCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32_SSCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R32_USCALED)
+   SF( Y,  Y,  x,  Y,  Y,  Y,  x,  x,  x, BRW_SURFACEFORMAT_B5G6R5_UNORM)
+   SF( Y,  Y,  x,  x,  Y,  Y,  x,  x,  x, BRW_SURFACEFORMAT_B5G6R5_UNORM_SRGB)
+   SF( Y,  Y,  x,  Y,  Y,  Y,  x,  x,  x, BRW_SURFACEFORMAT_B5G5R5A1_UNORM)
+   SF( Y,  Y,  x,  x,  Y,  Y,  x,  x,  x, BRW_SURFACEFORMAT_B5G5R5A1_UNORM_SRGB)
+   SF( Y,  Y,  x,  Y,  Y,  Y,  x,  x,  x, BRW_SURFACEFORMAT_B4G4R4A4_UNORM)
+   SF( Y,  Y,  x,  x,  Y,  Y,  x,  x,  x, BRW_SURFACEFORMAT_B4G4R4A4_UNORM_SRGB)
+   SF( Y,  Y,  x,  x,  Y,  Y,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8_UNORM)
+   SF( Y,  Y,  x,  Y,  Y, 60,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8_SNORM)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8_SINT)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8_UINT)
+   SF( Y,  Y,  Y,  x,  Y, 45,  Y,  x, 70, BRW_SURFACEFORMAT_R16_UNORM)
+   SF( Y,  Y,  x,  x,  Y, 60,  Y,  x,  x, BRW_SURFACEFORMAT_R16_SNORM)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16_SINT)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16_UINT)
+   SF( Y,  Y,  x,  x,  Y,  Y,  Y,  x,  x, BRW_SURFACEFORMAT_R16_FLOAT)
+   SF( Y,  Y,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_I16_UNORM)
+   SF( Y,  Y,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_L16_UNORM)
+   SF( Y,  Y,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_A16_UNORM)
+   SF( Y,  Y,  x,  Y,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_L8A8_UNORM)
+   SF( Y,  Y,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_I16_FLOAT)
+   SF( Y,  Y,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_L16_FLOAT)
+   SF( Y,  Y,  Y,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_A16_FLOAT)
+   SF(45, 45,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_L8A8_UNORM_SRGB)
+   SF( Y,  Y,  x,  Y,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_R5G5_SNORM_B6_UNORM)
+   SF( x,  x,  x,  x,  Y,  Y,  x,  x,  x, BRW_SURFACEFORMAT_B5G5R5X1_UNORM)
+   SF( x,  x,  x,  x,  Y,  Y,  x,  x,  x, BRW_SURFACEFORMAT_B5G5R5X1_UNORM_SRGB)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8_SSCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8_USCALED)
+/* smpl filt shad CK  RT  AB  VB  SO  color */
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16_SSCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16_USCALED)
+   SF( Y,  Y,  x, 45,  Y,  Y,  Y,  x,  x, BRW_SURFACEFORMAT_R8_UNORM)
+   SF( Y,  Y,  x,  x,  Y, 60,  Y,  x,  x, BRW_SURFACEFORMAT_R8_SNORM)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8_SINT)
+   SF( Y,  x,  x,  x,  Y,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8_UINT)
+   SF( Y,  Y,  x,  Y,  Y,  Y,  x,  x,  x, BRW_SURFACEFORMAT_A8_UNORM)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_I8_UNORM)
+   SF( Y,  Y,  x,  Y,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_L8_UNORM)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_P4A4_UNORM)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_A4P4_UNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8_SSCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8_USCALED)
+   SF(45, 45,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_L8_UNORM_SRGB)
+   SF(45, 45,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_DXT1_RGB_SRGB)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_R1_UINT)
+   SF( Y,  Y,  x,  Y,  Y,  x,  x,  x, 60, BRW_SURFACEFORMAT_YCRCB_NORMAL)
+   SF( Y,  Y,  x,  Y,  Y,  x,  x,  x, 60, BRW_SURFACEFORMAT_YCRCB_SWAPUVY)
+   SF( Y,  Y,  x,  Y,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_BC1_UNORM)
+   SF( Y,  Y,  x,  Y,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_BC2_UNORM)
+   SF( Y,  Y,  x,  Y,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_BC3_UNORM)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_BC4_UNORM)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_BC5_UNORM)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_BC1_UNORM_SRGB)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_BC2_UNORM_SRGB)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_BC3_UNORM_SRGB)
+   SF( Y,  x,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_MONO8)
+   SF( Y,  Y,  x,  x,  Y,  x,  x,  x, 60, BRW_SURFACEFORMAT_YCRCB_SWAPUV)
+   SF( Y,  Y,  x,  x,  Y,  x,  x,  x, 60, BRW_SURFACEFORMAT_YCRCB_SWAPY)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_DXT1_RGB)
+/* smpl filt shad CK  RT  AB  VB  SO  color */
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_FXT1)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8B8_UNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8B8_SNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8B8_SSCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R8G8B8_USCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R64G64B64A64_FLOAT)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R64G64B64_FLOAT)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_BC4_SNORM)
+   SF( Y,  Y,  x,  x,  x,  x,  x,  x,  x, BRW_SURFACEFORMAT_BC5_SNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16B16_UNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16B16_SNORM)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16B16_SSCALED)
+   SF( x,  x,  x,  x,  x,  x,  Y,  x,  x, BRW_SURFACEFORMAT_R16G16B16_USCALED)
 };
+#undef x
+#undef Y
 
-static GLuint translate_tex_format( gl_format mesa_format,
-                                    GLenum internal_format,
-                                   GLenum depth_mode )
+uint32_t
+brw_format_for_mesa_format(gl_format mesa_format)
+{
+   /* This table is ordered according to the enum ordering in formats.h.  We do
+    * expect that enum to be extended without our explicit initialization
+    * staying in sync, so we initialize to 0 even though
+    * BRW_SURFACEFORMAT_R32G32B32A32_FLOAT happens to also be 0.
+    */
+   static const uint32_t table[MESA_FORMAT_COUNT] =
+   {
+      [MESA_FORMAT_RGBA8888] = 0,
+      [MESA_FORMAT_RGBA8888_REV] = 0,
+      [MESA_FORMAT_ARGB8888] = BRW_SURFACEFORMAT_B8G8R8A8_UNORM,
+      [MESA_FORMAT_ARGB8888_REV] = 0,
+      [MESA_FORMAT_XRGB8888] = BRW_SURFACEFORMAT_B8G8R8X8_UNORM,
+      [MESA_FORMAT_XRGB8888_REV] = 0,
+      [MESA_FORMAT_RGB888] = 0,
+      [MESA_FORMAT_BGR888] = 0,
+      [MESA_FORMAT_RGB565] = BRW_SURFACEFORMAT_B5G6R5_UNORM,
+      [MESA_FORMAT_RGB565_REV] = 0,
+      [MESA_FORMAT_ARGB4444] = BRW_SURFACEFORMAT_B4G4R4A4_UNORM,
+      [MESA_FORMAT_ARGB4444_REV] = 0,
+      [MESA_FORMAT_RGBA5551] = 0,
+      [MESA_FORMAT_ARGB1555] = BRW_SURFACEFORMAT_B5G5R5A1_UNORM,
+      [MESA_FORMAT_ARGB1555_REV] = 0,
+      [MESA_FORMAT_AL44] = 0,
+      [MESA_FORMAT_AL88] = BRW_SURFACEFORMAT_L8A8_UNORM,
+      [MESA_FORMAT_AL88_REV] = 0,
+      [MESA_FORMAT_AL1616] = BRW_SURFACEFORMAT_L16A16_UNORM,
+      [MESA_FORMAT_AL1616_REV] = 0,
+      [MESA_FORMAT_RGB332] = 0,
+      [MESA_FORMAT_A8] = BRW_SURFACEFORMAT_A8_UNORM,
+      [MESA_FORMAT_A16] = BRW_SURFACEFORMAT_A16_UNORM,
+      [MESA_FORMAT_L8] = BRW_SURFACEFORMAT_L8_UNORM,
+      [MESA_FORMAT_L16] = BRW_SURFACEFORMAT_L16_UNORM,
+      [MESA_FORMAT_I8] = BRW_SURFACEFORMAT_I8_UNORM,
+      [MESA_FORMAT_I16] = BRW_SURFACEFORMAT_I16_UNORM,
+      [MESA_FORMAT_YCBCR_REV] = BRW_SURFACEFORMAT_YCRCB_NORMAL,
+      [MESA_FORMAT_YCBCR] = BRW_SURFACEFORMAT_YCRCB_SWAPUVY,
+      [MESA_FORMAT_R8] = BRW_SURFACEFORMAT_R8_UNORM,
+      [MESA_FORMAT_GR88] = BRW_SURFACEFORMAT_R8G8_UNORM,
+      [MESA_FORMAT_RG88] = 0,
+      [MESA_FORMAT_R16] = BRW_SURFACEFORMAT_R16_UNORM,
+      [MESA_FORMAT_RG1616] = BRW_SURFACEFORMAT_R16G16_UNORM,
+      [MESA_FORMAT_RG1616_REV] = 0,
+      [MESA_FORMAT_ARGB2101010] = BRW_SURFACEFORMAT_B10G10R10A2_UNORM,
+      [MESA_FORMAT_Z24_S8] = 0,
+      [MESA_FORMAT_S8_Z24] = 0,
+      [MESA_FORMAT_Z16] = 0,
+      [MESA_FORMAT_X8_Z24] = 0,
+      [MESA_FORMAT_Z24_S8] = 0,
+      [MESA_FORMAT_Z32] = 0,
+      [MESA_FORMAT_S8] = 0,
+
+      [MESA_FORMAT_SRGB8] = 0,
+      [MESA_FORMAT_SRGBA8] = 0,
+      [MESA_FORMAT_SARGB8] = BRW_SURFACEFORMAT_B8G8R8A8_UNORM_SRGB,
+      [MESA_FORMAT_SL8] = BRW_SURFACEFORMAT_L8_UNORM_SRGB,
+      [MESA_FORMAT_SLA8] = BRW_SURFACEFORMAT_L8A8_UNORM_SRGB,
+      [MESA_FORMAT_SRGB_DXT1] = BRW_SURFACEFORMAT_DXT1_RGB_SRGB,
+      [MESA_FORMAT_SRGBA_DXT1] = BRW_SURFACEFORMAT_BC1_UNORM_SRGB,
+      [MESA_FORMAT_SRGBA_DXT3] = BRW_SURFACEFORMAT_BC2_UNORM_SRGB,
+      [MESA_FORMAT_SRGBA_DXT5] = BRW_SURFACEFORMAT_BC3_UNORM_SRGB,
+
+      [MESA_FORMAT_RGB_FXT1] = BRW_SURFACEFORMAT_FXT1,
+      [MESA_FORMAT_RGBA_FXT1] = BRW_SURFACEFORMAT_FXT1,
+      [MESA_FORMAT_RGB_DXT1] = BRW_SURFACEFORMAT_DXT1_RGB,
+      [MESA_FORMAT_RGBA_DXT1] = BRW_SURFACEFORMAT_BC1_UNORM,
+      [MESA_FORMAT_RGBA_DXT3] = BRW_SURFACEFORMAT_BC2_UNORM,
+      [MESA_FORMAT_RGBA_DXT5] = BRW_SURFACEFORMAT_BC3_UNORM,
+
+      [MESA_FORMAT_RGBA_FLOAT32] = BRW_SURFACEFORMAT_R32G32B32A32_FLOAT,
+      [MESA_FORMAT_RGBA_FLOAT16] = BRW_SURFACEFORMAT_R16G16B16A16_FLOAT,
+      [MESA_FORMAT_RGB_FLOAT32] = 0,
+      [MESA_FORMAT_RGB_FLOAT16] = 0,
+      [MESA_FORMAT_ALPHA_FLOAT32] = BRW_SURFACEFORMAT_A32_FLOAT,
+      [MESA_FORMAT_ALPHA_FLOAT16] = BRW_SURFACEFORMAT_A16_FLOAT,
+      [MESA_FORMAT_LUMINANCE_FLOAT32] = BRW_SURFACEFORMAT_L32_FLOAT,
+      [MESA_FORMAT_LUMINANCE_FLOAT16] = BRW_SURFACEFORMAT_L16_FLOAT,
+      [MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32] = BRW_SURFACEFORMAT_L32A32_FLOAT,
+      [MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16] = BRW_SURFACEFORMAT_L16A16_FLOAT,
+      [MESA_FORMAT_INTENSITY_FLOAT32] = BRW_SURFACEFORMAT_I32_FLOAT,
+      [MESA_FORMAT_INTENSITY_FLOAT16] = BRW_SURFACEFORMAT_I16_FLOAT,
+      [MESA_FORMAT_R_FLOAT32] = BRW_SURFACEFORMAT_R32_FLOAT,
+      [MESA_FORMAT_R_FLOAT16] = BRW_SURFACEFORMAT_R16_FLOAT,
+      [MESA_FORMAT_RG_FLOAT32] = BRW_SURFACEFORMAT_R32G32_FLOAT,
+      [MESA_FORMAT_RG_FLOAT16] = BRW_SURFACEFORMAT_R16G16_FLOAT,
+
+      [MESA_FORMAT_ALPHA_UINT8] = 0,
+      [MESA_FORMAT_ALPHA_UINT16] = 0,
+      [MESA_FORMAT_ALPHA_UINT32] = 0,
+      [MESA_FORMAT_ALPHA_INT8] = 0,
+      [MESA_FORMAT_ALPHA_INT16] = 0,
+      [MESA_FORMAT_ALPHA_INT32] = 0,
+
+      [MESA_FORMAT_INTENSITY_UINT8] = 0,
+      [MESA_FORMAT_INTENSITY_UINT16] = 0,
+      [MESA_FORMAT_INTENSITY_UINT32] = 0,
+      [MESA_FORMAT_INTENSITY_INT8] = 0,
+      [MESA_FORMAT_INTENSITY_INT16] = 0,
+      [MESA_FORMAT_INTENSITY_INT32] = 0,
+
+      [MESA_FORMAT_LUMINANCE_UINT8] = 0,
+      [MESA_FORMAT_LUMINANCE_UINT16] = 0,
+      [MESA_FORMAT_LUMINANCE_UINT32] = 0,
+      [MESA_FORMAT_LUMINANCE_INT8] = 0,
+      [MESA_FORMAT_LUMINANCE_INT16] = 0,
+      [MESA_FORMAT_LUMINANCE_INT32] = 0,
+
+      [MESA_FORMAT_LUMINANCE_ALPHA_UINT8] = 0,
+      [MESA_FORMAT_LUMINANCE_ALPHA_UINT16] = 0,
+      [MESA_FORMAT_LUMINANCE_ALPHA_UINT32] = 0,
+      [MESA_FORMAT_LUMINANCE_ALPHA_INT8] = 0,
+      [MESA_FORMAT_LUMINANCE_ALPHA_INT16] = 0,
+      [MESA_FORMAT_LUMINANCE_ALPHA_INT32] = 0,
+
+      [MESA_FORMAT_R_INT8] = BRW_SURFACEFORMAT_R8_SINT,
+      [MESA_FORMAT_RG_INT8] = BRW_SURFACEFORMAT_R8G8_SINT,
+      [MESA_FORMAT_RGB_INT8] = 0,
+      [MESA_FORMAT_RGBA_INT8] = BRW_SURFACEFORMAT_R8G8B8A8_SINT,
+      [MESA_FORMAT_R_INT16] = BRW_SURFACEFORMAT_R16_SINT,
+      [MESA_FORMAT_RG_INT16] = BRW_SURFACEFORMAT_R16G16_SINT,
+      [MESA_FORMAT_RGB_INT16] = 0,
+      [MESA_FORMAT_RGBA_INT16] = BRW_SURFACEFORMAT_R16G16B16A16_SINT,
+      [MESA_FORMAT_R_INT32] = BRW_SURFACEFORMAT_R32_SINT,
+      [MESA_FORMAT_RG_INT32] = BRW_SURFACEFORMAT_R32G32_SINT,
+      [MESA_FORMAT_RGB_INT32] = BRW_SURFACEFORMAT_R32G32B32_SINT,
+      [MESA_FORMAT_RGBA_INT32] = BRW_SURFACEFORMAT_R32G32B32A32_SINT,
+
+      [MESA_FORMAT_R_UINT8] = BRW_SURFACEFORMAT_R8_UINT,
+      [MESA_FORMAT_RG_UINT8] = BRW_SURFACEFORMAT_R8G8_UINT,
+      [MESA_FORMAT_RGB_UINT8] = 0,
+      [MESA_FORMAT_RGBA_UINT8] = BRW_SURFACEFORMAT_R8G8B8A8_UINT,
+      [MESA_FORMAT_R_UINT16] = BRW_SURFACEFORMAT_R16_UINT,
+      [MESA_FORMAT_RG_UINT16] = BRW_SURFACEFORMAT_R16G16_UINT,
+      [MESA_FORMAT_RGB_UINT16] = 0,
+      [MESA_FORMAT_RGBA_UINT16] = BRW_SURFACEFORMAT_R16G16B16A16_UINT,
+      [MESA_FORMAT_R_UINT32] = BRW_SURFACEFORMAT_R32_UINT,
+      [MESA_FORMAT_RG_UINT32] = BRW_SURFACEFORMAT_R32G32_UINT,
+      [MESA_FORMAT_RGB_UINT32] = BRW_SURFACEFORMAT_R32G32B32_UINT,
+      [MESA_FORMAT_RGBA_UINT32] = BRW_SURFACEFORMAT_R32G32B32A32_UINT,
+
+      [MESA_FORMAT_DUDV8] = BRW_SURFACEFORMAT_R8G8_SNORM,
+      [MESA_FORMAT_SIGNED_R8] = BRW_SURFACEFORMAT_R8_SNORM,
+      [MESA_FORMAT_SIGNED_RG88_REV] = BRW_SURFACEFORMAT_R8G8_SNORM,
+      [MESA_FORMAT_SIGNED_RGBX8888] = 0,
+      [MESA_FORMAT_SIGNED_RGBA8888] = 0,
+      [MESA_FORMAT_SIGNED_RGBA8888_REV] = BRW_SURFACEFORMAT_R8G8B8A8_SNORM,
+      [MESA_FORMAT_SIGNED_R16] = BRW_SURFACEFORMAT_R16_SNORM,
+      [MESA_FORMAT_SIGNED_GR1616] = BRW_SURFACEFORMAT_R16G16_SNORM,
+      [MESA_FORMAT_SIGNED_RGB_16] = 0,
+      [MESA_FORMAT_SIGNED_RGBA_16] = 0,
+      [MESA_FORMAT_RGBA_16] = BRW_SURFACEFORMAT_R16G16B16A16_UNORM,
+
+      [MESA_FORMAT_RED_RGTC1] = BRW_SURFACEFORMAT_BC4_UNORM,
+      [MESA_FORMAT_SIGNED_RED_RGTC1] = BRW_SURFACEFORMAT_BC4_SNORM,
+      [MESA_FORMAT_RG_RGTC2] = BRW_SURFACEFORMAT_BC5_UNORM,
+      [MESA_FORMAT_SIGNED_RG_RGTC2] = BRW_SURFACEFORMAT_BC5_SNORM,
+
+      [MESA_FORMAT_L_LATC1] = 0,
+      [MESA_FORMAT_SIGNED_L_LATC1] = 0,
+      [MESA_FORMAT_LA_LATC2] = 0,
+      [MESA_FORMAT_SIGNED_LA_LATC2] = 0,
+
+      [MESA_FORMAT_SIGNED_A8] = 0,
+      [MESA_FORMAT_SIGNED_L8] = 0,
+      [MESA_FORMAT_SIGNED_AL88] = 0,
+      [MESA_FORMAT_SIGNED_I8] = 0,
+      [MESA_FORMAT_SIGNED_A16] = 0,
+      [MESA_FORMAT_SIGNED_L16] = 0,
+      [MESA_FORMAT_SIGNED_AL1616] = 0,
+      [MESA_FORMAT_SIGNED_I16] = 0,
+
+      [MESA_FORMAT_RGB9_E5_FLOAT] = BRW_SURFACEFORMAT_R9G9B9E5_SHAREDEXP,
+      [MESA_FORMAT_R11_G11_B10_FLOAT] = BRW_SURFACEFORMAT_R11G11B10_FLOAT,
+
+      [MESA_FORMAT_Z32_FLOAT] = 0,
+      [MESA_FORMAT_Z32_FLOAT_X24S8] = 0,
+   };
+   assert(mesa_format < MESA_FORMAT_COUNT);
+   return table[mesa_format];
+}
+
+void
+brw_init_surface_formats(struct brw_context *brw)
+{
+   struct intel_context *intel = &brw->intel;
+   struct gl_context *ctx = &intel->ctx;
+   int gen;
+   gl_format format;
+
+   gen = intel->gen * 10;
+   if (intel->is_g4x)
+      gen += 5;
+
+   for (format = MESA_FORMAT_NONE + 1; format < MESA_FORMAT_COUNT; format++) {
+      uint32_t texture, render;
+      const struct surface_format_info *rinfo, *tinfo;
+      bool is_integer = _mesa_is_format_integer_color(format);
+
+      render = texture = brw_format_for_mesa_format(format);
+      tinfo = &surface_formats[texture];
+
+      /* The value of BRW_SURFACEFORMAT_R32G32B32A32_FLOAT is 0, so don't skip
+       * it.
+       */
+      if (texture == 0 && format != MESA_FORMAT_RGBA_FLOAT32)
+        continue;
+
+      if (gen >= tinfo->sampling && (gen >= tinfo->filtering || is_integer))
+        ctx->TextureFormatSupported[format] = true;
+
+      /* Re-map some render target formats to make them supported when they
+       * wouldn't be using their format for texturing.
+       */
+      switch (render) {
+        /* For these formats, we just need to read/write the first
+         * channel into R, which is to say that we just treat them as
+         * GL_RED.
+         */
+      case BRW_SURFACEFORMAT_I32_FLOAT:
+      case BRW_SURFACEFORMAT_L32_FLOAT:
+        render = BRW_SURFACEFORMAT_R32_FLOAT;
+        break;
+      case BRW_SURFACEFORMAT_I16_FLOAT:
+      case BRW_SURFACEFORMAT_L16_FLOAT:
+        render = BRW_SURFACEFORMAT_R16_FLOAT;
+        break;
+      case BRW_SURFACEFORMAT_B8G8R8X8_UNORM:
+        /* XRGB is handled as ARGB because the chips in this family
+         * cannot render to XRGB targets.  This means that we have to
+         * mask writes to alpha (ala glColorMask) and reconfigure the
+         * alpha blending hardware to use GL_ONE (or GL_ZERO) for
+         * cases where GL_DST_ALPHA (or GL_ONE_MINUS_DST_ALPHA) is
+         * used.
+         */
+        render = BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+        break;
+      }
+
+      rinfo = &surface_formats[render];
+
+      /* Note that GL_EXT_texture_integer says that blending doesn't occur for
+       * integer, so we don't need hardware support for blending on it.  Other
+       * than that, GL in general requires alpha blending for render targets,
+       * even though we don't support it for some formats.
+       *
+       * We don't currently support rendering to SNORM textures because some of
+       * the ARB_color_buffer_float clamping is broken for it
+       * (piglit arb_color_buffer_float-drawpixels GL_RGBA8_SNORM).
+       */
+      if (gen >= rinfo->render_target &&
+         (gen >= rinfo->alpha_blend || is_integer) &&
+         _mesa_get_format_datatype(format) != GL_SIGNED_NORMALIZED) {
+        brw->render_target_format[format] = render;
+        brw->format_supported_as_render_target[format] = true;
+      }
+   }
+
+   /* We will check this table for FBO completeness, but the surface format
+    * table above only covered color rendering.
+    */
+   brw->format_supported_as_render_target[MESA_FORMAT_S8_Z24] = true;
+   brw->format_supported_as_render_target[MESA_FORMAT_X8_Z24] = true;
+   brw->format_supported_as_render_target[MESA_FORMAT_S8] = true;
+   brw->format_supported_as_render_target[MESA_FORMAT_Z16] = true;
+   brw->format_supported_as_render_target[MESA_FORMAT_Z32_FLOAT] = true;
+   brw->format_supported_as_render_target[MESA_FORMAT_Z32_FLOAT_X24S8] = true;
+
+   /* We remap depth formats to a supported texturing format in
+    * translate_tex_format().
+    */
+   ctx->TextureFormatSupported[MESA_FORMAT_S8_Z24] = true;
+   ctx->TextureFormatSupported[MESA_FORMAT_X8_Z24] = true;
+   ctx->TextureFormatSupported[MESA_FORMAT_Z32_FLOAT] = true;
+   ctx->TextureFormatSupported[MESA_FORMAT_Z32_FLOAT_X24S8] = true;
+}
+
+bool
+brw_render_target_supported(struct intel_context *intel, gl_format format)
+{
+   struct brw_context *brw = brw_context(&intel->ctx);
+   /* Not exactly true, as some of those formats are not renderable.
+    * But at least we know how to translate them.
+    */
+   return brw->format_supported_as_render_target[format];
+}
+
+GLuint
+translate_tex_format(gl_format mesa_format,
+                    GLenum internal_format,
+                    GLenum depth_mode,
+                    GLenum srgb_decode)
 {
    switch( mesa_format ) {
 
    case MESA_FORMAT_Z16:
-      if (depth_mode == GL_INTENSITY) 
-         return BRW_SURFACEFORMAT_I16_UNORM;
-      else if (depth_mode == GL_ALPHA)
-         return BRW_SURFACEFORMAT_A16_UNORM;
-      else if (depth_mode == GL_RED)
-         return BRW_SURFACEFORMAT_R16_UNORM;
-      else
-         return BRW_SURFACEFORMAT_L16_UNORM;
+      return BRW_SURFACEFORMAT_I16_UNORM;
 
    case MESA_FORMAT_S8_Z24:
-      /* XXX: these different surface formats don't seem to
-       * make any difference for shadow sampler/compares.
+   case MESA_FORMAT_X8_Z24:
+      return BRW_SURFACEFORMAT_I24X8_UNORM;
+
+   case MESA_FORMAT_Z32_FLOAT:
+      return BRW_SURFACEFORMAT_I32_FLOAT;
+
+   case MESA_FORMAT_Z32_FLOAT_X24S8:
+      return BRW_SURFACEFORMAT_R32G32_FLOAT;
+
+   case MESA_FORMAT_SARGB8:
+   case MESA_FORMAT_SLA8:
+   case MESA_FORMAT_SL8:
+      if (srgb_decode == GL_DECODE_EXT)
+        return brw_format_for_mesa_format(mesa_format);
+      else if (srgb_decode == GL_SKIP_DECODE_EXT)
+        return brw_format_for_mesa_format(_mesa_get_srgb_format_linear(mesa_format));
+
+   case MESA_FORMAT_RGBA8888_REV:
+      /* This format is not renderable? */
+      return BRW_SURFACEFORMAT_R8G8B8A8_UNORM;
+
+   case MESA_FORMAT_RGBA_FLOAT32:
+      /* The value of this BRW_SURFACEFORMAT is 0, which tricks the
+       * assertion below.
        */
-      if (depth_mode == GL_INTENSITY) 
-         return BRW_SURFACEFORMAT_I24X8_UNORM;
-      else if (depth_mode == GL_ALPHA)
-         return BRW_SURFACEFORMAT_A24X8_UNORM;
-      else if (depth_mode == GL_RED)
-         return BRW_SURFACEFORMAT_R24_UNORM_X8_TYPELESS;
-      else
-         return BRW_SURFACEFORMAT_L24X8_UNORM;
+      return BRW_SURFACEFORMAT_R32G32B32A32_FLOAT;
 
    default:
-      assert(brw_format_for_mesa_format[mesa_format] != 0);
-      return brw_format_for_mesa_format[mesa_format];
+      assert(brw_format_for_mesa_format(mesa_format) != 0);
+      return brw_format_for_mesa_format(mesa_format);
    }
 }
 
-static void
-brw_set_surface_tiling(struct brw_surface_state *surf, uint32_t tiling)
+static uint32_t
+brw_get_surface_tiling_bits(uint32_t tiling)
 {
    switch (tiling) {
-   case I915_TILING_NONE:
-      surf->ss3.tiled_surface = 0;
-      surf->ss3.tile_walk = 0;
-      break;
    case I915_TILING_X:
-      surf->ss3.tiled_surface = 1;
-      surf->ss3.tile_walk = BRW_TILEWALK_XMAJOR;
-      break;
+      return BRW_SURFACE_TILED;
    case I915_TILING_Y:
-      surf->ss3.tiled_surface = 1;
-      surf->ss3.tile_walk = BRW_TILEWALK_YMAJOR;
-      break;
+      return BRW_SURFACE_TILED | BRW_SURFACE_TILED_Y;
+   default:
+      return 0;
    }
 }
 
@@ -163,52 +629,46 @@ brw_update_texture_surface( struct gl_context *ctx, GLuint unit )
    struct brw_context *brw = brw_context(ctx);
    struct gl_texture_object *tObj = ctx->Texture.Unit[unit]._Current;
    struct intel_texture_object *intelObj = intel_texture_object(tObj);
+   struct intel_mipmap_tree *mt = intelObj->mt;
    struct gl_texture_image *firstImage = tObj->Image[0][tObj->BaseLevel];
+   struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit);
    const GLuint surf_index = SURF_INDEX_TEXTURE(unit);
-   struct brw_surface_state surf;
-   void *map;
+   uint32_t *surf;
+   int width, height, depth;
 
-   memset(&surf, 0, sizeof(surf));
+   intel_miptree_get_dimensions_for_image(firstImage, &width, &height, &depth);
 
-   surf.ss0.mipmap_layout_mode = BRW_SURFACE_MIPMAPLAYOUT_BELOW;
-   surf.ss0.surface_type = translate_tex_target(tObj->Target);
-   surf.ss0.surface_format = translate_tex_format(firstImage->TexFormat,
-                                                 firstImage->InternalFormat,
-                                                 tObj->DepthMode);
+   surf = brw_state_batch(brw, AUB_TRACE_SURFACE_STATE,
+                         6 * 4, 32, &brw->bind.surf_offset[surf_index]);
 
-   /* This is ok for all textures with channel width 8bit or less:
-    */
-/*    surf.ss0.data_return_format = BRW_SURFACERETURNFORMAT_S1; */
-   surf.ss1.base_addr = intelObj->mt->region->buffer->offset; /* reloc */
+   surf[0] = (translate_tex_target(tObj->Target) << BRW_SURFACE_TYPE_SHIFT |
+             BRW_SURFACE_MIPMAPLAYOUT_BELOW << BRW_SURFACE_MIPLAYOUT_SHIFT |
+             BRW_SURFACE_CUBEFACE_ENABLES |
+             (translate_tex_format(mt->format,
+                                   firstImage->InternalFormat,
+                                   sampler->DepthMode,
+                                   sampler->sRGBDecode) <<
+              BRW_SURFACE_FORMAT_SHIFT));
 
-   surf.ss2.mip_count = intelObj->_MaxLevel - tObj->BaseLevel;
-   surf.ss2.width = firstImage->Width - 1;
-   surf.ss2.height = firstImage->Height - 1;
-   brw_set_surface_tiling(&surf, intelObj->mt->region->tiling);
-   surf.ss3.pitch = (intelObj->mt->region->pitch * intelObj->mt->cpp) - 1;
-   surf.ss3.depth = firstImage->Depth - 1;
+   surf[1] = intelObj->mt->region->bo->offset; /* reloc */
 
-   surf.ss4.min_lod = 0;
-   if (tObj->Target == GL_TEXTURE_CUBE_MAP) {
-      surf.ss0.cube_pos_x = 1;
-      surf.ss0.cube_pos_y = 1;
-      surf.ss0.cube_pos_z = 1;
-      surf.ss0.cube_neg_x = 1;
-      surf.ss0.cube_neg_y = 1;
-      surf.ss0.cube_neg_z = 1;
-   }
+   surf[2] = ((intelObj->_MaxLevel - tObj->BaseLevel) << BRW_SURFACE_LOD_SHIFT |
+             (width - 1) << BRW_SURFACE_WIDTH_SHIFT |
+             (height - 1) << BRW_SURFACE_HEIGHT_SHIFT);
+
+   surf[3] = (brw_get_surface_tiling_bits(intelObj->mt->region->tiling) |
+             (depth - 1) << BRW_SURFACE_DEPTH_SHIFT |
+             ((intelObj->mt->region->pitch * intelObj->mt->cpp) - 1) <<
+             BRW_SURFACE_PITCH_SHIFT);
 
-   map = brw_state_batch(brw, sizeof(surf), 32,
-                        &brw->wm.surf_bo[surf_index],
-                        &brw->wm.surf_offset[surf_index]);
-   memcpy(map, &surf, sizeof(surf));
+   surf[4] = 0;
+
+   surf[5] = (mt->align_h == 4) ? BRW_SURFACE_VERTICAL_ALIGN_ENABLE : 0;
 
    /* Emit relocation to surface contents */
-   drm_intel_bo_emit_reloc(brw->wm.surf_bo[surf_index],
-                          brw->wm.surf_offset[surf_index] +
-                          offsetof(struct brw_surface_state, ss1),
-                          intelObj->mt->region->buffer, 0,
+   drm_intel_bo_emit_reloc(brw->intel.batch.bo,
+                          brw->bind.surf_offset[surf_index] + 4,
+                          intelObj->mt->region->bo, 0,
                           I915_GEM_DOMAIN_SAMPLER, 0);
 }
 
@@ -220,45 +680,127 @@ void
 brw_create_constant_surface(struct brw_context *brw,
                            drm_intel_bo *bo,
                            int width,
-                           drm_intel_bo **out_bo,
                            uint32_t *out_offset)
 {
    struct intel_context *intel = &brw->intel;
    const GLint w = width - 1;
-   struct brw_surface_state surf;
-   void *map;
+   uint32_t *surf;
 
-   memset(&surf, 0, sizeof(surf));
+   surf = brw_state_batch(brw, AUB_TRACE_SURFACE_STATE,
+                         6 * 4, 32, out_offset);
 
-   surf.ss0.mipmap_layout_mode = BRW_SURFACE_MIPMAPLAYOUT_BELOW;
-   surf.ss0.surface_type = BRW_SURFACE_BUFFER;
-   surf.ss0.surface_format = BRW_SURFACEFORMAT_R32G32B32A32_FLOAT;
+   surf[0] = (BRW_SURFACE_BUFFER << BRW_SURFACE_TYPE_SHIFT |
+             BRW_SURFACE_MIPMAPLAYOUT_BELOW << BRW_SURFACE_MIPLAYOUT_SHIFT |
+             BRW_SURFACEFORMAT_R32G32B32A32_FLOAT << BRW_SURFACE_FORMAT_SHIFT);
 
    if (intel->gen >= 6)
-      surf.ss0.render_cache_read_write = 1;
+      surf[0] |= BRW_SURFACE_RC_READ_WRITE;
+
+   surf[1] = bo->offset; /* reloc */
 
-   assert(bo);
-   surf.ss1.base_addr = bo->offset; /* reloc */
+   surf[2] = (((w & 0x7f) - 1) << BRW_SURFACE_WIDTH_SHIFT |
+             (((w >> 7) & 0x1fff) - 1) << BRW_SURFACE_HEIGHT_SHIFT);
 
-   surf.ss2.width = w & 0x7f;            /* bits 6:0 of size or width */
-   surf.ss2.height = (w >> 7) & 0x1fff;  /* bits 19:7 of size or width */
-   surf.ss3.depth = (w >> 20) & 0x7f;    /* bits 26:20 of size or width */
-   surf.ss3.pitch = (width * 16) - 1; /* ignored?? */
-   brw_set_surface_tiling(&surf, I915_TILING_NONE); /* tiling now allowed */
+   surf[3] = ((((w >> 20) & 0x7f) - 1) << BRW_SURFACE_DEPTH_SHIFT |
+             (width * 16 - 1) << BRW_SURFACE_PITCH_SHIFT);
 
-   map = brw_state_batch(brw, sizeof(surf), 32, out_bo, out_offset);
-   memcpy(map, &surf, sizeof(surf));
+   surf[4] = 0;
+   surf[5] = 0;
 
    /* Emit relocation to surface contents.  Section 5.1.1 of the gen4
     * bspec ("Data Cache") says that the data cache does not exist as
     * a separate cache and is just the sampler cache.
     */
-   drm_intel_bo_emit_reloc(*out_bo, (*out_offset +
-                                    offsetof(struct brw_surface_state, ss1)),
+   drm_intel_bo_emit_reloc(brw->intel.batch.bo,
+                          *out_offset + 4,
                           bo, 0,
                           I915_GEM_DOMAIN_SAMPLER, 0);
 }
 
+/**
+ * Set up a binding table entry for use by stream output logic (transform
+ * feedback).
+ *
+ * buffer_size_minus_1 must me less than BRW_MAX_NUM_BUFFER_ENTRIES.
+ */
+void
+brw_update_sol_surface(struct brw_context *brw,
+                       struct gl_buffer_object *buffer_obj,
+                       uint32_t *out_offset, unsigned num_vector_components,
+                       unsigned stride_dwords, unsigned offset_dwords)
+{
+   drm_intel_bo *bo = intel_buffer_object(buffer_obj)->buffer;
+   uint32_t *surf = brw_state_batch(brw, AUB_TRACE_SURFACE_STATE, 6 * 4, 32,
+                                    out_offset);
+   uint32_t pitch_minus_1 = 4*stride_dwords - 1;
+   uint32_t offset_bytes = 4 * offset_dwords;
+   size_t size_dwords = buffer_obj->Size / 4;
+   uint32_t buffer_size_minus_1, width, height, depth, surface_format;
+
+   /* FIXME: can we rely on core Mesa to ensure that the buffer isn't
+    * too big to map using a single binding table entry?
+    */
+   assert((size_dwords - offset_dwords) / stride_dwords
+          <= BRW_MAX_NUM_BUFFER_ENTRIES);
+
+   if (size_dwords > offset_dwords + num_vector_components) {
+      /* There is room for at least 1 transform feedback output in the buffer.
+       * Compute the number of additional transform feedback outputs the
+       * buffer has room for.
+       */
+      buffer_size_minus_1 =
+         (size_dwords - offset_dwords - num_vector_components) / stride_dwords;
+   } else {
+      /* There isn't even room for a single transform feedback output in the
+       * buffer.  We can't configure the binding table entry to prevent output
+       * entirely; we'll have to rely on the geometry shader to detect
+       * overflow.  But to minimize the damage in case of a bug, set up the
+       * binding table entry to just allow a single output.
+       */
+      buffer_size_minus_1 = 0;
+   }
+   width = buffer_size_minus_1 & 0x7f;
+   height = (buffer_size_minus_1 & 0xfff80) >> 7;
+   depth = (buffer_size_minus_1 & 0x7f00000) >> 20;
+
+   switch (num_vector_components) {
+   case 1:
+      surface_format = BRW_SURFACEFORMAT_R32_FLOAT;
+      break;
+   case 2:
+      surface_format = BRW_SURFACEFORMAT_R32G32_FLOAT;
+      break;
+   case 3:
+      surface_format = BRW_SURFACEFORMAT_R32G32B32_FLOAT;
+      break;
+   case 4:
+      surface_format = BRW_SURFACEFORMAT_R32G32B32A32_FLOAT;
+      break;
+   default:
+      assert(!"Invalid vector size for transform feedback output");
+      surface_format = BRW_SURFACEFORMAT_R32_FLOAT;
+      break;
+   }
+
+   surf[0] = BRW_SURFACE_BUFFER << BRW_SURFACE_TYPE_SHIFT |
+      BRW_SURFACE_MIPMAPLAYOUT_BELOW << BRW_SURFACE_MIPLAYOUT_SHIFT |
+      surface_format << BRW_SURFACE_FORMAT_SHIFT |
+      BRW_SURFACE_RC_READ_WRITE;
+   surf[1] = bo->offset + offset_bytes; /* reloc */
+   surf[2] = (width << BRW_SURFACE_WIDTH_SHIFT |
+             height << BRW_SURFACE_HEIGHT_SHIFT);
+   surf[3] = (depth << BRW_SURFACE_DEPTH_SHIFT |
+              pitch_minus_1 << BRW_SURFACE_PITCH_SHIFT);
+   surf[4] = 0;
+   surf[5] = 0;
+
+   /* Emit relocation to surface contents. */
+   drm_intel_bo_emit_reloc(brw->intel.batch.bo,
+                          *out_offset + 4,
+                          bo, offset_bytes,
+                          I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+}
+
 /* Creates a new WM constant buffer reflecting the current fragment program's
  * constants, if needed by the fragment program.
  *
@@ -266,24 +808,28 @@ brw_create_constant_surface(struct brw_context *brw,
  * state atom.
  */
 static void
-prepare_wm_constants(struct brw_context *brw)
+brw_upload_wm_pull_constants(struct brw_context *brw)
 {
    struct gl_context *ctx = &brw->intel.ctx;
    struct intel_context *intel = &brw->intel;
+   /* BRW_NEW_FRAGMENT_PROGRAM */
    struct brw_fragment_program *fp =
       (struct brw_fragment_program *) brw->fragment_program;
+   struct gl_program_parameter_list *params = fp->program.Base.Parameters;
    const int size = brw->wm.prog_data->nr_pull_params * sizeof(float);
+   const int surf_index = SURF_INDEX_FRAG_CONST_BUFFER;
    float *constants;
    unsigned int i;
 
-   _mesa_load_state_parameters(ctx, fp->program.Base.Parameters);
+   _mesa_load_state_parameters(ctx, params);
 
-   /* BRW_NEW_FRAGMENT_PROGRAM */
+   /* CACHE_NEW_WM_PROG */
    if (brw->wm.prog_data->nr_pull_params == 0) {
       if (brw->wm.const_bo) {
         drm_intel_bo_unreference(brw->wm.const_bo);
         brw->wm.const_bo = NULL;
-        brw->state.dirty.brw |= BRW_NEW_WM_CONSTBUF;
+        brw->bind.surf_offset[surf_index] = 0;
+        brw->state.dirty.brw |= BRW_NEW_SURFACES;
       }
       return;
    }
@@ -297,97 +843,48 @@ prepare_wm_constants(struct brw_context *brw)
    constants = brw->wm.const_bo->virtual;
    for (i = 0; i < brw->wm.prog_data->nr_pull_params; i++) {
       constants[i] = convert_param(brw->wm.prog_data->pull_param_convert[i],
-                                  *brw->wm.prog_data->pull_param[i]);
+                                  brw->wm.prog_data->pull_param[i]);
    }
    drm_intel_gem_bo_unmap_gtt(brw->wm.const_bo);
 
-   brw->state.dirty.brw |= BRW_NEW_WM_CONSTBUF;
-}
+   intel->vtbl.create_constant_surface(brw, brw->wm.const_bo,
+                                      params->NumParameters,
+                                      &brw->bind.surf_offset[surf_index]);
 
-const struct brw_tracked_state brw_wm_constants = {
-   .dirty = {
-      .mesa = (_NEW_PROGRAM_CONSTANTS),
-      .brw = (BRW_NEW_FRAGMENT_PROGRAM),
-      .cache = 0
-   },
-   .prepare = prepare_wm_constants,
-};
-
-/**
- * Updates surface / buffer for fragment shader constant buffer, if
- * one is required.
- *
- * This consumes the state updates for the constant buffer, and produces
- * BRW_NEW_WM_SURFACES to get picked up by brw_prepare_wm_surfaces for
- * inclusion in the binding table.
- */
-static void upload_wm_constant_surface(struct brw_context *brw )
-{
-   GLuint surf = SURF_INDEX_FRAG_CONST_BUFFER;
-   struct brw_fragment_program *fp =
-      (struct brw_fragment_program *) brw->fragment_program;
-   const struct gl_program_parameter_list *params =
-      fp->program.Base.Parameters;
-
-   /* If there's no constant buffer, then no surface BO is needed to point at
-    * it.
-    */
-   if (brw->wm.const_bo == 0) {
-      if (brw->wm.surf_bo[surf] != NULL) {
-        drm_intel_bo_unreference(brw->wm.surf_bo[surf]);
-        brw->wm.surf_bo[surf] = NULL;
-        brw->state.dirty.brw |= BRW_NEW_WM_SURFACES;
-      }
-      return;
-   }
-
-   brw_create_constant_surface(brw, brw->wm.const_bo, params->NumParameters,
-                              &brw->wm.surf_bo[surf],
-                              &brw->wm.surf_offset[surf]);
-   brw->state.dirty.brw |= BRW_NEW_WM_SURFACES;
+   brw->state.dirty.brw |= BRW_NEW_SURFACES;
 }
 
-const struct brw_tracked_state brw_wm_constant_surface = {
+const struct brw_tracked_state brw_wm_pull_constants = {
    .dirty = {
-      .mesa = 0,
-      .brw = (BRW_NEW_WM_CONSTBUF |
-             BRW_NEW_BATCH),
-      .cache = 0
+      .mesa = (_NEW_PROGRAM_CONSTANTS),
+      .brw = (BRW_NEW_BATCH | BRW_NEW_FRAGMENT_PROGRAM),
+      .cache = CACHE_NEW_WM_PROG,
    },
-   .emit = upload_wm_constant_surface,
+   .emit = brw_upload_wm_pull_constants,
 };
 
 static void
 brw_update_null_renderbuffer_surface(struct brw_context *brw, unsigned int unit)
 {
    struct intel_context *intel = &brw->intel;
-   struct brw_surface_state surf;
-   void *map;
-
-   memset(&surf, 0, sizeof(surf));
+   uint32_t *surf;
 
-   surf.ss0.surface_type = BRW_SURFACE_NULL;
-   surf.ss0.surface_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
-   surf.ss1.base_addr = 0;
-
-   surf.ss2.width = 0;
-   surf.ss2.height = 0;
-   brw_set_surface_tiling(&surf, I915_TILING_NONE);
-   surf.ss3.pitch = 0;
+   surf = brw_state_batch(brw, AUB_TRACE_SURFACE_STATE,
+                         6 * 4, 32, &brw->bind.surf_offset[unit]);
 
+   surf[0] = (BRW_SURFACE_NULL << BRW_SURFACE_TYPE_SHIFT |
+             BRW_SURFACEFORMAT_B8G8R8A8_UNORM << BRW_SURFACE_FORMAT_SHIFT);
    if (intel->gen < 6) {
-      /* _NEW_COLOR */
-      surf.ss0.color_blend = 0;
-      surf.ss0.writedisable_red =   1;
-      surf.ss0.writedisable_green = 1;
-      surf.ss0.writedisable_blue =  1;
-      surf.ss0.writedisable_alpha = 1;
+      surf[0] |= (1 << BRW_SURFACE_WRITEDISABLE_R_SHIFT |
+                 1 << BRW_SURFACE_WRITEDISABLE_G_SHIFT |
+                 1 << BRW_SURFACE_WRITEDISABLE_B_SHIFT |
+                 1 << BRW_SURFACE_WRITEDISABLE_A_SHIFT);
    }
-
-   map = brw_state_batch(brw, sizeof(surf), 32,
-                        &brw->wm.surf_bo[unit],
-                        &brw->wm.surf_offset[unit]);
-   memcpy(map, &surf, sizeof(surf));
+   surf[1] = 0;
+   surf[2] = 0;
+   surf[3] = 0;
+   surf[4] = 0;
+   surf[5] = 0;
 }
 
 /**
@@ -403,145 +900,95 @@ brw_update_renderbuffer_surface(struct brw_context *brw,
    struct intel_context *intel = &brw->intel;
    struct gl_context *ctx = &intel->ctx;
    struct intel_renderbuffer *irb = intel_renderbuffer(rb);
-   struct intel_region *region = irb->region;
-   struct brw_surface_state surf;
-   void *map;
+   struct intel_mipmap_tree *mt = irb->mt;
+   struct intel_region *region = irb->mt->region;
+   uint32_t *surf;
+   uint32_t tile_x, tile_y;
+   uint32_t format = 0;
 
-   memset(&surf, 0, sizeof(surf));
+   surf = brw_state_batch(brw, AUB_TRACE_SURFACE_STATE,
+                         6 * 4, 32, &brw->bind.surf_offset[unit]);
 
    switch (irb->Base.Format) {
-   case MESA_FORMAT_XRGB8888:
-      /* XRGB is handled as ARGB because the chips in this family
-       * cannot render to XRGB targets.  This means that we have to
-       * mask writes to alpha (ala glColorMask) and reconfigure the
-       * alpha blending hardware to use GL_ONE (or GL_ZERO) for
-       * cases where GL_DST_ALPHA (or GL_ONE_MINUS_DST_ALPHA) is
-       * used.
-       */
-      surf.ss0.surface_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+   case MESA_FORMAT_SARGB8:
+      /* without GL_EXT_framebuffer_sRGB we shouldn't bind sRGB
+        surfaces to the blend/update as sRGB */
+      if (ctx->Color.sRGBEnabled)
+        format = brw_format_for_mesa_format(irb->Base.Format);
+      else
+        format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
       break;
    default:
-      surf.ss0.surface_format = brw_format_for_mesa_format[irb->Base.Format];
-      assert(surf.ss0.surface_format != 0);
-   }
-
-   surf.ss0.surface_type = BRW_SURFACE_2D;
-   if (region->tiling == I915_TILING_NONE) {
-      surf.ss1.base_addr = (region->draw_x +
-                           region->draw_y * region->pitch) * region->cpp;
-   } else {
-      uint32_t tile_base, tile_x, tile_y;
-      uint32_t pitch = region->pitch * region->cpp;
-
-      if (region->tiling == I915_TILING_X) {
-        tile_x = region->draw_x % (512 / region->cpp);
-        tile_y = region->draw_y % 8;
-        tile_base = ((region->draw_y / 8) * (8 * pitch));
-        tile_base += (region->draw_x - tile_x) / (512 / region->cpp) * 4096;
-      } else {
-        /* Y */
-        tile_x = region->draw_x % (128 / region->cpp);
-        tile_y = region->draw_y % 32;
-        tile_base = ((region->draw_y / 32) * (32 * pitch));
-        tile_base += (region->draw_x - tile_x) / (128 / region->cpp) * 4096;
+      format = brw->render_target_format[irb->Base.Format];
+      if (unlikely(!brw->format_supported_as_render_target[irb->Base.Format])) {
+        _mesa_problem(ctx, "%s: renderbuffer format %s unsupported\n",
+                      __FUNCTION__, _mesa_get_format_name(irb->Base.Format));
       }
-      assert(brw->has_surface_tile_offset || (tile_x == 0 && tile_y == 0));
-      assert(tile_x % 4 == 0);
-      assert(tile_y % 2 == 0);
-      /* Note that the low bits of these fields are missing, so
-       * there's the possibility of getting in trouble.
-       */
-      surf.ss1.base_addr = tile_base;
-      surf.ss5.x_offset = tile_x / 4;
-      surf.ss5.y_offset = tile_y / 2;
+      break;
    }
-   surf.ss1.base_addr += region->buffer->offset; /* reloc */
 
-   surf.ss2.width = rb->Width - 1;
-   surf.ss2.height = rb->Height - 1;
-   brw_set_surface_tiling(&surf, region->tiling);
-   surf.ss3.pitch = (region->pitch * region->cpp) - 1;
-
-   if (intel->gen < 6) {
-      /* _NEW_COLOR */
-      surf.ss0.color_blend = (!ctx->Color._LogicOpEnabled &&
-                             (ctx->Color.BlendEnabled & (1 << unit)));
-      surf.ss0.writedisable_red =   !ctx->Color.ColorMask[unit][0];
-      surf.ss0.writedisable_green = !ctx->Color.ColorMask[unit][1];
-      surf.ss0.writedisable_blue =  !ctx->Color.ColorMask[unit][2];
-      /* As mentioned above, disable writes to the alpha component when the
-       * renderbuffer is XRGB.
-       */
-      if (ctx->DrawBuffer->Visual.alphaBits == 0)
-        surf.ss0.writedisable_alpha = 1;
-      else
-        surf.ss0.writedisable_alpha = !ctx->Color.ColorMask[unit][3];
-   }
+   surf[0] = (BRW_SURFACE_2D << BRW_SURFACE_TYPE_SHIFT |
+             format << BRW_SURFACE_FORMAT_SHIFT);
 
-   map = brw_state_batch(brw, sizeof(surf), 32,
-                        &brw->wm.surf_bo[unit],
-                        &brw->wm.surf_offset[unit]);
-   memcpy(map, &surf, sizeof(surf));
+   /* reloc */
+   surf[1] = (intel_renderbuffer_tile_offsets(irb, &tile_x, &tile_y) +
+             region->bo->offset);
 
-   drm_intel_bo_emit_reloc(brw->wm.surf_bo[unit],
-                          brw->wm.surf_offset[unit] +
-                          offsetof(struct brw_surface_state, ss1),
-                          region->buffer,
-                          surf.ss1.base_addr - region->buffer->offset,
-                          I915_GEM_DOMAIN_RENDER,
-                          I915_GEM_DOMAIN_RENDER);
-}
+   surf[2] = ((rb->Width - 1) << BRW_SURFACE_WIDTH_SHIFT |
+             (rb->Height - 1) << BRW_SURFACE_HEIGHT_SHIFT);
 
-static void
-prepare_wm_surfaces(struct brw_context *brw)
-{
-   struct gl_context *ctx = &brw->intel.ctx;
-   int i;
-   int nr_surfaces = 0;
+   surf[3] = (brw_get_surface_tiling_bits(region->tiling) |
+             ((region->pitch * region->cpp) - 1) << BRW_SURFACE_PITCH_SHIFT);
 
-   if (ctx->DrawBuffer->_NumColorDrawBuffers >= 1) {
-      for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
-        struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[i];
-        struct intel_renderbuffer *irb = intel_renderbuffer(rb);
-        struct intel_region *region = irb ? irb->region : NULL;
+   surf[4] = 0;
 
-        brw_add_validated_bo(brw, region->buffer);
-        nr_surfaces = SURF_INDEX_DRAW(i) + 1;
-      }
-   }
+   assert(brw->has_surface_tile_offset || (tile_x == 0 && tile_y == 0));
+   /* Note that the low bits of these fields are missing, so
+    * there's the possibility of getting in trouble.
+    */
+   assert(tile_x % 4 == 0);
+   assert(tile_y % 2 == 0);
+   surf[5] = ((tile_x / 4) << BRW_SURFACE_X_OFFSET_SHIFT |
+             (tile_y / 2) << BRW_SURFACE_Y_OFFSET_SHIFT |
+             (mt->align_h == 4 ? BRW_SURFACE_VERTICAL_ALIGN_ENABLE : 0));
 
-   if (brw->wm.const_bo) {
-      brw_add_validated_bo(brw, brw->wm.const_bo);
-      nr_surfaces = SURF_INDEX_FRAG_CONST_BUFFER + 1;
-   }
+   if (intel->gen < 6) {
+      /* _NEW_COLOR */
+      if (!ctx->Color.ColorLogicOpEnabled &&
+         (ctx->Color.BlendEnabled & (1 << unit)))
+        surf[0] |= BRW_SURFACE_BLEND_ENABLED;
 
-   for (i = 0; i < BRW_MAX_TEX_UNIT; i++) {
-      const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
-      struct gl_texture_object *tObj = texUnit->_Current;
-      struct intel_texture_object *intelObj = intel_texture_object(tObj);
+      if (!ctx->Color.ColorMask[unit][0])
+        surf[0] |= 1 << BRW_SURFACE_WRITEDISABLE_R_SHIFT;
+      if (!ctx->Color.ColorMask[unit][1])
+        surf[0] |= 1 << BRW_SURFACE_WRITEDISABLE_G_SHIFT;
+      if (!ctx->Color.ColorMask[unit][2])
+        surf[0] |= 1 << BRW_SURFACE_WRITEDISABLE_B_SHIFT;
 
-      if (texUnit->_ReallyEnabled) {
-        brw_add_validated_bo(brw, intelObj->mt->region->buffer);
-        nr_surfaces = SURF_INDEX_TEXTURE(i) + 1;
+      /* As mentioned above, disable writes to the alpha component when the
+       * renderbuffer is XRGB.
+       */
+      if (ctx->DrawBuffer->Visual.alphaBits == 0 ||
+         !ctx->Color.ColorMask[unit][3]) {
+        surf[0] |= 1 << BRW_SURFACE_WRITEDISABLE_A_SHIFT;
       }
    }
 
-   /* Have to update this in our prepare, since the unit's prepare
-    * relies on it.
-    */
-   if (brw->wm.nr_surfaces != nr_surfaces) {
-      brw->wm.nr_surfaces = nr_surfaces;
-      brw->state.dirty.brw |= BRW_NEW_NR_WM_SURFACES;
-   }
+   drm_intel_bo_emit_reloc(brw->intel.batch.bo,
+                          brw->bind.surf_offset[unit] + 4,
+                          region->bo,
+                          surf[1] - region->bo->offset,
+                          I915_GEM_DOMAIN_RENDER,
+                          I915_GEM_DOMAIN_RENDER);
 }
 
 /**
- * Constructs the set of surface state objects pointed to by the
- * binding table.
+ * Construct SURFACE_STATE objects for renderbuffers/draw buffers.
  */
 static void
-upload_wm_surfaces(struct brw_context *brw)
+brw_update_renderbuffer_surfaces(struct brw_context *brw)
 {
+   struct intel_context *intel = &brw->intel;
    struct gl_context *ctx = &brw->intel.ctx;
    GLuint i;
 
@@ -550,44 +997,66 @@ upload_wm_surfaces(struct brw_context *brw)
    if (ctx->DrawBuffer->_NumColorDrawBuffers >= 1) {
       for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
         if (intel_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[i])) {
-           brw_update_renderbuffer_surface(brw,
-                                           ctx->DrawBuffer->_ColorDrawBuffers[i],
-                                           i);
+           intel->vtbl.update_renderbuffer_surface(brw, ctx->DrawBuffer->_ColorDrawBuffers[i], i);
         } else {
-           brw_update_null_renderbuffer_surface(brw, i);
+           intel->vtbl.update_null_renderbuffer_surface(brw, i);
         }
       }
    } else {
-      brw_update_null_renderbuffer_surface(brw, 0);
+      intel->vtbl.update_null_renderbuffer_surface(brw, 0);
    }
+   brw->state.dirty.brw |= BRW_NEW_SURFACES;
+}
+
+const struct brw_tracked_state brw_renderbuffer_surfaces = {
+   .dirty = {
+      .mesa = (_NEW_COLOR |
+               _NEW_BUFFERS),
+      .brw = BRW_NEW_BATCH,
+      .cache = 0
+   },
+   .emit = brw_update_renderbuffer_surfaces,
+};
 
-   /* Update surfaces for textures */
-   for (i = 0; i < BRW_MAX_TEX_UNIT; i++) {
+const struct brw_tracked_state gen6_renderbuffer_surfaces = {
+   .dirty = {
+      .mesa = _NEW_BUFFERS,
+      .brw = BRW_NEW_BATCH,
+      .cache = 0
+   },
+   .emit = brw_update_renderbuffer_surfaces,
+};
+
+/**
+ * Construct SURFACE_STATE objects for enabled textures.
+ */
+static void
+brw_update_texture_surfaces(struct brw_context *brw)
+{
+   struct gl_context *ctx = &brw->intel.ctx;
+
+   for (unsigned i = 0; i < BRW_MAX_TEX_UNIT; i++) {
       const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
       const GLuint surf = SURF_INDEX_TEXTURE(i);
 
       /* _NEW_TEXTURE */
       if (texUnit->_ReallyEnabled) {
-        brw_update_texture_surface(ctx, i);
+        brw->intel.vtbl.update_texture_surface(ctx, i);
       } else {
-         drm_intel_bo_unreference(brw->wm.surf_bo[surf]);
-         brw->wm.surf_bo[surf] = NULL;
+         brw->bind.surf_offset[surf] = 0;
       }
    }
 
-   brw->state.dirty.brw |= BRW_NEW_WM_SURFACES;
+   brw->state.dirty.brw |= BRW_NEW_SURFACES;
 }
 
-const struct brw_tracked_state brw_wm_surfaces = {
+const struct brw_tracked_state brw_texture_surfaces = {
    .dirty = {
-      .mesa = (_NEW_COLOR |
-               _NEW_TEXTURE |
-               _NEW_BUFFERS),
-      .brw = (BRW_NEW_BATCH),
+      .mesa = _NEW_TEXTURE,
+      .brw = BRW_NEW_BATCH,
       .cache = 0
    },
-   .prepare = prepare_wm_surfaces,
-   .emit = upload_wm_surfaces,
+   .emit = brw_update_texture_surfaces,
 };
 
 /**
@@ -595,7 +1064,7 @@ const struct brw_tracked_state brw_wm_surfaces = {
  * numbers to surface state objects.
  */
 static void
-brw_wm_upload_binding_table(struct brw_context *brw)
+brw_upload_binding_table(struct brw_context *brw)
 {
    uint32_t *bind;
    int i;
@@ -603,28 +1072,38 @@ brw_wm_upload_binding_table(struct brw_context *brw)
    /* Might want to calculate nr_surfaces first, to avoid taking up so much
     * space for the binding table.
     */
-   bind = brw_state_batch(brw, sizeof(uint32_t) * BRW_WM_MAX_SURF,
-                         32, &brw->wm.bind_bo, &brw->wm.bind_bo_offset);
-
-   for (i = 0; i < BRW_WM_MAX_SURF; i++) {
-      /* BRW_NEW_WM_SURFACES */
-      bind[i] = brw->wm.surf_offset[i];
-      if (brw->wm.surf_bo[i]) {
-        bind[i] = brw->wm.surf_offset[i];
-      } else {
-        bind[i] = 0;
-      }
+   bind = brw_state_batch(brw, AUB_TRACE_BINDING_TABLE,
+                         sizeof(uint32_t) * BRW_MAX_SURFACES,
+                         32, &brw->bind.bo_offset);
+
+   /* BRW_NEW_SURFACES and BRW_NEW_VS_CONSTBUF */
+   for (i = 0; i < BRW_MAX_SURFACES; i++) {
+      bind[i] = brw->bind.surf_offset[i];
    }
 
-   brw->state.dirty.brw |= BRW_NEW_BINDING_TABLE;
+   brw->state.dirty.brw |= BRW_NEW_VS_BINDING_TABLE;
+   brw->state.dirty.brw |= BRW_NEW_PS_BINDING_TABLE;
 }
 
-const struct brw_tracked_state brw_wm_binding_table = {
+const struct brw_tracked_state brw_binding_table = {
    .dirty = {
       .mesa = 0,
       .brw = (BRW_NEW_BATCH |
-             BRW_NEW_WM_SURFACES),
+             BRW_NEW_VS_CONSTBUF |
+             BRW_NEW_SURFACES),
       .cache = 0
    },
-   .emit = brw_wm_upload_binding_table,
+   .emit = brw_upload_binding_table,
 };
+
+void
+gen4_init_vtable_surface_functions(struct brw_context *brw)
+{
+   struct intel_context *intel = &brw->intel;
+
+   intel->vtbl.update_texture_surface = brw_update_texture_surface;
+   intel->vtbl.update_renderbuffer_surface = brw_update_renderbuffer_surface;
+   intel->vtbl.update_null_renderbuffer_surface =
+      brw_update_null_renderbuffer_surface;
+   intel->vtbl.create_constant_surface = brw_create_constant_surface;
+}