X-Git-Url: https://git.libre-soc.org/?p=mesa.git;a=blobdiff_plain;f=src%2Fmesa%2Fdrivers%2Fdri%2Fi965%2Fintel_tex_image.c;h=c0a4a9c2ca9163364830fe1201266f37c393a35c;hp=93a8cdee0cba3fbe77b8ae7961467b016f7b319d;hb=6c11a7994dd8937035f4f9e49b63dd18b015bce6;hpb=6a7ca4ef2cd3f39d3b5e77051cb3f3175e9e60df diff --git a/src/mesa/drivers/dri/i965/intel_tex_image.c b/src/mesa/drivers/dri/i965/intel_tex_image.c index 93a8cdee0cb..c0a4a9c2ca9 100644 --- a/src/mesa/drivers/dri/i965/intel_tex_image.c +++ b/src/mesa/drivers/dri/i965/intel_tex_image.c @@ -1,11 +1,11 @@ -#include "main/glheader.h" #include "main/macros.h" #include "main/mtypes.h" #include "main/enums.h" #include "main/bufferobj.h" #include "main/context.h" #include "main/formats.h" +#include "main/glformats.h" #include "main/image.h" #include "main/pbo.h" #include "main/renderbuffer.h" @@ -14,6 +14,7 @@ #include "main/texobj.h" #include "main/teximage.h" #include "main/texstore.h" +#include "main/glthread.h" #include "drivers/common/meta.h" @@ -21,14 +22,29 @@ #include "intel_buffer_objects.h" #include "intel_batchbuffer.h" #include "intel_tex.h" -#include "intel_blit.h" #include "intel_fbo.h" #include "intel_image.h" -#include "intel_tiled_memcpy.h" #include "brw_context.h" +#include "brw_blorp.h" #define FILE_DEBUG_FLAG DEBUG_TEXTURE +/* Make sure one doesn't end up shrinking base level zero unnecessarily. + * Determining the base level dimension by shifting higher level dimension + * ends up in off-by-one value in case base level has NPOT size (for example, + * 293 != 146 << 1). + * Choose the original base level dimension when shifted dimensions agree. + * Otherwise assume real resize is intended and use the new shifted value. + */ +static unsigned +get_base_dim(unsigned old_base_dim, unsigned new_level_dim, unsigned level) +{ + const unsigned old_level_dim = old_base_dim >> level; + const unsigned new_base_dim = new_level_dim << level; + + return old_level_dim == new_level_dim ? old_base_dim : new_base_dim; +} + /* Work back from the specified level of the image to the baselevel and create a * miptree of that size. */ @@ -36,24 +52,52 @@ struct intel_mipmap_tree * intel_miptree_create_for_teximage(struct brw_context *brw, struct intel_texture_object *intelObj, struct intel_texture_image *intelImage, - uint32_t layout_flags) + enum intel_miptree_create_flags flags) { GLuint lastLevel; int width, height, depth; - GLuint i; - - intel_miptree_get_dimensions_for_image(&intelImage->base.Base, - &width, &height, &depth); + unsigned old_width = 0, old_height = 0, old_depth = 0; + const struct intel_mipmap_tree *old_mt = intelObj->mt; + const unsigned level = intelImage->base.Base.Level; + + intel_get_image_dims(&intelImage->base.Base, &width, &height, &depth); + + if (old_mt) { + old_width = old_mt->surf.logical_level0_px.width; + old_height = old_mt->surf.logical_level0_px.height; + old_depth = old_mt->surf.dim == ISL_SURF_DIM_3D ? + old_mt->surf.logical_level0_px.depth : + old_mt->surf.logical_level0_px.array_len; + } DBG("%s\n", __func__); /* Figure out image dimensions at start level. */ - for (i = intelImage->base.Base.Level; i > 0; i--) { - width <<= 1; - if (height != 1) - height <<= 1; - if (depth != 1) - depth <<= 1; + 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 = old_mt ? get_base_dim(old_depth, depth, level) : + 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 = old_mt ? get_base_dim(old_height, height, level) : + height << level; + /* Fall through */ + case GL_TEXTURE_1D: + case GL_TEXTURE_1D_ARRAY: + width = old_mt ? get_base_dim(old_width, width, level) : + width << level; + break; + default: + unreachable("Unexpected target"); } /* Guess a reasonable value for lastLevel. This is probably going @@ -79,10 +123,235 @@ intel_miptree_create_for_teximage(struct brw_context *brw, width, height, depth, - intelImage->base.Base.NumSamples, - layout_flags | MIPTREE_LAYOUT_TILING_ANY); + MAX2(intelImage->base.Base.NumSamples, 1), + flags); } +static bool +intel_texsubimage_blorp(struct brw_context *brw, GLuint dims, + struct gl_texture_image *tex_image, + unsigned x, unsigned y, unsigned z, + unsigned width, unsigned height, unsigned depth, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *packing) +{ + struct intel_texture_image *intel_image = intel_texture_image(tex_image); + const unsigned mt_level = tex_image->Level + tex_image->TexObject->MinLevel; + const unsigned mt_z = tex_image->TexObject->MinLayer + tex_image->Face + z; + + /* The blorp path can't understand crazy format hackery */ + if (_mesa_base_tex_format(&brw->ctx, tex_image->InternalFormat) != + _mesa_get_format_base_format(tex_image->TexFormat)) + return false; + + return brw_blorp_upload_miptree(brw, intel_image->mt, tex_image->TexFormat, + mt_level, x, y, mt_z, width, height, depth, + tex_image->TexObject->Target, format, type, + pixels, packing); +} + +/** + * \brief A fast path for glTexImage and glTexSubImage. + * + * This fast path is taken when the texture format is BGRA, RGBA, + * A or L and when the texture memory is X- or Y-tiled. It uploads + * the texture data by mapping the texture memory without a GTT fence, thus + * acquiring a tiled view of the memory, and then copying sucessive + * spans within each tile. + * + * This is a performance win over the conventional texture upload path because + * it avoids the performance penalty of writing through the write-combine + * buffer. In the conventional texture upload path, + * texstore.c:store_texsubimage(), the texture memory is mapped through a GTT + * fence, thus acquiring a linear view of the memory, then each row in the + * image is memcpy'd. In this fast path, we replace each row's copy with + * a sequence of copies over each linear span in tile. + * + * One use case is Google Chrome's paint rectangles. Chrome (as + * of version 21) renders each page as a tiling of 256x256 GL_BGRA textures. + * Each page's content is initially uploaded with glTexImage2D and damaged + * regions are updated with glTexSubImage2D. On some workloads, the + * performance gain of this fastpath on Sandybridge is over 5x. + */ +static bool +intel_texsubimage_tiled_memcpy(struct gl_context * ctx, + GLuint dims, + struct gl_texture_image *texImage, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing) +{ + struct brw_context *brw = brw_context(ctx); + const struct gen_device_info *devinfo = &brw->screen->devinfo; + struct intel_texture_image *image = intel_texture_image(texImage); + int src_pitch; + + /* The miptree's buffer. */ + struct brw_bo *bo; + + uint32_t cpp; + isl_memcpy_type copy_type; + + /* This fastpath is restricted to specific texture types: + * a 2D BGRA, RGBA, L8 or A8 texture. It could be generalized to support + * more types. + * + * FINISHME: The restrictions below on packing alignment and packing row + * length are likely unneeded now because we calculate the source stride + * with _mesa_image_row_stride. However, before removing the restrictions + * we need tests. + */ + if (!devinfo->has_llc || + !(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT_8_8_8_8_REV) || + !(texImage->TexObject->Target == GL_TEXTURE_2D || + texImage->TexObject->Target == GL_TEXTURE_RECTANGLE) || + pixels == NULL || + packing->BufferObj || + packing->Alignment > 4 || + packing->SkipPixels > 0 || + packing->SkipRows > 0 || + (packing->RowLength != 0 && packing->RowLength != width) || + packing->SwapBytes || + packing->LsbFirst || + packing->Invert) + return false; + + /* Only a simple blit, no scale, bias or other mapping. */ + if (ctx->_ImageTransferState) + return false; + + copy_type = intel_miptree_get_memcpy_type(texImage->TexFormat, format, type, + &cpp); + if (copy_type == ISL_MEMCPY_INVALID) + return false; + + /* If this is a nontrivial texture view, let another path handle it instead. */ + if (texImage->TexObject->MinLayer) + return false; + + if (!image->mt || + (image->mt->surf.tiling != ISL_TILING_X && + image->mt->surf.tiling != ISL_TILING_Y0)) { + /* The algorithm is written only for X- or Y-tiled memory. */ + return false; + } + + /* linear_to_tiled() assumes that if the object is swizzled, it is using + * I915_BIT6_SWIZZLE_9_10 for X and I915_BIT6_SWIZZLE_9 for Y. This is only + * true on gen5 and above. + * + * The killer on top is that some gen4 have an L-shaped swizzle mode, where + * parts of the memory aren't swizzled at all. Userspace just can't handle + * that. + */ + if (devinfo->gen < 5 && brw->has_swizzling) + return false; + + int level = texImage->Level + texImage->TexObject->MinLevel; + + /* Since we are going to write raw data to the miptree, we need to resolve + * any pending fast color clears before we start. + */ + assert(image->mt->surf.logical_level0_px.depth == 1); + assert(image->mt->surf.logical_level0_px.array_len == 1); + + intel_miptree_access_raw(brw, image->mt, level, 0, true); + + bo = image->mt->bo; + + if (brw_batch_references(&brw->batch, bo)) { + perf_debug("Flushing before mapping a referenced bo.\n"); + intel_batchbuffer_flush(brw); + } + + void *map = brw_bo_map(brw, bo, MAP_WRITE | MAP_RAW); + if (map == NULL) { + DBG("%s: failed to map bo\n", __func__); + return false; + } + + src_pitch = _mesa_image_row_stride(packing, width, format, type); + + /* We postponed printing this message until having committed to executing + * the function. + */ + DBG("%s: level=%d offset=(%d,%d) (w,h)=(%d,%d) format=0x%x type=0x%x " + "mesa_format=0x%x tiling=%d " + "packing=(alignment=%d row_length=%d skip_pixels=%d skip_rows=%d) ", + __func__, texImage->Level, xoffset, yoffset, width, height, + format, type, texImage->TexFormat, image->mt->surf.tiling, + packing->Alignment, packing->RowLength, packing->SkipPixels, + packing->SkipRows); + + /* Adjust x and y offset based on miplevel */ + unsigned level_x, level_y; + intel_miptree_get_image_offset(image->mt, level, 0, &level_x, &level_y); + xoffset += level_x; + yoffset += level_y; + + isl_memcpy_linear_to_tiled( + xoffset * cpp, (xoffset + width) * cpp, + yoffset, yoffset + height, + map, + pixels, + image->mt->surf.row_pitch_B, src_pitch, + brw->has_swizzling, + image->mt->surf.tiling, + copy_type + ); + + brw_bo_unmap(bo); + return true; +} + + +static void +intel_upload_tex(struct gl_context * ctx, + GLuint dims, + struct gl_texture_image *texImage, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + const GLvoid * pixels, + const struct gl_pixelstore_attrib *packing) +{ + struct brw_context *brw = brw_context(ctx); + struct intel_mipmap_tree *mt = intel_texture_image(texImage)->mt; + bool ok; + + /* Check that there is actually data to store. */ + if (pixels == NULL && !packing->BufferObj) + return; + + bool tex_busy = mt && + (brw_batch_references(&brw->batch, mt->bo) || brw_bo_busy(mt->bo)); + + if (packing->BufferObj || tex_busy || + mt->aux_usage == ISL_AUX_USAGE_CCS_E) { + ok = intel_texsubimage_blorp(brw, dims, texImage, + xoffset, yoffset, zoffset, + width, height, depth, format, type, + pixels, packing); + if (ok) + return; + } + + ok = intel_texsubimage_tiled_memcpy(ctx, dims, texImage, + xoffset, yoffset, zoffset, + width, height, depth, + format, type, pixels, packing); + if (ok) + return; + + _mesa_store_texsubimage(ctx, dims, texImage, + xoffset, yoffset, zoffset, + width, height, depth, + format, type, pixels, packing); +} + + static void intelTexImage(struct gl_context * ctx, GLuint dims, @@ -90,11 +359,6 @@ intelTexImage(struct gl_context * ctx, GLenum format, GLenum type, const void *pixels, const struct gl_pixelstore_attrib *unpack) { - struct intel_texture_image *intelImage = intel_texture_image(texImage); - bool ok; - - bool tex_busy = intelImage->mt && drm_intel_bo_busy(intelImage->mt->bo); - DBG("%s mesa_format %s target %s format %s type %s level %d %dx%dx%d\n", __func__, _mesa_get_format_name(texImage->TexFormat), _mesa_enum_to_string(texImage->TexObject->Target), @@ -107,100 +371,65 @@ intelTexImage(struct gl_context * ctx, return; } - assert(intelImage->mt); + assert(intel_texture_image(texImage)->mt); - ok = _mesa_meta_pbo_TexSubImage(ctx, dims, texImage, 0, 0, 0, - texImage->Width, texImage->Height, - texImage->Depth, - format, type, pixels, - false /*allocate_storage*/, - tex_busy, unpack); - if (ok) - return; + intel_upload_tex(ctx, dims, texImage, 0, 0, 0, + texImage->Width, texImage->Height, texImage->Depth, + format, type, pixels, unpack); +} - ok = intel_texsubimage_tiled_memcpy(ctx, dims, texImage, - 0, 0, 0, /*x,y,z offsets*/ - texImage->Width, - texImage->Height, - texImage->Depth, - format, type, pixels, unpack, - false /*allocate_storage*/); - if (ok) - return; - DBG("%s: upload image %dx%dx%d pixels %p\n", - __func__, texImage->Width, texImage->Height, texImage->Depth, - pixels); +static void +intelTexSubImage(struct gl_context * ctx, + GLuint dims, + struct gl_texture_image *texImage, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + const GLvoid * pixels, + const struct gl_pixelstore_attrib *packing) +{ + DBG("%s mesa_format %s target %s format %s type %s level %d %dx%dx%d\n", + __func__, _mesa_get_format_name(texImage->TexFormat), + _mesa_enum_to_string(texImage->TexObject->Target), + _mesa_enum_to_string(format), _mesa_enum_to_string(type), + texImage->Level, texImage->Width, texImage->Height, texImage->Depth); - _mesa_store_teximage(ctx, dims, texImage, - format, type, pixels, unpack); + intel_upload_tex(ctx, dims, texImage, xoffset, yoffset, zoffset, + width, height, depth, format, type, pixels, packing); } -/** - * Binds a BO to a texture image, as if it was uploaded by glTexImage2D(). - * - * Used for GLX_EXT_texture_from_pixmap and EGL image extensions, - */ static void -intel_set_texture_image_bo(struct gl_context *ctx, +intel_set_texture_image_mt(struct brw_context *brw, struct gl_texture_image *image, - drm_intel_bo *bo, - GLenum target, - GLenum internalFormat, + GLenum internal_format, mesa_format format, - uint32_t offset, - GLuint width, GLuint height, - GLuint pitch, - GLuint tile_x, GLuint tile_y, - uint32_t layout_flags) + struct intel_mipmap_tree *mt) + { - struct brw_context *brw = brw_context(ctx); - struct intel_texture_image *intel_image = intel_texture_image(image); struct gl_texture_object *texobj = image->TexObject; struct intel_texture_object *intel_texobj = intel_texture_object(texobj); - uint32_t draw_x, draw_y; + struct intel_texture_image *intel_image = intel_texture_image(image); _mesa_init_teximage_fields(&brw->ctx, image, - width, height, 1, - 0, internalFormat, format); - - ctx->Driver.FreeTextureImageBuffer(ctx, image); - - intel_image->mt = intel_miptree_create_for_bo(brw, bo, image->TexFormat, - 0, width, height, 1, pitch, - layout_flags); - if (intel_image->mt == NULL) - return; - intel_image->mt->target = target; - intel_image->mt->total_width = width; - intel_image->mt->total_height = height; - intel_image->mt->level[0].slice[0].x_offset = tile_x; - intel_image->mt->level[0].slice[0].y_offset = tile_y; - - intel_miptree_get_tile_offsets(intel_image->mt, 0, 0, &draw_x, &draw_y); - - /* From "OES_EGL_image" error reporting. We report GL_INVALID_OPERATION - * for EGL images from non-tile aligned sufaces in gen4 hw and earlier which has - * trouble resolving back to destination image due to alignment issues. - */ - if (!brw->has_surface_tile_offset && - (draw_x != 0 || draw_y != 0)) { - _mesa_error(ctx, GL_INVALID_OPERATION, __func__); - intel_miptree_release(&intel_image->mt); - return; - } + mt->surf.logical_level0_px.width, + mt->surf.logical_level0_px.height, 1, + 0, internal_format, format); + + brw->ctx.Driver.FreeTextureImageBuffer(&brw->ctx, image); intel_texobj->needs_validate = true; + intel_image->base.RowStride = mt->surf.row_pitch_B / mt->cpp; + assert(mt->surf.row_pitch_B % mt->cpp == 0); - intel_image->mt->offset = offset; - assert(pitch % intel_image->mt->cpp == 0); - intel_image->base.RowStride = pitch / intel_image->mt->cpp; + intel_miptree_reference(&intel_image->mt, mt); /* Immediately validate the image to the object. */ - intel_miptree_reference(&intel_texobj->mt, intel_image->mt); + intel_miptree_reference(&intel_texobj->mt, mt); } + void intelSetTexBuffer2(__DRIcontext *pDRICtx, GLint target, GLint texture_format, @@ -212,8 +441,10 @@ intelSetTexBuffer2(__DRIcontext *pDRICtx, GLint target, struct intel_renderbuffer *rb; struct gl_texture_object *texObj; struct gl_texture_image *texImage; - int level = 0, internalFormat = 0; mesa_format texFormat = MESA_FORMAT_NONE; + GLenum internal_format = 0; + + _mesa_glthread_finish(ctx); texObj = _mesa_get_current_tex_object(ctx, target); @@ -231,32 +462,102 @@ intelSetTexBuffer2(__DRIcontext *pDRICtx, GLint target, if (!rb || !rb->mt) return; + /* Neither the EGL and GLX texture_from_pixmap specs say anything about + * sRGB. They are both from a time where sRGB was considered an extra + * encoding step you did as part of rendering/blending and not a format. + * Even though we have concept of sRGB visuals, X has classically assumed + * that your data is just bits and sRGB rendering is entirely a client-side + * rendering construct. The assumption is that the result of BindTexImage + * is a texture with a linear format even if it was rendered with sRGB + * encoding enabled. + */ + texFormat = _mesa_get_srgb_format_linear(intel_rb_format(rb)); + if (rb->mt->cpp == 4) { - if (texture_format == __DRI_TEXTURE_FORMAT_RGB) { - internalFormat = GL_RGB; - texFormat = MESA_FORMAT_B8G8R8X8_UNORM; - } - else { - internalFormat = GL_RGBA; - texFormat = MESA_FORMAT_B8G8R8A8_UNORM; - } + /* The extra texture_format parameter indicates whether the alpha + * channel should be respected or ignored. If we set internal_format to + * GL_RGB, the texture handling code is smart enough to swap the format + * or apply a swizzle if the underlying format is RGBA so we don't need + * to stomp it to RGBX or anything like that. + */ + if (texture_format == __DRI_TEXTURE_FORMAT_RGB) + internal_format = GL_RGB; + else + internal_format = GL_RGBA; } else if (rb->mt->cpp == 2) { - internalFormat = GL_RGB; - texFormat = MESA_FORMAT_B5G6R5_UNORM; + internal_format = GL_RGB; } + intel_miptree_finish_external(brw, rb->mt); + _mesa_lock_texture(&brw->ctx, texObj); - texImage = _mesa_get_tex_image(ctx, texObj, target, level); - intel_miptree_make_shareable(brw, rb->mt); - intel_set_texture_image_bo(ctx, texImage, rb->mt->bo, target, - internalFormat, texFormat, 0, - rb->Base.Base.Width, - rb->Base.Base.Height, - rb->mt->pitch, - 0, 0, 0); + texImage = _mesa_get_tex_image(ctx, texObj, target, 0); + intel_set_texture_image_mt(brw, texImage, internal_format, + texFormat, rb->mt); _mesa_unlock_texture(&brw->ctx, texObj); } +void +intelReleaseTexBuffer(__DRIcontext *pDRICtx, GLint target, + __DRIdrawable *dPriv) +{ + struct brw_context *brw = pDRICtx->driverPrivate; + struct gl_context *ctx = &brw->ctx; + struct gl_texture_object *tex_obj; + struct intel_texture_object *intel_tex; + + tex_obj = _mesa_get_current_tex_object(ctx, target); + if (!tex_obj) + return; + + _mesa_lock_texture(&brw->ctx, tex_obj); + + intel_tex = intel_texture_object(tex_obj); + if (!intel_tex->mt) { + _mesa_unlock_texture(&brw->ctx, tex_obj); + return; + } + + /* The intel_miptree_prepare_external below as well as the finish_external + * above in intelSetTexBuffer2 *should* do nothing. The BindTexImage call + * from both GLX and EGL has TexImage2D and not TexSubImage2D semantics so + * the texture is not immutable. This means that the user cannot create a + * texture view of the image with a different format. Since the only three + * formats available when using BindTexImage are all UNORM, we can never + * end up with an sRGB format being used for texturing and so we shouldn't + * get any format-related resolves when texturing from it. + * + * While very unlikely, it is possible that the client could use the bound + * texture with GL_ARB_image_load_store. In that case, we'll do a resolve + * but that's not actually a problem as it just means that we lose + * compression on this texture until the next time it's used as a render + * target. + * + * The only other way we could end up with an unexpected aux usage would be + * if we rendered to the image from the same context as we have it bound as + * a texture between BindTexImage and ReleaseTexImage. However, the spec + * clearly calls this case out and says you shouldn't do that. It doesn't + * explicitly prevent binding the texture to a framebuffer but it says the + * results of trying to render to it while bound are undefined. + * + * Just to keep everything safe and sane, we do a prepare_external but it + * should be a no-op in almost all cases. On the off chance that someone + * ever triggers this, we should at least warn them. + */ + if (intel_tex->mt->aux_buf && + intel_miptree_get_aux_state(intel_tex->mt, 0, 0) != + isl_drm_modifier_get_default_aux_state(intel_tex->mt->drm_modifier)) { + _mesa_warning(ctx, "Aux state changed between BindTexImage and " + "ReleaseTexImage. Most likely someone tried to draw " + "to the pixmap bound in BindTexImage or used it with " + "image_load_store."); + } + + intel_miptree_prepare_external(brw, intel_tex->mt); + + _mesa_unlock_texture(&brw->ctx, tex_obj); +} + static GLboolean intel_bind_renderbuffer_tex_image(struct gl_context *ctx, struct gl_renderbuffer *rb, @@ -302,31 +603,22 @@ intelSetTexBuffer(__DRIcontext *pDRICtx, GLint target, __DRIdrawable *dPriv) } static void -intel_image_target_texture_2d(struct gl_context *ctx, GLenum target, - struct gl_texture_object *texObj, - struct gl_texture_image *texImage, - GLeglImageOES image_handle) +intel_image_target_texture(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage, + GLeglImageOES image_handle, + bool storage) { struct brw_context *brw = brw_context(ctx); - __DRIscreen *screen; + struct intel_mipmap_tree *mt; + __DRIscreen *dri_screen = brw->screen->driScrnPriv; __DRIimage *image; - screen = brw->intelScreen->driScrnPriv; - image = screen->dri2.image->lookupEGLImage(screen, image_handle, - screen->loaderPrivate); + image = dri_screen->dri2.image->lookupEGLImage(dri_screen, image_handle, + dri_screen->loaderPrivate); if (image == NULL) return; - /* We support external textures only for EGLImages created with - * EGL_EXT_image_dma_buf_import. We may lift that restriction in the future. - */ - if (target == GL_TEXTURE_EXTERNAL_OES && !image->dma_buf_imported) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glEGLImageTargetTexture2DOES(external target is enabled only " - "for images created with EGL_EXT_image_dma_buf_import"); - return; - } - /* Disallow depth/stencil textures: we don't have a way to pass the * separate stencil miptree of a GL_DEPTH_STENCIL texture through. */ @@ -335,18 +627,95 @@ intel_image_target_texture_2d(struct gl_context *ctx, GLenum target, return; } - /* Disable creation of the texture's aux buffers because the driver exposes - * no EGL API to manage them. That is, there is no API for resolving the aux - * buffer's content to the main buffer nor for invalidating the aux buffer's - * content. + mt = intel_miptree_create_for_dri_image(brw, image, target, image->format, + false); + if (mt == NULL) + return; + + struct intel_texture_object *intel_texobj = intel_texture_object(texObj); + intel_texobj->planar_format = image->planar_format; + intel_texobj->yuv_color_space = image->yuv_color_space; + + GLenum internal_format = + image->internal_format != 0 ? + image->internal_format : _mesa_get_format_base_format(mt->format); + + /* Fix the internal format when _mesa_get_format_base_format(mt->format) + * isn't a valid one for that particular format. + */ + if (brw->mesa_format_supports_render[image->format]) { + if (image->format == MESA_FORMAT_R10G10B10A2_UNORM || + image->format == MESA_FORMAT_R10G10B10X2_UNORM || + image->format == MESA_FORMAT_B10G10R10A2_UNORM || + image->format == MESA_FORMAT_B10G10R10X2_UNORM) + internal_format = GL_RGB10_A2; + } + + /* Guess sized internal format for dma-bufs, as specified by + * EXT_EGL_image_storage. */ - intel_set_texture_image_bo(ctx, texImage, image->bo, - target, image->internal_format, - image->format, image->offset, - image->width, image->height, - image->pitch, - image->tile_x, image->tile_y, - MIPTREE_LAYOUT_DISABLE_AUX); + if (storage && target == GL_TEXTURE_2D && image->imported_dmabuf) { + internal_format = driGLFormatToSizedInternalGLFormat(image->format); + if (internal_format == GL_NONE) { + _mesa_error(ctx, GL_INVALID_OPERATION, __func__); + return; + } + } + + intel_set_texture_image_mt(brw, texImage, internal_format, mt->format, mt); + intel_miptree_release(&mt); +} + +static void +intel_image_target_texture_2d(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage, + GLeglImageOES image_handle) +{ + intel_image_target_texture(ctx, target, texObj, texImage, image_handle, + false); +} + +static void +intel_image_target_tex_storage(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage, + GLeglImageOES image_handle) +{ + struct intel_texture_object *intel_texobj = intel_texture_object(texObj); + intel_image_target_texture(ctx, target, texObj, texImage, image_handle, + true); + + /* The miptree is in a validated state, so no need to check later. */ + intel_texobj->needs_validate = false; + intel_texobj->validated_first_level = 0; + intel_texobj->validated_last_level = 0; + intel_texobj->_Format = texImage->TexFormat; +} + +static bool +intel_gettexsubimage_blorp(struct brw_context *brw, + struct gl_texture_image *tex_image, + unsigned x, unsigned y, unsigned z, + unsigned width, unsigned height, unsigned depth, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *packing) +{ + struct intel_texture_image *intel_image = intel_texture_image(tex_image); + const unsigned mt_level = tex_image->Level + tex_image->TexObject->MinLevel; + const unsigned mt_z = tex_image->TexObject->MinLayer + tex_image->Face + z; + + /* The blorp path can't understand crazy format hackery */ + if (_mesa_base_tex_format(&brw->ctx, tex_image->InternalFormat) != + _mesa_get_format_base_format(tex_image->TexFormat)) + return false; + + return brw_blorp_download_miptree(brw, intel_image->mt, + tex_image->TexFormat, SWIZZLE_XYZW, + mt_level, x, y, mt_z, + width, height, depth, + tex_image->TexObject->Target, + format, type, false, pixels, packing); } /** @@ -354,7 +723,7 @@ intel_image_target_texture_2d(struct gl_context *ctx, GLenum target, * * \see intel_readpixels_tiled_memcpy() */ -bool +static bool intel_gettexsubimage_tiled_memcpy(struct gl_context *ctx, struct gl_texture_image *texImage, GLint xoffset, GLint yoffset, @@ -364,16 +733,15 @@ intel_gettexsubimage_tiled_memcpy(struct gl_context *ctx, const struct gl_pixelstore_attrib *packing) { struct brw_context *brw = brw_context(ctx); + const struct gen_device_info *devinfo = &brw->screen->devinfo; struct intel_texture_image *image = intel_texture_image(texImage); int dst_pitch; /* The miptree's buffer. */ - drm_intel_bo *bo; - - int error = 0; + struct brw_bo *bo; uint32_t cpp; - mem_copy_fn mem_copy = NULL; + isl_memcpy_type copy_type; /* This fastpath is restricted to specific texture types: * a 2D BGRA, RGBA, L8 or A8 texture. It could be generalized to support @@ -384,12 +752,12 @@ intel_gettexsubimage_tiled_memcpy(struct gl_context *ctx, * with _mesa_image_row_stride. However, before removing the restrictions * we need tests. */ - if (!brw->has_llc || + if (!devinfo->has_llc || !(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT_8_8_8_8_REV) || !(texImage->TexObject->Target == GL_TEXTURE_2D || texImage->TexObject->Target == GL_TEXTURE_RECTANGLE) || pixels == NULL || - _mesa_is_bufferobj(packing->BufferObj) || + packing->BufferObj || packing->Alignment > 4 || packing->SkipPixels > 0 || packing->SkipRows > 0 || @@ -400,14 +768,16 @@ intel_gettexsubimage_tiled_memcpy(struct gl_context *ctx, return false; /* We can't handle copying from RGBX or BGRX because the tiled_memcpy - * function doesn't set the last channel to 1. + * function doesn't set the last channel to 1. Note this checks BaseFormat + * rather than TexFormat in case the RGBX format is being simulated with an + * RGBA format. */ - if (texImage->TexFormat == MESA_FORMAT_B8G8R8X8_UNORM || - texImage->TexFormat == MESA_FORMAT_R8G8B8X8_UNORM) + if (texImage->_BaseFormat == GL_RGB) return false; - if (!intel_get_memcpy(texImage->TexFormat, format, type, &mem_copy, &cpp, - INTEL_DOWNLOAD)) + copy_type = intel_miptree_get_memcpy_type(texImage->TexFormat, format, type, + &cpp); + if (copy_type == ISL_MEMCPY_INVALID) return false; /* If this is a nontrivial texture view, let another path handle it instead. */ @@ -415,26 +785,42 @@ intel_gettexsubimage_tiled_memcpy(struct gl_context *ctx, return false; if (!image->mt || - (image->mt->tiling != I915_TILING_X && - image->mt->tiling != I915_TILING_Y)) { + (image->mt->surf.tiling != ISL_TILING_X && + image->mt->surf.tiling != ISL_TILING_Y0)) { /* The algorithm is written only for X- or Y-tiled memory. */ return false; } + /* tiled_to_linear() assumes that if the object is swizzled, it is using + * I915_BIT6_SWIZZLE_9_10 for X and I915_BIT6_SWIZZLE_9 for Y. This is only + * true on gen5 and above. + * + * The killer on top is that some gen4 have an L-shaped swizzle mode, where + * parts of the memory aren't swizzled at all. Userspace just can't handle + * that. + */ + if (devinfo->gen < 5 && brw->has_swizzling) + return false; + + int level = texImage->Level + texImage->TexObject->MinLevel; + /* Since we are going to write raw data to the miptree, we need to resolve * any pending fast color clears before we start. */ - intel_miptree_resolve_color(brw, image->mt); + assert(image->mt->surf.logical_level0_px.depth == 1); + assert(image->mt->surf.logical_level0_px.array_len == 1); + + intel_miptree_access_raw(brw, image->mt, level, 0, true); bo = image->mt->bo; - if (drm_intel_bo_references(brw->batch.bo, bo)) { + if (brw_batch_references(&brw->batch, bo)) { perf_debug("Flushing before mapping a referenced bo.\n"); intel_batchbuffer_flush(brw); } - error = brw_bo_map(brw, bo, false /* write enable */, "miptree"); - if (error) { + void *map = brw_bo_map(brw, bo, MAP_READ | MAP_RAW); + if (map == NULL) { DBG("%s: failed to map bo\n", __func__); return false; } @@ -445,28 +831,28 @@ intel_gettexsubimage_tiled_memcpy(struct gl_context *ctx, "mesa_format=0x%x tiling=%d " "packing=(alignment=%d row_length=%d skip_pixels=%d skip_rows=%d)\n", __func__, texImage->Level, xoffset, yoffset, width, height, - format, type, texImage->TexFormat, image->mt->tiling, + format, type, texImage->TexFormat, image->mt->surf.tiling, packing->Alignment, packing->RowLength, packing->SkipPixels, packing->SkipRows); - int level = texImage->Level + texImage->TexObject->MinLevel; - /* Adjust x and y offset based on miplevel */ - xoffset += image->mt->level[level].level_x; - yoffset += image->mt->level[level].level_y; + unsigned level_x, level_y; + intel_miptree_get_image_offset(image->mt, level, 0, &level_x, &level_y); + xoffset += level_x; + yoffset += level_y; - tiled_to_linear( + isl_memcpy_tiled_to_linear( xoffset * cpp, (xoffset + width) * cpp, yoffset, yoffset + height, - pixels - (ptrdiff_t) yoffset * dst_pitch - (ptrdiff_t) xoffset * cpp, - bo->virtual, - dst_pitch, image->mt->pitch, + pixels, + map, + dst_pitch, image->mt->surf.row_pitch_B, brw->has_swizzling, - image->mt->tiling, - mem_copy + image->mt->surf.tiling, + copy_type ); - drm_intel_bo_unmap(bo); + brw_bo_unmap(bo); return true; } @@ -482,19 +868,12 @@ intel_get_tex_sub_image(struct gl_context *ctx, DBG("%s\n", __func__); - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - if (_mesa_meta_pbo_GetTexSubImage(ctx, 3, texImage, - xoffset, yoffset, zoffset, - width, height, depth, format, type, - pixels, &ctx->Pack)) { - /* Flush to guarantee coherency between the render cache and other - * caches the PBO could potentially be bound to after this point. - * See the related comment in intelReadPixels() for a more detailed - * explanation. - */ - brw_emit_mi_flush(brw); + if (ctx->Pack.BufferObj) { + if (intel_gettexsubimage_blorp(brw, texImage, + xoffset, yoffset, zoffset, + width, height, depth, format, type, + pixels, &ctx->Pack)) return; - } perf_debug("%s: fallback to CPU mapping in PBO case\n", __func__); } @@ -513,11 +892,100 @@ intel_get_tex_sub_image(struct gl_context *ctx, DBG("%s - DONE\n", __func__); } +static void +flush_astc_denorms(struct gl_context *ctx, GLuint dims, + struct gl_texture_image *texImage, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth) +{ + struct compressed_pixelstore store; + _mesa_compute_compressed_pixelstore(dims, texImage->TexFormat, + width, height, depth, + &ctx->Unpack, &store); + + for (int slice = 0; slice < store.CopySlices; slice++) { + + /* Map dest texture buffer */ + GLubyte *dstMap; + GLint dstRowStride; + ctx->Driver.MapTextureImage(ctx, texImage, slice + zoffset, + xoffset, yoffset, width, height, + GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, + &dstMap, &dstRowStride); + if (!dstMap) + continue; + + for (int i = 0; i < store.CopyRowsPerSlice; i++) { + + /* An ASTC block is stored in little endian mode. The byte that + * contains bits 0..7 is stored at the lower address in memory. + */ + struct astc_void_extent { + uint16_t header : 12; + uint16_t dontcare[3]; + uint16_t R; + uint16_t G; + uint16_t B; + uint16_t A; + } *blocks = (struct astc_void_extent*) dstMap; + + /* Iterate over every copied block in the row */ + for (int j = 0; j < store.CopyBytesPerRow / 16; j++) { + + /* Check if the header matches that of an LDR void-extent block */ + if (blocks[j].header == 0xDFC) { + + /* Flush UNORM16 values that would be denormalized */ + if (blocks[j].A < 4) blocks[j].A = 0; + if (blocks[j].B < 4) blocks[j].B = 0; + if (blocks[j].G < 4) blocks[j].G = 0; + if (blocks[j].R < 4) blocks[j].R = 0; + } + } + + dstMap += dstRowStride; + } + + ctx->Driver.UnmapTextureImage(ctx, texImage, slice + zoffset); + } +} + + +static void +intelCompressedTexSubImage(struct gl_context *ctx, GLuint dims, + struct gl_texture_image *texImage, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, + GLsizei imageSize, const GLvoid *data) +{ + /* Upload the compressed data blocks */ + _mesa_store_compressed_texsubimage(ctx, dims, texImage, + xoffset, yoffset, zoffset, + width, height, depth, + format, imageSize, data); + + /* Fix up copied ASTC blocks if necessary */ + GLenum gl_format = _mesa_compressed_format_to_glenum(ctx, + texImage->TexFormat); + bool is_linear_astc = _mesa_is_astc_format(gl_format) && + !_mesa_is_srgb_format(gl_format); + struct brw_context *brw = (struct brw_context*) ctx; + const struct gen_device_info *devinfo = &brw->screen->devinfo; + if (devinfo->gen == 9 && !gen_device_info_is_9lp(devinfo) && is_linear_astc) + flush_astc_denorms(ctx, dims, texImage, + xoffset, yoffset, zoffset, + width, height, depth); +} + void intelInitTextureImageFuncs(struct dd_function_table *functions) { functions->TexImage = intelTexImage; + functions->TexSubImage = intelTexSubImage; + functions->CompressedTexSubImage = intelCompressedTexSubImage; functions->EGLImageTargetTexture2D = intel_image_target_texture_2d; + functions->EGLImageTargetTexStorage = intel_image_target_tex_storage; functions->BindRenderbufferTexImage = intel_bind_renderbuffer_tex_image; functions->GetTexSubImage = intel_get_tex_sub_image; }