nir: support lowering clipdist to arrays
[mesa.git] / src / mesa / drivers / dri / i965 / intel_tex_validate.c
index 0cfb32f76d19f895490bdc050bb5c68644572ba0..37aa8f43ec9ae59c1b05acccb5cf9e18288decd9 100644 (file)
-/**************************************************************************
- * 
- * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- * 
+/*
+ * Copyright © 2013 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, sub license, 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 NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
- * 
- **************************************************************************/
+ * 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 "mtypes.h"
-#include "macros.h"
+#include "main/mtypes.h"
+#include "main/macros.h"
+#include "main/samplerobj.h"
+#include "main/teximage.h"
+#include "main/texobj.h"
 
-#include "intel_context.h"
+#include "brw_context.h"
 #include "intel_mipmap_tree.h"
 #include "intel_tex.h"
-#include "dri_bufmgr.h"
+
+#define FILE_DEBUG_FLAG DEBUG_TEXTURE
 
 /**
- * Compute which mipmap levels that really need to be sent to the hardware.
- * This depends on the base image size, GL_TEXTURE_MIN_LOD,
- * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
+ * Sets our driver-specific variant of tObj->_MaxLevel for later surface state
+ * upload.
+ *
+ * If we're only ensuring that there is storage for the first miplevel of a
+ * texture, then in texture setup we're going to have to make sure we don't
+ * allow sampling beyond level 0.
  */
-static void intel_calculate_first_last_level( struct intel_texture_object *intelObj )
+static void
+intel_update_max_level(struct gl_texture_object *tObj,
+                      struct gl_sampler_object *sampler)
 {
-   struct gl_texture_object *tObj = &intelObj->base;
-   const struct gl_texture_image * const baseImage =
-       tObj->Image[0][tObj->BaseLevel];
-
-   /* These must be signed values.  MinLod and MaxLod can be negative numbers,
-    * and having firstLevel and lastLevel as signed prevents the need for
-    * extra sign checks.
-    */
-   int   firstLevel;
-   int   lastLevel;
+   struct intel_texture_object *intelObj = intel_texture_object(tObj);
 
-   /* Yes, this looks overly complicated, but it's all needed.
-    */
-   switch (tObj->Target) {
-   case GL_TEXTURE_1D:
-   case GL_TEXTURE_2D:
-   case GL_TEXTURE_3D:
-   case GL_TEXTURE_CUBE_MAP:
-      if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) {
-         /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
-          */
-         firstLevel = lastLevel = tObj->BaseLevel;
-      }
-      else {
-        /* Currently not taking min/max lod into account here, those
-         * values are programmed as sampler state elsewhere and we
-         * upload the same mipmap levels regardless.  Not sure if
-         * this makes sense as it means it isn't possible for the app
-         * to use min/max lod to reduce texture memory pressure:
-         */
-        firstLevel = tObj->BaseLevel;
-        lastLevel = MIN2(tObj->BaseLevel + baseImage->MaxLog2, 
-                         tObj->MaxLevel);
-        lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
-      }
-      break;
-   case GL_TEXTURE_RECTANGLE_NV:
-   case GL_TEXTURE_4D_SGIS:
-      firstLevel = lastLevel = 0;
-      break;
-   default:
-      return;
+   if (!tObj->_MipmapComplete ||
+       (tObj->_RenderToTexture &&
+        (sampler->MinFilter == GL_NEAREST ||
+         sampler->MinFilter == GL_LINEAR))) {
+      intelObj->_MaxLevel = tObj->BaseLevel;
+   } else {
+      intelObj->_MaxLevel = tObj->_MaxLevel;
    }
-
-   /* save these values */
-   intelObj->firstLevel = firstLevel;
-   intelObj->lastLevel = lastLevel;
-}
-
-static GLboolean copy_image_data_to_tree( struct intel_context *intel,
-                                         struct intel_texture_object *intelObj,
-                                         struct gl_texture_image *texImage,
-                                         GLuint face,
-                                         GLuint level)
-{
-   return intel_miptree_image_data(intel,
-                                  intelObj->mt,
-                                  face,
-                                  level,
-                                  texImage->Data,
-                                  texImage->RowStride,
-                                  (texImage->RowStride * 
-                                   texImage->Height * 
-                                   texImage->TexFormat->TexelBytes));
-}
-
-static void intel_texture_invalidate( struct intel_texture_object *intelObj )
-{
-   GLint nr_faces, face;
-   intelObj->dirty = ~0;
-
-   nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
-   for (face = 0; face < nr_faces; face++) 
-      intelObj->dirty_images[face] = ~0;
-}
-
-static void intel_texture_invalidate_cb( struct intel_context *intel,
-                                        void *ptr )
-{
-   intel_texture_invalidate( (struct intel_texture_object *) ptr );
-}
-
-#include "texformat.h"
-static GLuint intel_compressed_num_bytes(GLenum mesaFormat)
-{
-    GLuint bytes = 0;
-
-    switch (mesaFormat) {
-    case MESA_FORMAT_RGB_FXT1:
-    case MESA_FORMAT_RGBA_FXT1:
-    case MESA_FORMAT_RGB_DXT1:
-    case MESA_FORMAT_RGBA_DXT1:
-        bytes = 2;
-        break;
-
-    case MESA_FORMAT_RGBA_DXT3:
-    case MESA_FORMAT_RGBA_DXT5:
-        bytes = 4;
-    
-    default:
-        break;
-    }
-
-    return bytes;
 }
 
-/*  
+/**
+ * At rendering-from-a-texture time, make sure that the texture object has a
+ * miptree that can hold the entire texture based on
+ * BaseLevel/MaxLevel/filtering, and copy in any texture images that are
+ * stored in other miptrees.
  */
-GLuint intel_finalize_mipmap_tree( struct intel_context *intel,
-                                  struct gl_texture_object *tObj )
+void
+intel_finalize_mipmap_tree(struct brw_context *brw,
+                           struct gl_texture_object *tObj)
 {
    struct intel_texture_object *intelObj = intel_texture_object(tObj);
    GLuint face, i;
    GLuint nr_faces = 0;
-   struct gl_texture_image *firstImage;
-   GLuint cpp = 0;
-   
-   if( tObj == intel->frame_buffer_texobj )
-      return GL_FALSE;
-   
-   /* We know/require this is true by now: 
-    */
-   assert(intelObj->base._Complete);
+   struct intel_texture_image *firstImage;
+   int width, height, depth;
 
-   /* What levels must the tree include at a minimum?
-    */
-   if (intelObj->dirty) {
-      intel_calculate_first_last_level( intelObj );
-/*       intel_miptree_destroy(intel, intelObj->mt); */
-/*       intelObj->mt = NULL; */
-   }
+   /* TBOs require no validation -- they always just point to their BO. */
+   if (tObj->Target == GL_TEXTURE_BUFFER)
+      return;
 
-   firstImage = intelObj->base.Image[0][intelObj->firstLevel];
+   /* What levels does this validated texture image require? */
+   int validate_first_level = tObj->BaseLevel;
+   int validate_last_level = intelObj->_MaxLevel;
 
-   /* Fallback case:
+   /* Skip the loop over images in the common case of no images having
+    * changed.  But if the GL_BASE_LEVEL or GL_MAX_LEVEL change to something we
+    * haven't looked at, then we do need to look at those new images.
     */
-   if (firstImage->Border) {
-      if (intelObj->mt) {
-        intel_miptree_destroy(intel, intelObj->mt);
-        intelObj->mt = NULL;
-        /* Set all images dirty:
-         */
-        intel_texture_invalidate(intelObj);
-      }
-      return GL_FALSE;
+   if (!intelObj->needs_validate &&
+       validate_first_level >= intelObj->validated_first_level &&
+       validate_last_level <= intelObj->validated_last_level) {
+      return;
    }
 
+   /* On recent generations, immutable textures should not get this far
+    * -- they should have been created in a validated state, and nothing
+    * can invalidate them.
+    *
+    * Unfortunately, this is not true on pre-Sandybridge hardware -- when
+    * rendering into an immutable-format depth texture we may have to rebase
+    * the rendered levels to meet alignment requirements.
+    *
+    * FINISHME: Avoid doing this.
+    */
+   assert(!tObj->Immutable || brw->screen->devinfo.gen < 6);
 
+   firstImage = intel_texture_image(tObj->Image[0][tObj->BaseLevel]);
 
-   if (firstImage->IsCompressed) {
-       cpp = intel_compressed_num_bytes(firstImage->TexFormat->MesaFormat);
-   } else {
-       cpp = firstImage->TexFormat->TexelBytes;
-   }
-       
    /* Check tree can hold all active levels.  Check tree matches
     * target, imageFormat, etc.
     */
    if (intelObj->mt &&
-       (intelObj->mt->target != intelObj->base.Target ||
-       intelObj->mt->internal_format != firstImage->InternalFormat ||
-       intelObj->mt->first_level != intelObj->firstLevel ||
-       intelObj->mt->last_level != intelObj->lastLevel ||
-       intelObj->mt->width0 != firstImage->Width ||
-       intelObj->mt->height0 != firstImage->Height ||
-       intelObj->mt->depth0 != firstImage->Depth ||
-       intelObj->mt->cpp != cpp ||
-       intelObj->mt->compressed != firstImage->IsCompressed)) 
-   {
-      intel_miptree_destroy(intel, intelObj->mt);
-      intelObj->mt = NULL;
-      
-      /* Set all images dirty:
-       */
-      intel_texture_invalidate(intelObj);
+       (!intel_miptree_match_image(intelObj->mt, &firstImage->base.Base) ||
+       validate_first_level < intelObj->mt->first_level ||
+       validate_last_level > intelObj->mt->last_level)) {
+      intel_miptree_release(&intelObj->mt);
    }
-      
+
 
    /* May need to create a new tree:
     */
    if (!intelObj->mt) {
-      intelObj->mt = intel_miptree_create(intel,
-                                         intelObj->base.Target,
-                                         firstImage->InternalFormat,
-                                         intelObj->firstLevel,
-                                         intelObj->lastLevel,
-                                         firstImage->Width,
-                                         firstImage->Height,
-                                         firstImage->Depth,
-                                         cpp,
-                                         firstImage->IsCompressed);
-
-      /* Tell the buffer manager that we will manage the backing
-       * store, but we still want it to do fencing for us.
-       */
-      bmBufferSetInvalidateCB(intel, 
-                             intelObj->mt->region->buffer,
-                             intel_texture_invalidate_cb,
-                             intelObj,
-                             GL_FALSE);
+      const unsigned level = firstImage->base.Base.Level;
+      intel_get_image_dims(&firstImage->base.Base, &width, &height, &depth);
+      /* Figure out image dimensions at start level. */
+      switch(intelObj->base.Target) {
+      case GL_TEXTURE_2D_MULTISAMPLE:
+      case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+      case GL_TEXTURE_RECTANGLE:
+      case GL_TEXTURE_EXTERNAL_OES:
+          assert(level == 0);
+          break;
+      case GL_TEXTURE_3D:
+          depth = depth << level;
+          /* Fall through */
+      case GL_TEXTURE_2D:
+      case GL_TEXTURE_2D_ARRAY:
+      case GL_TEXTURE_CUBE_MAP:
+      case GL_TEXTURE_CUBE_MAP_ARRAY:
+          height = height << level;
+          /* Fall through */
+      case GL_TEXTURE_1D:
+      case GL_TEXTURE_1D_ARRAY:
+          width = width << level;
+          break;
+      default:
+          unreachable("Unexpected target");
+      }
+      perf_debug("Creating new %s %dx%dx%d %d-level miptree to handle "
+                 "finalized texture miptree.\n",
+                 _mesa_get_format_name(firstImage->base.Base.TexFormat),
+                 width, height, depth, validate_last_level + 1);
+
+      intelObj->mt = intel_miptree_create(brw,
+                                          intelObj->base.Target,
+                                         firstImage->base.Base.TexFormat,
+                                          0, /* first_level */
+                                          validate_last_level,
+                                          width,
+                                          height,
+                                          depth,
+                                          1 /* num_samples */,
+                                          MIPTREE_CREATE_BUSY);
+      if (!intelObj->mt)
+         return;
    }
 
    /* Pull in any images not in the object's tree:
     */
-   if (intelObj->dirty) {
-      nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
-      for (face = 0; face < nr_faces; face++) {
-        if (intelObj->dirty_images[face]) {
-           for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++) {
-              struct gl_texture_image *texImage = intelObj->base.Image[face][i];
+   nr_faces = _mesa_num_tex_faces(intelObj->base.Target);
+   for (face = 0; face < nr_faces; face++) {
+      for (i = validate_first_level; i <= validate_last_level; i++) {
+         struct intel_texture_image *intelImage =
+            intel_texture_image(intelObj->base.Image[face][i]);
+        /* skip too small size mipmap */
+        if (intelImage == NULL)
+                break;
+
+         if (intelObj->mt != intelImage->mt)
+            intel_miptree_copy_teximage(brw, intelImage, intelObj->mt);
+
+         /* After we're done, we'd better agree that our layout is
+          * appropriate, or we'll end up hitting this function again on the
+          * next draw
+          */
+         assert(intel_miptree_match_image(intelObj->mt, &intelImage->base.Base));
+      }
+   }
 
-              /* Need to import images in main memory or held in other trees.
-               */
-              if (intelObj->dirty_images[face] & (1<<i) &&
-                  texImage) {
+   intelObj->validated_first_level = validate_first_level;
+   intelObj->validated_last_level = validate_last_level;
+   intelObj->_Format = firstImage->base.Base.TexFormat,
+   intelObj->needs_validate = false;
+}
 
-                 if (INTEL_DEBUG & DEBUG_TEXTURE)
-                    _mesa_printf("copy data from image %d (%p) into object miptree\n",
-                                 i,
-                                 texImage->Data);
+/**
+ * Finalizes all textures, completing any rendering that needs to be done
+ * to prepare them.
+ */
+void
+brw_validate_textures(struct brw_context *brw)
+{
+   struct gl_context *ctx = &brw->ctx;
+   const int max_enabled_unit = ctx->Texture._MaxEnabledTexImageUnit;
 
-                 if (!copy_image_data_to_tree(intel,
-                                              intelObj,
-                                              texImage,
-                                              face,
-                                              i))
-                    return GL_FALSE;
+   for (int unit = 0; unit <= max_enabled_unit; unit++) {
+      struct gl_texture_object *tex_obj = ctx->Texture.Unit[unit]._Current;
 
-              }
-           }
-        }
-      }
+      if (!tex_obj)
+         continue;
 
-      /* Only clear the dirty flags if everything went ok:
+      struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit);
+
+      /* We know that this is true by now, and if it wasn't, we might have
+       * mismatched level sizes and the copies would fail.
        */
-      for (face = 0; face < nr_faces; face++) {
-        intelObj->dirty_images[face] = 0;
-      }
+      assert(tex_obj->_BaseComplete);
 
-      intelObj->dirty = 0;
+      intel_update_max_level(tex_obj, sampler);
+      intel_finalize_mipmap_tree(brw, tex_obj);
    }
-
-   return GL_TRUE;
 }