i965: Fix overwriting of depth override for SetTexOffset.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_wm_surface_state.c
index bf1a8668bed1c1b664c82491f9ba6f1fde669391..3790b50c976111e73d60ab66c55711c7a8d5d31f 100644 (file)
@@ -30,9 +30,9 @@
   */
                    
 
-#include "mtypes.h"
-#include "texformat.h"
-#include "texstore.h"
+#include "main/mtypes.h"
+#include "main/texformat.h"
+#include "main/texstore.h"
 
 #include "intel_mipmap_tree.h"
 #include "intel_batchbuffer.h"
@@ -69,7 +69,7 @@ static GLuint translate_tex_target( GLenum target )
 }
 
 
-static GLuint translate_tex_format( GLuint mesa_format )
+static GLuint translate_tex_format( GLuint mesa_format, GLenum depth_mode )
 {
    switch( mesa_format ) {
    case MESA_FORMAT_L8:
@@ -114,7 +114,12 @@ static GLuint translate_tex_format( GLuint mesa_format )
       return BRW_SURFACEFORMAT_FXT1;
 
    case MESA_FORMAT_Z16:
-      return BRW_SURFACEFORMAT_I16_UNORM;
+      if (depth_mode == GL_INTENSITY) 
+         return BRW_SURFACEFORMAT_I16_UNORM;
+      else if (depth_mode == GL_ALPHA)
+         return BRW_SURFACEFORMAT_A16_UNORM;
+      else
+         return BRW_SURFACEFORMAT_L16_UNORM;
 
    case MESA_FORMAT_RGB_DXT1:
        return BRW_SURFACEFORMAT_DXT1_RGB;
@@ -133,48 +138,86 @@ static GLuint translate_tex_format( GLuint mesa_format )
    case MESA_FORMAT_SRGB_DXT1:
       return BRW_SURFACEFORMAT_BC1_UNORM_SRGB;
 
+   case MESA_FORMAT_S8_Z24:
+      return BRW_SURFACEFORMAT_I24X8_UNORM;
+
    default:
       assert(0);
       return 0;
    }
 }
 
-static
-void brw_update_texture_surface( GLcontext *ctx, GLuint unit )
+struct brw_wm_surface_key {
+   GLenum target, depthmode;
+   dri_bo *bo;
+   GLint format;
+   GLint first_level, last_level;
+   GLint width, height, depth;
+   GLint pitch, cpp;
+   uint32_t tiling;
+   GLuint offset;
+};
+
+static void
+brw_set_surface_tiling(struct brw_surface_state *surf, 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;
+   case I915_TILING_Y:
+      surf->ss3.tiled_surface = 1;
+      surf->ss3.tile_walk = BRW_TILEWALK_YMAJOR;
+      break;
+   }
+}
+
+static dri_bo *
+brw_create_texture_surface( struct brw_context *brw,
+                           struct brw_wm_surface_key *key )
 {
-   struct intel_context *intel = intel_context(ctx);
-   struct brw_context *brw = brw_context(ctx);
-   struct gl_texture_object *tObj = brw->attribs.Texture->Unit[unit]._Current;
-   struct intel_texture_object *intelObj = intel_texture_object(tObj);
-   struct gl_texture_image *firstImage = tObj->Image[0][intelObj->firstLevel];
    struct brw_surface_state surf;
+   dri_bo *bo;
 
    memset(&surf, 0, sizeof(surf));
 
    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->MesaFormat);
+   surf.ss0.surface_type = translate_tex_target(key->target);
+
+   if (key->bo) 
+      surf.ss0.surface_format = translate_tex_format(key->format, key->depthmode);
+   else {
+     switch(key->depth) {
+     case 32: surf.ss0.surface_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM; break;
+     default:
+     case 24: surf.ss0.surface_format = BRW_SURFACEFORMAT_B8G8R8X8_UNORM; break;
+     case 16: surf.ss0.surface_format = BRW_SURFACEFORMAT_B5G6R5_UNORM; break;
+     }
+   }
 
    /* This is ok for all textures with channel width 8bit or less:
     */
 /*    surf.ss0.data_return_format = BRW_SURFACERETURNFORMAT_S1; */
-
-   /* BRW_NEW_LOCK */
-   surf.ss1.base_addr = bmBufferOffset(intel,
-                                       intelObj->mt->region->buffer);
-
-   surf.ss2.mip_count = intelObj->lastLevel - intelObj->firstLevel;
-   surf.ss2.width = firstImage->Width - 1;
-   surf.ss2.height = firstImage->Height - 1;
-
-   surf.ss3.tile_walk = BRW_TILEWALK_XMAJOR;
-   surf.ss3.tiled_surface = intelObj->mt->region->tiled; /* always zero */
-   surf.ss3.pitch = (intelObj->mt->pitch * intelObj->mt->cpp) - 1;
-   surf.ss3.depth = firstImage->Depth - 1;
+   if (key->bo)
+     surf.ss1.base_addr = key->bo->offset; /* reloc */
+   else
+     surf.ss1.base_addr = key->offset;
+
+   surf.ss2.mip_count = key->last_level - key->first_level;
+   surf.ss2.width = key->width - 1;
+   surf.ss2.height = key->height - 1;
+   brw_set_surface_tiling(&surf, key->tiling);
+   surf.ss3.pitch = (key->pitch * key->cpp) - 1;
+   surf.ss3.depth = key->depth - 1;
 
    surf.ss4.min_lod = 0;
  
-   if (tObj->Target == GL_TEXTURE_CUBE_MAP) {
+   if (key->target == GL_TEXTURE_CUBE_MAP) {
       surf.ss0.cube_pos_x = 1;
       surf.ss0.cube_pos_y = 1;
       surf.ss0.cube_pos_z = 1;
@@ -183,96 +226,263 @@ void brw_update_texture_surface( GLcontext *ctx, GLuint unit )
       surf.ss0.cube_neg_z = 1;
    }
 
-   brw->wm.bind.surf_ss_offset[unit + 1] =
-      brw_cache_data( &brw->cache[BRW_SS_SURFACE], &surf );
+   bo = brw_upload_cache(&brw->cache, BRW_SS_SURFACE,
+                        key, sizeof(*key),
+                        &key->bo, key->bo ? 1 : 0,
+                        &surf, sizeof(surf),
+                        NULL, NULL);
+
+   if (key->bo) {
+      /* Emit relocation to surface contents */
+      dri_bo_emit_reloc(bo,
+                       I915_GEM_DOMAIN_SAMPLER, 0,
+                       0,
+                       offsetof(struct brw_surface_state, ss1),
+                       key->bo);
+   }
+   return bo;
 }
 
+static void
+brw_update_texture_surface( GLcontext *ctx, GLuint unit )
+{
+   struct brw_context *brw = brw_context(ctx);
+   struct gl_texture_object *tObj = brw->attribs.Texture->Unit[unit]._Current;
+   struct intel_texture_object *intelObj = intel_texture_object(tObj);
+   struct gl_texture_image *firstImage = tObj->Image[0][intelObj->firstLevel];
+   struct brw_wm_surface_key key;
+
+   memset(&key, 0, sizeof(key));
+
+   if (intelObj->imageOverride) {
+      key.pitch = intelObj->pitchOverride / intelObj->mt->cpp;
+      key.depth = intelObj->depthOverride;
+      key.bo = NULL;
+      key.offset = intelObj->textureOffset;
+   } else {
+      key.format = firstImage->TexFormat->MesaFormat;
+      key.pitch = intelObj->mt->pitch;
+      key.depth = firstImage->Depth;
+      key.bo = intelObj->mt->region->buffer;
+      key.offset = 0;
+   }
 
+   key.target = tObj->Target;
+   key.depthmode = tObj->DepthMode;
+   key.first_level = intelObj->firstLevel;
+   key.last_level = intelObj->lastLevel;
+   key.width = firstImage->Width;
+   key.height = firstImage->Height;
+   key.cpp = intelObj->mt->cpp;
+   key.tiling = intelObj->mt->region->tiling;
+
+   dri_bo_unreference(brw->wm.surf_bo[unit + MAX_DRAW_BUFFERS]);
+   brw->wm.surf_bo[unit + MAX_DRAW_BUFFERS] = brw_search_cache(&brw->cache, BRW_SS_SURFACE,
+                                                              &key, sizeof(key),
+                                                              &key.bo, key.bo ? 1 : 0,
+                                                              NULL);
+   if (brw->wm.surf_bo[unit + MAX_DRAW_BUFFERS] == NULL) {
+      brw->wm.surf_bo[unit + MAX_DRAW_BUFFERS] = brw_create_texture_surface(brw, &key);
+   }
+}
 
-#define OFFSET(TYPE, FIELD) ( (GLuint)&(((TYPE *)0)->FIELD) )
-
-
-static void upload_wm_surfaces(struct brw_context *brw )
+/**
+ * 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
+brw_update_region_surface(struct brw_context *brw, struct intel_region *region,
+                         unsigned int unit, GLboolean cached)
 {
-   GLcontext *ctx = &brw->intel.ctx;
-   struct intel_context *intel = &brw->intel;
-   struct brw_surface_binding_table bind;
-   GLuint i;
-
-   memcpy(&bind, &brw->wm.bind, sizeof(bind));
-      
-   {
+   dri_bo *region_bo = NULL;
+   struct {
+      unsigned int surface_type;
+      unsigned int surface_format;
+      unsigned int width, height, cpp;
+      GLubyte color_mask[4];
+      GLboolean color_blend;
+      uint32_t tiling;
+   } key;
+
+   memset(&key, 0, sizeof(key));
+
+   if (region != NULL) {
+      region_bo = region->buffer;
+
+      key.surface_type = BRW_SURFACE_2D;
+      if (region->cpp == 4)
+        key.surface_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+      else
+        key.surface_format = BRW_SURFACEFORMAT_B5G6R5_UNORM;
+      key.tiling = region->tiling;
+      key.width = region->pitch; /* XXX: not really! */
+      key.height = region->height;
+      key.cpp = region->cpp;
+   } else {
+      key.surface_type = BRW_SURFACE_NULL;
+      key.surface_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+      key.tiling = 0;
+      key.width = 1;
+      key.height = 1;
+      key.cpp = 4;
+   }
+   memcpy(key.color_mask, brw->attribs.Color->ColorMask,
+         sizeof(key.color_mask));
+   key.color_blend = (!brw->attribs.Color->_LogicOpEnabled &&
+                     brw->attribs.Color->BlendEnabled);
+
+   dri_bo_unreference(brw->wm.surf_bo[unit]);
+   brw->wm.surf_bo[unit] = NULL;
+   if (cached) 
+       brw->wm.surf_bo[unit] = brw_search_cache(&brw->cache, BRW_SS_SURFACE,
+              &key, sizeof(key),
+              &region_bo, 1,
+              NULL);
+
+   if (brw->wm.surf_bo[unit] == NULL) {
       struct brw_surface_state surf;
-      struct intel_region *region = brw->state.draw_region;
 
       memset(&surf, 0, sizeof(surf));
 
-      if (region->cpp == 4)
-        surf.ss0.surface_format = BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
-      else 
-        surf.ss0.surface_format = BRW_SURFACEFORMAT_B5G6R5_UNORM;
+      surf.ss0.surface_format = key.surface_format;
+      surf.ss0.surface_type = key.surface_type;
+      if (region_bo != NULL)
+        surf.ss1.base_addr = region_bo->offset; /* reloc */
 
-      surf.ss0.surface_type = BRW_SURFACE_2D;
+      surf.ss2.width = key.width - 1;
+      surf.ss2.height = key.height - 1;
+      brw_set_surface_tiling(&surf, key.tiling);
+      surf.ss3.pitch = (key.width * key.cpp) - 1;
 
       /* _NEW_COLOR */
-      surf.ss0.color_blend = (!brw->attribs.Color->_LogicOpEnabled &&
-                             brw->attribs.Color->BlendEnabled);
+      surf.ss0.color_blend = key.color_blend;
+      surf.ss0.writedisable_red =   !key.color_mask[0];
+      surf.ss0.writedisable_green = !key.color_mask[1];
+      surf.ss0.writedisable_blue =  !key.color_mask[2];
+      surf.ss0.writedisable_alpha = !key.color_mask[3];
+
+      /* Key size will never match key size for textures, so we're safe. */
+      brw->wm.surf_bo[unit] = brw_upload_cache(&brw->cache, BRW_SS_SURFACE,
+                                             &key, sizeof(key),
+                                              &region_bo, 1,
+                                              &surf, sizeof(surf),
+                                              NULL, NULL);
+      if (region_bo != NULL) {
+        /* We might sample from it, and we might render to it, so flag
+         * them both.  We might be able to figure out from other state
+         * a more restrictive relocation to emit.
+         */
+        dri_bo_emit_reloc(brw->wm.surf_bo[unit],
+                          I915_GEM_DOMAIN_RENDER |
+                          I915_GEM_DOMAIN_SAMPLER,
+                          I915_GEM_DOMAIN_RENDER,
+                          0,
+                          offsetof(struct brw_surface_state, ss1),
+                          region_bo);
+      }
+   }
+}
 
 
-      surf.ss0.writedisable_red =   !brw->attribs.Color->ColorMask[0];
-      surf.ss0.writedisable_green = !brw->attribs.Color->ColorMask[1];
-      surf.ss0.writedisable_blue =  !brw->attribs.Color->ColorMask[2];
-      surf.ss0.writedisable_alpha = !brw->attribs.Color->ColorMask[3];
+/**
+ * Constructs the binding table for the WM surface state, which maps unit
+ * numbers to surface state objects.
+ */
+static dri_bo *
+brw_wm_get_binding_table(struct brw_context *brw)
+{
+   dri_bo *bind_bo;
+
+   bind_bo = brw_search_cache(&brw->cache, BRW_SS_SURF_BIND,
+                             NULL, 0,
+                             brw->wm.surf_bo, brw->wm.nr_surfaces,
+                             NULL);
+
+   if (bind_bo == NULL) {
+      GLuint data_size = brw->wm.nr_surfaces * sizeof(GLuint);
+      uint32_t *data = malloc(data_size);
+      int i;
+
+      for (i = 0; i < brw->wm.nr_surfaces; i++)
+         if (brw->wm.surf_bo[i])
+            data[i] = brw->wm.surf_bo[i]->offset;
+         else
+            data[i] = 0;
+
+      bind_bo = brw_upload_cache( &brw->cache, BRW_SS_SURF_BIND,
+                                 NULL, 0,
+                                 brw->wm.surf_bo, brw->wm.nr_surfaces,
+                                 data, data_size,
+                                 NULL, NULL);
+
+      /* Emit binding table relocations to surface state */
+      for (i = 0; i < BRW_WM_MAX_SURF; i++) {
+        if (brw->wm.surf_bo[i] != NULL) {
+           dri_bo_emit_reloc(bind_bo,
+                             I915_GEM_DOMAIN_INSTRUCTION, 0,
+                             0,
+                             i * sizeof(GLuint),
+                             brw->wm.surf_bo[i]);
+        }
+      }
 
-      /* BRW_NEW_LOCK */
-      surf.ss1.base_addr = bmBufferOffset(&brw->intel, region->buffer);
+      free(data);
+   }
 
+   return bind_bo;
+}
 
-      surf.ss2.width = region->pitch - 1; /* XXX: not really! */
-      surf.ss2.height = region->height - 1;
-      surf.ss3.tile_walk = BRW_TILEWALK_XMAJOR;
-      surf.ss3.tiled_surface = region->tiled;
-      surf.ss3.pitch = (region->pitch * region->cpp) - 1;
+static void prepare_wm_surfaces(struct brw_context *brw )
+{
+   GLcontext *ctx = &brw->intel.ctx;
+   struct intel_context *intel = &brw->intel;
+   GLuint i;
 
-      brw->wm.bind.surf_ss_offset[0] = brw_cache_data( &brw->cache[BRW_SS_SURFACE], &surf );
-      brw->wm.nr_surfaces = 1;
+   if (brw->state.nr_draw_regions  > 1) {
+      for (i = 0; i < brw->state.nr_draw_regions; i++) {
+         brw_update_region_surface(brw, brw->state.draw_regions[i], i,
+                                  GL_FALSE);
+      }
+   }else {
+      brw_update_region_surface(brw, brw->state.draw_regions[0], 0, GL_TRUE);
    }
 
+   brw->wm.nr_surfaces = MAX_DRAW_BUFFERS;
 
    for (i = 0; i < BRW_MAX_TEX_UNIT; i++) {
       struct gl_texture_unit *texUnit = &brw->attribs.Texture->Unit[i];
 
-      /* _NEW_TEXTURE, BRW_NEW_TEXDATA 
-       */
-      if (texUnit->_ReallyEnabled &&
-         intel_finalize_mipmap_tree(intel,texUnit->_Current))
-      {
-        brw_update_texture_surface(ctx, i);
-        brw->wm.nr_surfaces = i+2;
-      }
-      else if( texUnit->_ReallyEnabled &&
-              texUnit->_Current == intel->frame_buffer_texobj )
-      {
-        brw->wm.bind.surf_ss_offset[i+1] = brw->wm.bind.surf_ss_offset[0];
-        brw->wm.nr_surfaces = i+2;
-      }    
-      else {
-        brw->wm.bind.surf_ss_offset[i+1] = 0;
+      /* _NEW_TEXTURE, BRW_NEW_TEXDATA */
+      if(texUnit->_ReallyEnabled) {
+         if (texUnit->_Current == intel->frame_buffer_texobj) {
+            dri_bo_unreference(brw->wm.surf_bo[i+MAX_DRAW_BUFFERS]);
+            brw->wm.surf_bo[i+MAX_DRAW_BUFFERS] = brw->wm.surf_bo[0];
+            dri_bo_reference(brw->wm.surf_bo[i+MAX_DRAW_BUFFERS]);
+            brw->wm.nr_surfaces = i + MAX_DRAW_BUFFERS + 1;
+         } else {
+            brw_update_texture_surface(ctx, i);
+            brw->wm.nr_surfaces = i + MAX_DRAW_BUFFERS + 1;
+         }
+      } else {
+         dri_bo_unreference(brw->wm.surf_bo[i+MAX_DRAW_BUFFERS]);
+         brw->wm.surf_bo[i+MAX_DRAW_BUFFERS] = NULL;
       }
+
    }
 
-   brw->wm.bind_ss_offset = brw_cache_data( &brw->cache[BRW_SS_SURF_BIND],
-                                           &brw->wm.bind );
+   dri_bo_unreference(brw->wm.bind_bo);
+   brw->wm.bind_bo = brw_wm_get_binding_table(brw);
 }
 
+
 const struct brw_tracked_state brw_wm_surfaces = {
    .dirty = {
       .mesa = _NEW_COLOR | _NEW_TEXTURE | _NEW_BUFFERS,
-      .brw = (BRW_NEW_CONTEXT | 
-             BRW_NEW_LOCK),    /* required for bmBufferOffset */
+      .brw = BRW_NEW_CONTEXT,
       .cache = 0
    },
-   .update = upload_wm_surfaces
+   .prepare = prepare_wm_surfaces,
 };