+ if (image->planar_format && image->planar_format->nplanes > 0)
+ mt = create_mt_for_planar_dri_image(brw, target, image);
+ else
+ mt = create_mt_for_dri_image(brw, target, image);
+ if (mt == NULL)
+ return;
+
+ struct intel_texture_object *intel_texobj = intel_texture_object(texObj);
+ intel_texobj->planar_format = image->planar_format;
+
+ const GLenum internal_format =
+ image->internal_format != 0 ?
+ image->internal_format : _mesa_get_format_base_format(mt->format);
+ intel_set_texture_image_mt(brw, texImage, internal_format, mt);
+ intel_miptree_release(&mt);
+}
+
+/**
+ * \brief A fast path for glGetTexImage.
+ *
+ * \see intel_readpixels_tiled_memcpy()
+ */
+bool
+intel_gettexsubimage_tiled_memcpy(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing)
+{
+ struct brw_context *brw = brw_context(ctx);
+ struct intel_texture_image *image = intel_texture_image(texImage);
+ int dst_pitch;
+
+ /* The miptree's buffer. */
+ struct brw_bo *bo;
+
+ uint32_t cpp;
+ mem_copy_fn mem_copy = NULL;
+
+ /* 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 destination stride
+ * with _mesa_image_row_stride. However, before removing the restrictions
+ * we need tests.
+ */
+ if (!brw->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->Alignment > 4 ||
+ packing->SkipPixels > 0 ||
+ packing->SkipRows > 0 ||
+ (packing->RowLength != 0 && packing->RowLength != width) ||
+ packing->SwapBytes ||
+ packing->LsbFirst ||
+ packing->Invert)
+ return false;
+
+ /* We can't handle copying from RGBX or BGRX because the tiled_memcpy
+ * 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->_BaseFormat == GL_RGB)
+ return false;
+
+ if (!intel_get_memcpy(texImage->TexFormat, format, type, &mem_copy, &cpp))
+ 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->tiling != I915_TILING_X &&
+ image->mt->tiling != I915_TILING_Y)) {
+ /* 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 (brw->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->logical_depth0 == 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_READ | MAP_RAW);
+ if (map == NULL) {
+ DBG("%s: failed to map bo\n", __func__);
+ return false;
+ }
+
+ dst_pitch = _mesa_image_row_stride(packing, width, format, type);
+
+ DBG("%s: level=%d x,y=(%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)\n",
+ __func__, texImage->Level, xoffset, yoffset, width, height,
+ format, type, texImage->TexFormat, image->mt->tiling,
+ packing->Alignment, packing->RowLength, packing->SkipPixels,
+ packing->SkipRows);
+
+ /* Adjust x and y offset based on miplevel */
+ xoffset += image->mt->level[level].level_x;
+ yoffset += image->mt->level[level].level_y;
+
+ tiled_to_linear(
+ xoffset * cpp, (xoffset + width) * cpp,
+ yoffset, yoffset + height,
+ pixels - (ptrdiff_t) yoffset * dst_pitch - (ptrdiff_t) xoffset * cpp,
+ map,
+ dst_pitch, image->mt->pitch,
+ brw->has_swizzling,
+ image->mt->tiling,
+ mem_copy
+ );
+
+ brw_bo_unmap(bo);
+ return true;
+}
+
+static void
+intel_get_tex_sub_image(struct gl_context *ctx,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLint depth,
+ GLenum format, GLenum type, GLvoid *pixels,
+ struct gl_texture_image *texImage)
+{
+ struct brw_context *brw = brw_context(ctx);
+ bool ok;
+
+ 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);
+ return;
+ }
+
+ perf_debug("%s: fallback to CPU mapping in PBO case\n", __func__);
+ }
+
+ ok = intel_gettexsubimage_tiled_memcpy(ctx, texImage, xoffset, yoffset,
+ width, height,
+ format, type, pixels, &ctx->Pack);
+
+ if(ok)
+ return;
+
+ _mesa_meta_GetTexSubImage(ctx, xoffset, yoffset, zoffset,
+ width, height, depth,
+ format, type, pixels, texImage);
+
+ 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;
+ if (brw->gen == 9 && is_linear_astc)
+ flush_astc_denorms(ctx, dims, texImage,
+ xoffset, yoffset, zoffset,
+ width, height, depth);