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, report INVALID_OPERATION as per spec wording.
Signed-off-by: Abdiel Janulgue <abdiel.janul...@linux.intel.com> --- src/mesa/drivers/dri/intel/intel_screen.c | 178 +++++++++++++++++++++++++---- 1 file changed, 158 insertions(+), 20 deletions(-) diff --git a/src/mesa/drivers/dri/intel/intel_screen.c b/src/mesa/drivers/dri/intel/intel_screen.c index e0fe8c1..ea62933 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,92 @@ 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, + image->slice_x_offset & ~mask_x, + image->slice_y_offset & ~mask_y, + false); +} + +/** + * Sets up a DRIImage structure to point to our shared image in a region + */ +static bool +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) && + (level > 0 || zoffset > 0)){ + /* Non-tile aligned sufaces in gen4 hw and earlier have problems resolving + * back to our destination due to alignment issues. Bail-out and report error + */ + _mesa_warning(NULL, "%s: can't resolve miptree level", __func__); + return false; + } else { + intel_image_set_level_info(image, mt, level, zoffset, mask_x, mask_y); + intel_region_reference(&image->region, mt->region); + } + + return true; +} + +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 +408,8 @@ intel_create_image_from_name(__DRIscreen *screen, return NULL; } + intel_setup_image_from_dimensions(image); + return image; } @@ -346,27 +439,63 @@ 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; + if (!intel_setup_image_from_mipmap_tree(intel, image, iobj->mt, level, zoffset)) { + _mesa_error(&intel->ctx, + GL_INVALID_OPERATION, "intel_create_image_from_texture"); + free(image); + return NULL; } + image->dri_format = intel_dri_format(image->format); return image; } @@ -405,6 +534,8 @@ intel_create_image(__DRIscreen *screen, return NULL; } + intel_setup_image_from_dimensions(image); + return image; } @@ -459,6 +590,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 +724,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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev