+static void
+panfrost_tile_texture(struct panfrost_screen *screen, struct panfrost_resource *rsrc, int level)
+{
+ struct panfrost_bo *bo = (struct panfrost_bo *)rsrc->bo;
+ int bytes_per_pixel = util_format_get_blocksize(rsrc->base.format);
+ int stride = bytes_per_pixel * rsrc->base.width0; /* TODO: Alignment? */
+
+ int width = rsrc->base.width0 >> level;
+ int height = rsrc->base.height0 >> level;
+
+ /* Estimate swizzled bitmap size. Slight overestimates are fine.
+ * Underestimates will result in memory corruption or worse. */
+
+ int swizzled_sz = panfrost_swizzled_size(width, height, bytes_per_pixel);
+
+ /* Allocate the transfer given that known size but do not copy */
+ struct pb_slab_entry *entry = pb_slab_alloc(&screen->slabs, swizzled_sz, HEAP_TEXTURE);
+ struct panfrost_memory_entry *p_entry = (struct panfrost_memory_entry *) entry;
+ struct panfrost_memory *backing = (struct panfrost_memory *) entry->slab;
+ uint8_t *swizzled = backing->cpu + p_entry->offset;
+
+ /* Save the entry. But if there was already an entry here (from a
+ * previous upload of the resource), free that one so we don't leak */
+
+ if (bo->entry[level] != NULL) {
+ bo->entry[level]->freed = true;
+ pb_slab_free(&screen->slabs, &bo->entry[level]->base);
+ }
+
+ bo->entry[level] = p_entry;
+ bo->gpu[level] = backing->gpu + p_entry->offset;
+
+ /* Run actual texture swizzle, writing directly to the mapped
+ * GPU chunk we allocated */
+
+ panfrost_texture_swizzle(width, height, bytes_per_pixel, stride, bo->cpu[level], swizzled);
+}
+
+static void
+panfrost_unmap_bo(struct panfrost_context *ctx,
+ struct pipe_transfer *transfer)
+{
+ struct panfrost_bo *bo = (struct panfrost_bo *)pan_resource(transfer->resource)->bo;
+
+ if (transfer->usage & PIPE_TRANSFER_WRITE) {
+ if (transfer->resource->target == PIPE_TEXTURE_2D) {
+ struct panfrost_resource *prsrc = (struct panfrost_resource *) transfer->resource;
+
+ /* Gallium thinks writeback happens here; instead, this is our cue to tile */
+ if (bo->has_afbc) {
+ printf("Warning: writes to afbc surface can't possibly work out well for you...\n");
+ } else if (bo->tiled) {
+ struct pipe_context *gallium = (struct pipe_context *) ctx;
+ struct panfrost_screen *screen = pan_screen(gallium->screen);
+ panfrost_tile_texture(screen, prsrc, transfer->level);
+ }
+ }
+ }
+}
+