i965: Update SURFACE_STATE for Ivybridge.
authorKenneth Graunke <kenneth@whitecape.org>
Thu, 28 Apr 2011 01:12:20 +0000 (18:12 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Wed, 18 May 2011 06:33:01 +0000 (23:33 -0700)
I'm still not happy with the amount of code duplication here, but it
will have to do for now.

Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
src/mesa/drivers/dri/i965/Makefile
src/mesa/drivers/dri/i965/brw_state.h
src/mesa/drivers/dri/i965/brw_state_upload.c
src/mesa/drivers/dri/i965/brw_structs.h
src/mesa/drivers/dri/i965/gen7_wm_surface_state.c [new file with mode: 0644]

index 4e80785..651f09e 100644 (file)
@@ -105,7 +105,8 @@ DRIVER_SOURCES = \
        gen7_urb.c \
        gen7_viewport_state.c \
        gen7_vs_state.c \
-       gen7_wm_state.c
+       gen7_wm_state.c \
+       gen7_wm_surface_state.c \
 
 C_SOURCES = \
        $(COMMON_SOURCES) \
index 527c280..4bf4e85 100644 (file)
@@ -128,7 +128,9 @@ extern const struct brw_tracked_state gen7_sol_state;
 extern const struct brw_tracked_state gen7_urb;
 extern const struct brw_tracked_state gen7_vs_state;
 extern const struct brw_tracked_state gen7_wm_constants;
+extern const struct brw_tracked_state gen7_wm_constant_surface;
 extern const struct brw_tracked_state gen7_wm_state;
+extern const struct brw_tracked_state gen7_wm_surfaces;
 
 /***********************************************************************
  * brw_state.c
index 73aca31..2ea2a05 100644 (file)
@@ -200,11 +200,11 @@ const struct brw_tracked_state *gen7_atoms[] =
    &brw_vs_constants, /* Before vs_surfaces and constant_buffer */
    &brw_wm_constants, /* Before wm_surfaces and constant_buffer */
    &gen6_vs_constants, /* Before vs_state */
-   &gen7_wm_constants, /* Before wm_state */
+   &gen7_wm_constants, /* Before wm_surfaces and constant_buffer */
 
    &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 */
+   &gen7_wm_constant_surface,  /* must do before wm surfaces/bind bo */
+   &gen7_wm_surfaces,          /* must do before samplers and unit */
    &brw_wm_binding_table,
 
    &brw_wm_samplers,
index 8a5619a..730e7e2 100644 (file)
@@ -1178,6 +1178,8 @@ struct gen7_sf_clip_viewport {
 };
 
 /* Documented in the subsystem/shared-functions/sampler chapter...
+ *
+ * vol5c Shared Functions - 1.13.4.1.1
  */
 struct brw_surface_state
 {
@@ -1249,6 +1251,82 @@ struct brw_surface_state
 
 };
 
+/* volume 5c Shared Functions - 1.13.4.1.2 */
+struct gen7_surface_state
+{
+   struct {
+      GLuint cube_pos_z:1;
+      GLuint cube_neg_z:1;
+      GLuint cube_pos_y:1;
+      GLuint cube_neg_y:1;
+      GLuint cube_pos_x:1;
+      GLuint cube_neg_x:1;
+      GLuint pad2:2;
+      GLuint render_cache_read_write:1;
+      GLuint pad1:1;
+      GLuint surface_array_spacing:1;
+      GLuint vert_line_stride_ofs:1;
+      GLuint vert_line_stride:1;
+      GLuint tile_walk:1;
+      GLuint tiled_surface:1;
+      GLuint horizontal_alignment:1;
+      GLuint vertical_alignment:2;
+      GLuint surface_format:9;     /**< BRW_SURFACEFORMAT_x */
+      GLuint pad0:1;
+      GLuint is_array:1;
+      GLuint surface_type:3;       /**< BRW_SURFACE_1D/2D/3D/CUBE */
+   } ss0;
+
+   struct {
+      GLuint base_addr;
+   } ss1;
+
+   struct {
+      GLuint width:14;
+      GLuint pad1:2;
+      GLuint height:14;
+      GLuint pad0:2;
+   } ss2;
+
+   struct {
+      GLuint pitch:18;
+      GLuint pad:3;
+      GLuint depth:11;
+   } ss3;
+
+   struct {
+      GLuint multisample_position_palette_index:3;
+      GLuint num_multisamples:3;
+      GLuint multisampled_surface_storage_format:1;
+      GLuint render_target_view_extent:11;
+      GLuint min_array_elt:11;
+      GLuint rotation:2;
+      GLuint pad0:1;
+   } ss4;
+
+   struct {
+      GLuint mip_count:4;
+      GLuint min_lod:4;
+      GLuint pad1:12;
+      GLuint y_offset:4;
+      GLuint pad0:1;
+      GLuint x_offset:7;
+   } ss5;
+
+   struct {
+      GLuint pad; /* Multisample Control Surface stuff */
+   } ss6;
+
+   struct {
+      GLuint resource_min_lod:12;
+      GLuint pad0:16;
+      GLuint alpha_clear_color:1;
+      GLuint blue_clear_color:1;
+      GLuint green_clear_color:1;
+      GLuint red_clear_color:1;
+   } ss7;
+};
+
 
 struct brw_vertex_element_state
 {
diff --git a/src/mesa/drivers/dri/i965/gen7_wm_surface_state.c b/src/mesa/drivers/dri/i965/gen7_wm_surface_state.c
new file mode 100644 (file)
index 0000000..ff22025
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ * Copyright © 2011 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.
+ */
+#include "main/mtypes.h"
+#include "main/samplerobj.h"
+#include "main/texstore.h"
+#include "program/prog_parameter.h"
+
+#include "intel_mipmap_tree.h"
+#include "intel_batchbuffer.h"
+#include "intel_tex.h"
+#include "intel_fbo.h"
+
+#include "brw_context.h"
+#include "brw_state.h"
+#include "brw_defines.h"
+#include "brw_wm.h"
+
+static void
+gen7_set_surface_tiling(struct gen7_surface_state *surf, uint32_t tiling)
+{
+   switch (tiling) {
+   case I915_TILING_NONE:
+      surf->ss0.tiled_surface = 0;
+      surf->ss0.tile_walk = 0;
+      break;
+   case I915_TILING_X:
+      surf->ss0.tiled_surface = 1;
+      surf->ss0.tile_walk = BRW_TILEWALK_XMAJOR;
+      break;
+   case I915_TILING_Y:
+      surf->ss0.tiled_surface = 1;
+      surf->ss0.tile_walk = BRW_TILEWALK_YMAJOR;
+      break;
+   }
+}
+
+static void
+gen7_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 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 gen7_surface_state *surf;
+
+   surf = brw_state_batch(brw, sizeof(*surf), 32,
+                        &brw->wm.surf_offset[surf_index]);
+   memset(surf, 0, sizeof(*surf));
+
+   surf->ss0.surface_type = translate_tex_target(tObj->Target);
+   surf->ss0.surface_format = translate_tex_format(firstImage->TexFormat,
+                                                   firstImage->InternalFormat,
+                                                   sampler->DepthMode,
+                                                   sampler->sRGBDecode);
+   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;
+   }
+
+   gen7_set_surface_tiling(surf, intelObj->mt->region->tiling);
+
+   /* ss0 remaining fields:
+    * - is_array
+    * - vertical_alignment
+    * - horizontal_alignment
+    * - vert_line_stride (exists on gen6 but we ignore it)
+    * - vert_line_stride_ofs (exists on gen6 but we ignore it)
+    * - surface_array_spacing
+    * - render_cache_read_write (exists on gen6 but ignored here)
+    */
+
+   surf->ss1.base_addr = intelObj->mt->region->buffer->offset; /* reloc */
+
+   surf->ss2.width = firstImage->Width - 1;
+   surf->ss2.height = firstImage->Height - 1;
+
+   surf->ss3.pitch = (intelObj->mt->region->pitch * intelObj->mt->cpp) - 1;
+   surf->ss3.depth = firstImage->Depth - 1;
+
+   /* ss4: ignored? */
+
+   surf->ss5.mip_count = intelObj->_MaxLevel - tObj->BaseLevel;
+   surf->ss5.min_lod = 0;
+
+   /* ss5 remaining fields:
+    * - x_offset (N/A for textures?)
+    * - y_offset (ditto)
+    * - cache_control
+    */
+
+   /* Emit relocation to surface contents */
+   drm_intel_bo_emit_reloc(brw->intel.batch.bo,
+                          brw->wm.surf_offset[surf_index] +
+                          offsetof(struct gen7_surface_state, ss1),
+                          intelObj->mt->region->buffer, 0,
+                          I915_GEM_DOMAIN_SAMPLER, 0);
+}
+
+/**
+ * Create the constant buffer surface.  Vertex/fragment shader constants will
+ * be read from this buffer with Data Port Read instructions/messages.
+ */
+static void
+gen7_create_constant_surface(struct brw_context *brw,
+                            drm_intel_bo *bo,
+                            int width,
+                            uint32_t *out_offset)
+{
+   const GLint w = width - 1;
+   struct gen7_surface_state *surf;
+
+   surf = brw_state_batch(brw, sizeof(*surf), 32, out_offset);
+   memset(surf, 0, sizeof(*surf));
+
+   surf->ss0.surface_type = BRW_SURFACE_BUFFER;
+   surf->ss0.surface_format = BRW_SURFACEFORMAT_R32G32B32A32_FLOAT;
+
+   surf->ss0.render_cache_read_write = 1;
+
+   assert(bo);
+   surf->ss1.base_addr = bo->offset; /* reloc */
+
+   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?? */
+   gen7_set_surface_tiling(surf, I915_TILING_NONE); /* tiling now allowed */
+
+   /* 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(brw->intel.batch.bo,
+                          (*out_offset +
+                           offsetof(struct gen7_surface_state, ss1)),
+                          bo, 0,
+                          I915_GEM_DOMAIN_SAMPLER, 0);
+}
+
+/**
+ * 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_offset[surf]) {
+        brw->state.dirty.brw |= BRW_NEW_WM_SURFACES;
+        brw->wm.surf_offset[surf] = 0;
+      }
+      return;
+   }
+
+   gen7_create_constant_surface(brw, brw->wm.const_bo, params->NumParameters,
+                               &brw->wm.surf_offset[surf]);
+   brw->state.dirty.brw |= BRW_NEW_WM_SURFACES;
+}
+
+const struct brw_tracked_state gen7_wm_constant_surface = {
+   .dirty = {
+      .mesa = 0,
+      .brw = (BRW_NEW_WM_CONSTBUF |
+             BRW_NEW_BATCH),
+      .cache = 0
+   },
+   .emit = upload_wm_constant_surface,
+};
+
+static void
+gen7_update_null_renderbuffer_surface(struct brw_context *brw, unsigned unit)
+{
+   struct gen7_surface_state *surf;
+
+   surf = brw_state_batch(brw, sizeof(*surf), 32,
+                        &brw->wm.surf_offset[unit]);
+   memset(surf, 0, sizeof(*surf));
+
+   surf->ss0.surface_type = BRW_SURFACE_NULL;
+   surf->ss0.surface_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+}
+
+/**
+ * Sets up a surface state structure to point at the given region.
+ * While it is only used for the front/back buffer currently, it should be
+ * usable for further buffers when doing ARB_draw_buffer support.
+ */
+static void
+gen7_update_renderbuffer_surface(struct brw_context *brw,
+                                struct gl_renderbuffer *rb,
+                                unsigned int unit)
+{
+   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 gen7_surface_state *surf;
+
+   surf = brw_state_batch(brw, sizeof(*surf), 32,
+                         &brw->wm.surf_offset[unit]);
+   memset(surf, 0, sizeof(*surf));
+
+   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;
+      break;
+   case MESA_FORMAT_INTENSITY_FLOAT32:
+   case MESA_FORMAT_LUMINANCE_FLOAT32:
+      /* 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.
+       */
+      surf->ss0.surface_format = BRW_SURFACEFORMAT_R32_FLOAT;
+      break;
+   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)
+        surf->ss0.surface_format = brw_format_for_mesa_format(irb->Base.Format);
+      else
+        surf->ss0.surface_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+      break;
+   default:
+      assert(brw_render_target_supported(irb->Base.Format));
+      surf->ss0.surface_format = brw_format_for_mesa_format(irb->Base.Format);
+   }
+
+   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;
+      }
+      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;
+   }
+   surf->ss1.base_addr += region->buffer->offset; /* reloc */
+
+   surf->ss2.width = rb->Width - 1;
+   surf->ss2.height = rb->Height - 1;
+   gen7_set_surface_tiling(surf, region->tiling);
+   surf->ss3.pitch = (region->pitch * region->cpp) - 1;
+
+   drm_intel_bo_emit_reloc(brw->intel.batch.bo,
+                          brw->wm.surf_offset[unit] +
+                          offsetof(struct gen7_surface_state, ss1),
+                          region->buffer,
+                          surf->ss1.base_addr - region->buffer->offset,
+                          I915_GEM_DOMAIN_RENDER,
+                          I915_GEM_DOMAIN_RENDER);
+}
+
+static void
+prepare_wm_surfaces(struct brw_context *brw)
+{
+   struct gl_context *ctx = &brw->intel.ctx;
+   int i;
+   int nr_surfaces = 0;
+
+   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;
+
+        if (region == NULL || region->buffer == NULL) {
+           brw->intel.Fallback = GL_TRUE; /* boolean, not bitfield */
+           return;
+        }
+
+        brw_add_validated_bo(brw, region->buffer);
+        nr_surfaces = SURF_INDEX_DRAW(i) + 1;
+      }
+   }
+
+   if (brw->wm.const_bo) {
+      brw_add_validated_bo(brw, brw->wm.const_bo);
+      nr_surfaces = SURF_INDEX_FRAG_CONST_BUFFER + 1;
+   }
+
+   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 (texUnit->_ReallyEnabled) {
+        brw_add_validated_bo(brw, intelObj->mt->region->buffer);
+        nr_surfaces = SURF_INDEX_TEXTURE(i) + 1;
+      }
+   }
+
+   /* 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;
+   }
+}
+
+/**
+ * Constructs the set of surface state objects pointed to by the
+ * binding table.
+ */
+static void
+upload_wm_surfaces(struct brw_context *brw)
+{
+   struct gl_context *ctx = &brw->intel.ctx;
+   GLuint i;
+
+   /* _NEW_BUFFERS | _NEW_COLOR */
+   /* Update surfaces for drawing buffers */
+   if (ctx->DrawBuffer->_NumColorDrawBuffers >= 1) {
+      for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
+        if (intel_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[i])) {
+           gen7_update_renderbuffer_surface(brw,
+              ctx->DrawBuffer->_ColorDrawBuffers[i], i);
+        } else {
+           gen7_update_null_renderbuffer_surface(brw, i);
+        }
+      }
+   } else {
+      gen7_update_null_renderbuffer_surface(brw, 0);
+   }
+
+   /* Update surfaces for textures */
+   for (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) {
+        gen7_update_texture_surface(ctx, i);
+      } else {
+         brw->wm.surf_offset[surf] = 0;
+      }
+   }
+
+   brw->state.dirty.brw |= BRW_NEW_WM_SURFACES;
+}
+
+const struct brw_tracked_state gen7_wm_surfaces = {
+   .dirty = {
+      .mesa = (_NEW_COLOR |
+               _NEW_TEXTURE |
+               _NEW_BUFFERS),
+      .brw = BRW_NEW_BATCH,
+      .cache = 0
+   },
+   .prepare = prepare_wm_surfaces,
+   .emit = upload_wm_surfaces,
+};