[Mesa-dev] [PATCH 5/6] intel: implement create image from texture

Abdiel Janulgue abdiel.janulgue at linux.intel.com
Wed Jan 2 05:34:36 PST 2013


Save miptree level info to DRIImage, taking offsets into consideration.
In non-tile-aligned surface cases where resolving back to the original image
proves problematic due to alignment issues, copy the image to a single-level
miptree and refer to the offsets there instead to avoid orphaning

Signed-off-by: Abdiel Janulgue <abdiel.janulgue at linux.intel.com>
---
 src/mesa/drivers/dri/intel/intel_screen.c |  181 +++++++++++++++++++++++++----
 1 file changed, 161 insertions(+), 20 deletions(-)

diff --git a/src/mesa/drivers/dri/intel/intel_screen.c b/src/mesa/drivers/dri/intel/intel_screen.c
index 4e2742f..0cd1a2c 100644
--- a/src/mesa/drivers/dri/intel/intel_screen.c
+++ b/src/mesa/drivers/dri/intel/intel_screen.c
@@ -31,6 +31,7 @@
 #include "main/context.h"
 #include "main/framebuffer.h"
 #include "main/renderbuffer.h"
+#include "main/texobj.h"
 #include "main/hash.h"
 #include "main/fbobject.h"
 #include "main/mfeatures.h"
@@ -104,6 +105,10 @@ const GLuint __driNConfigOptions = 15;
 #include "intel_tex.h"
 #include "intel_regions.h"
 
+#ifndef I915
+#include "brw_context.h"
+#endif
+
 #include "i915_drm.h"
 
 #ifdef USE_NEW_INTERFACE
@@ -295,6 +300,101 @@ intel_allocate_image(int dri_format, void *loaderPrivate)
     return image;
 }
 
+static void
+intel_image_set_level_info(__DRIimage *image, struct intel_mipmap_tree *mt,
+                           int level, int slice,
+                           uint32_t mask_x,  uint32_t mask_y)
+{
+   image->width = mt->level[level].width;
+   image->height = mt->level[level].height;
+   image->level_x = mt->level[level].level_x;
+   image->level_y = mt->level[level].level_y;
+   image->slice_x_offset = mt->level[level].slice[slice].x_offset;
+   image->slice_y_offset = mt->level[level].slice[slice].y_offset;
+
+   image->offset = intel_region_get_aligned_offset(mt->region,
+                                                   mt->level[level].level_x & ~mask_x,
+                                                   mt->level[level].level_y & ~mask_y,
+                                                   false);
+}
+
+/**
+ * Sets up a DRIImage structure to point to our shared image in a region
+ */
+static void
+intel_setup_image_from_mipmap_tree(struct intel_context *intel, __DRIimage *image,
+                                   struct intel_mipmap_tree *mt, GLuint level,
+                                   GLuint zoffset)
+{
+   bool has_surface_tile_offset = false;
+   uint32_t mask_x, mask_y;
+   uint32_t draw_x, draw_y;
+
+   intel_miptree_check_level_layer(mt, level, zoffset);
+   intel_miptree_get_image_offset(mt, level, zoffset,
+                                  &draw_x, &draw_y);
+   intel_region_get_tile_masks(mt->region, &mask_x, &mask_y, false);
+
+#ifndef I915
+   has_surface_tile_offset = brw_context(&intel->ctx)->has_surface_tile_offset;
+#endif
+   if (!has_surface_tile_offset &&
+       ((draw_x & mask_x) != 0 || (draw_y & mask_y) != 0)) {
+      /* Non-tile aligned sufaces in gen4 hw and earlier have problems resolving
+       * back to our destination due to alignment issues. So we make a temporary
+       * single-level miptree and copy our mipmap level there.
+       */ 
+      struct intel_mipmap_tree *new_mt = intel_miptree_create(intel,
+                                                              mt->target, mt->format,
+                                                              level, level,
+                                                              mt->level[level].width, 
+                                                              mt->level[level].height, 
+                                                              1, true,
+                                                              mt->num_samples,
+                                                              mt->msaa_layout);
+
+      intel_miptree_copy_slice(intel, new_mt, mt, level, 0, zoffset);
+      intel_image_set_level_info(image, new_mt, level, 0, mask_x, mask_y);
+      intel_region_reference(&image->region, new_mt->region);
+      intel_miptree_release(&new_mt);
+   } else {
+      intel_image_set_level_info(image, mt, level, zoffset, mask_x, mask_y);
+      intel_region_reference(&image->region, mt->region);
+   }
+}
+
+static void
+intel_setup_image_from_dimensions(__DRIimage *image)
+{
+   image->width    = image->region->width;
+   image->height   = image->region->height;
+   image->level_x = 0;
+   image->level_y = 0;
+   image->slice_x_offset = 0;
+   image->slice_y_offset = 0;
+}
+
+static inline uint32_t
+intel_dri_format(GLuint format)
+{
+   switch (format) {
+   case MESA_FORMAT_RGB565:
+      return __DRI_IMAGE_FORMAT_RGB565;
+   case MESA_FORMAT_XRGB8888:
+      return __DRI_IMAGE_FORMAT_XRGB8888;
+   case MESA_FORMAT_ARGB8888:
+      return __DRI_IMAGE_FORMAT_ARGB8888;
+   case MESA_FORMAT_RGBA8888_REV:
+      return __DRI_IMAGE_FORMAT_ABGR8888;
+   case MESA_FORMAT_R8:
+      return __DRI_IMAGE_FORMAT_R8;
+   case MESA_FORMAT_RG88:
+      return __DRI_IMAGE_FORMAT_GR88;
+   }
+
+   return 0;
+}
+
 static __DRIimage *
 intel_create_image_from_name(__DRIscreen *screen,
 			     int width, int height, int format,
@@ -317,6 +417,8 @@ intel_create_image_from_name(__DRIscreen *screen,
        return NULL;
     }
 
+    intel_setup_image_from_dimensions(image);
+
     return image;	
 }
 
@@ -346,28 +448,58 @@ intel_create_image_from_renderbuffer(__DRIcontext *context,
    image->offset = 0;
    image->data = loaderPrivate;
    intel_region_reference(&image->region, irb->mt->region);
+   intel_setup_image_from_dimensions(image);
+   image->dri_format = intel_dri_format(image->format);
 
-   switch (image->format) {
-   case MESA_FORMAT_RGB565:
-      image->dri_format = __DRI_IMAGE_FORMAT_RGB565;
-      break;
-   case MESA_FORMAT_XRGB8888:
-      image->dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
-      break;
-   case MESA_FORMAT_ARGB8888:
-      image->dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
-      break;
-   case MESA_FORMAT_RGBA8888_REV:
-      image->dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
-      break;
-   case MESA_FORMAT_R8:
-      image->dri_format = __DRI_IMAGE_FORMAT_R8;
-      break;
-   case MESA_FORMAT_RG88:
-      image->dri_format = __DRI_IMAGE_FORMAT_GR88;
-      break;
+   return image;
+}
+
+static __DRIimage *
+intel_create_image_from_texture(__DRIcontext *context, int target,
+                                unsigned texture, int zoffset, int level,
+                                void *loaderPrivate)
+{
+   __DRIimage *image;
+   struct intel_context *intel = context->driverPrivate;
+   struct gl_texture_object *obj;
+   struct intel_texture_object *iobj;
+   GLuint face = 0;
+
+   obj = _mesa_lookup_texture(&intel->ctx, texture);
+   if (!obj || obj->Target != target) {
+      _mesa_warning(NULL, "%s: invalid texture", __func__);
+      return NULL;
    }
 
+   if (target == GL_TEXTURE_CUBE_MAP)
+      face = zoffset;
+
+   _mesa_test_texobj_completeness(&intel->ctx, obj);
+   iobj = intel_texture_object(obj);
+   if (!obj->_BaseComplete || (level > 0 && !obj->_MipmapComplete)) {
+      _mesa_warning(NULL, "%s: texture object incomplete", __func__);
+      return NULL;
+   }
+
+   if (level < obj->BaseLevel || level > obj->_MaxLevel) {
+      _mesa_warning(NULL, "%s: invalid mipmap level", __func__);
+      return NULL;
+   }
+
+   if (target == GL_TEXTURE_3D && obj->Image[face][level]->Depth < zoffset) {
+      _mesa_warning(NULL, "%s: invalid Z offset", __func__);
+      return NULL;
+   }
+   image = calloc(1, sizeof *image);
+   if (image == NULL)
+      return NULL;
+
+   image->internal_format = obj->Image[face][level]->InternalFormat;
+   image->format = obj->Image[face][level]->TexFormat;
+   image->data = loaderPrivate;
+   intel_setup_image_from_mipmap_tree(intel, image, iobj->mt, level, zoffset);
+   image->dri_format = intel_dri_format(image->format);
+
    return image;
 }
 
@@ -405,6 +537,8 @@ intel_create_image(__DRIscreen *screen,
       return NULL;
    }
    
+   intel_setup_image_from_dimensions(image);
+
    return image;
 }
 
@@ -459,6 +593,12 @@ intel_dup_image(__DRIimage *orig_image, void *loaderPrivate)
    image->dri_format      = orig_image->dri_format;
    image->format          = orig_image->format;
    image->offset          = orig_image->offset;
+   image->width           = orig_image->width;
+   image->height          = orig_image->height;
+   image->level_x         = orig_image->level_x;
+   image->level_y         = orig_image->level_y;
+   image->slice_x_offset  = orig_image->slice_x_offset;
+   image->slice_y_offset  = orig_image->slice_y_offset;
    image->data            = loaderPrivate;
 
    memcpy(image->strides, orig_image->strides, sizeof(image->strides));
@@ -587,7 +727,8 @@ static struct __DRIimageExtensionRec intelImageExtension = {
     .dupImage                           = intel_dup_image,
     .validateUsage                      = intel_validate_usage,
     .createImageFromNames               = intel_create_image_from_names,
-    .fromPlanar                         = intel_from_planar
+    .fromPlanar                         = intel_from_planar,
+    .createImageFromTexture             = intel_create_image_from_texture
 };
 
 static const __DRIextension *intelScreenExtensions[] = {
-- 
1.7.9.5



More information about the mesa-dev mailing list