Save miptree level info to DRIImage: - Appropriately-aligned base offset pointing to the image - x/y offsets from miptree's base address
In non-tile-aligned surface cases where resolving back to the original image located in mip-levels higher than the base level proves problematic due to offset 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 | 186 +++++++++++++++++++++++++---- 1 file changed, 166 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..a4e71b3 100644 --- a/src/mesa/drivers/dri/intel/intel_screen.c +++ b/src/mesa/drivers/dri/intel/intel_screen.c @@ -31,11 +31,13 @@ #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" #include "main/version.h" #include "swrast/s_renderbuffer.h" +#include "egl/main/eglcurrent.h" #include "utils.h" #include "xmlpool.h" @@ -104,6 +106,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 +301,95 @@ intel_allocate_image(int dri_format, void *loaderPrivate) return image; } +/** + * Save appropriately-aligned base offset pointing to the image + * in addition to the x/y offsets from miptree's base address. + * The fine adjustment in pixels are derived later from the x/y + * offsets when the new texture resolves to our original image. + */ +static void +intel_image_set_level_info(__DRIimage *image, struct intel_mipmap_tree *mt, + int level, int slice) +{ + unsigned int draw_x, draw_y; + uint32_t mask_x, mask_y; + + intel_region_get_tile_masks(mt->region, &mask_x, &mask_y, false); + intel_miptree_get_image_offset(mt, level, slice, &draw_x, &draw_y); + + image->width = mt->level[level].width; + image->height = mt->level[level].height; + image->draw_x = draw_x; + image->draw_y = draw_y; + + image->offset = intel_region_get_aligned_offset(mt->region, + draw_x & ~mask_x, + draw_y & ~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 draw_x, draw_y; + + intel_miptree_check_level_layer(mt, level, zoffset); + intel_miptree_get_tile_offsets(mt, level, zoffset, &draw_x, &draw_y); + +#ifndef I915 + has_surface_tile_offset = brw_context(&intel->ctx)->has_surface_tile_offset; +#endif + if ((!has_surface_tile_offset && + (draw_x != 0 || draw_y != 0)) || + mt->stencil_mt) { + /* 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 + */ + return false; + } + + intel_image_set_level_info(image, mt, level, zoffset); + 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->draw_x = 0; + image->draw_y = 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 MESA_FORMAT_NONE; +} + static __DRIimage * intel_create_image_from_name(__DRIscreen *screen, int width, int height, int format, @@ -317,6 +412,8 @@ intel_create_image_from_name(__DRIscreen *screen, return NULL; } + intel_setup_image_from_dimensions(image); + return image; } @@ -346,26 +443,68 @@ 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) { + _eglError(EGL_BAD_PARAMETER, __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)) { + _eglError(EGL_BAD_PARAMETER, __func__); + return NULL; + } + + if (level < obj->BaseLevel || level > obj->_MaxLevel) { + _eglError(EGL_BAD_MATCH, __func__); + return NULL; + } + + if (target == GL_TEXTURE_3D && obj->Image[face][level]->Depth < zoffset) { + _eglError(EGL_BAD_MATCH, __func__); + return NULL; + } + image = calloc(1, sizeof *image); + if (image == NULL) { + _eglError(EGL_BAD_ALLOC, __func__); + 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, __func__); + free(image); + return NULL; + } + image->dri_format = intel_dri_format(image->format); + if (image->dri_format == MESA_FORMAT_NONE) { + fprintf(stderr, "%s: Cannot make EGL image from invalid format.\n", __func__); + free(image); + return NULL; } return image; @@ -405,6 +544,8 @@ intel_create_image(__DRIscreen *screen, return NULL; } + intel_setup_image_from_dimensions(image); + return image; } @@ -459,6 +600,10 @@ 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->draw_x = orig_image->draw_x; + image->draw_y = orig_image->draw_y; image->data = loaderPrivate; memcpy(image->strides, orig_image->strides, sizeof(image->strides)); @@ -587,7 +732,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