- /* FIXME: Looks like aligning on a tile is not enough, but
- * aligning on twice the tile size seems to works. We don't
- * know exactly what happens here but this deserves extra
- * investigation to figure it out.
- */
- batch->minx = batch->minx & ~((MALI_TILE_LENGTH * 2) - 1);
- batch->miny = batch->miny & ~((MALI_TILE_LENGTH * 2) - 1);
- batch->maxx = MIN2(ALIGN_POT(batch->maxx, MALI_TILE_LENGTH * 2),
- rsrc->base.width0);
- batch->maxy = MIN2(ALIGN_POT(batch->maxy, MALI_TILE_LENGTH * 2),
- rsrc->base.height0);
-
- struct pipe_scissor_state damage;
- struct pipe_box rects[4];
-
- /* Clamp the damage box to the rendering area. */
- damage.minx = MAX2(batch->minx, rsrc->damage.biggest_rect.x);
- damage.miny = MAX2(batch->miny, rsrc->damage.biggest_rect.y);
- damage.maxx = MIN2(batch->maxx,
- rsrc->damage.biggest_rect.x +
- rsrc->damage.biggest_rect.width);
- damage.maxy = MIN2(batch->maxy,
- rsrc->damage.biggest_rect.y +
- rsrc->damage.biggest_rect.height);
-
- /* One damage rectangle means we can end up with at most 4 reload
- * regions:
- * 1: left region, only exists if damage.x > 0
- * 2: right region, only exists if damage.x + damage.width < fb->width
- * 3: top region, only exists if damage.y > 0. The intersection with
- * the left and right regions are dropped
- * 4: bottom region, only exists if damage.y + damage.height < fb->height.
- * The intersection with the left and right regions are dropped
- *
- * ____________________________
- * | | 3 | |
- * | |___________| |
- * | | damage | |
- * | 1 | rect | 2 |
- * | |___________| |
- * | | 4 | |
- * |_______|___________|______|
- */
- u_box_2d(batch->minx, batch->miny, damage.minx - batch->minx,
- batch->maxy - batch->miny, &rects[0]);
- u_box_2d(damage.maxx, batch->miny, batch->maxx - damage.maxx,
- batch->maxy - batch->miny, &rects[1]);
- u_box_2d(damage.minx, batch->miny, damage.maxx - damage.minx,
- damage.miny - batch->miny, &rects[2]);
- u_box_2d(damage.minx, damage.maxy, damage.maxx - damage.minx,
- batch->maxy - damage.maxy, &rects[3]);
-
- for (unsigned i = 0; i < 4; i++) {
- /* Width and height are always >= 0 even if width is declared as a
- * signed integer: u_box_2d() helper takes unsigned args and
- * panfrost_set_damage_region() is taking care of clamping
- * negative values.
- */
- if (!rects[i].width || !rects[i].height)
- continue;
+ /* XXX: Native blits on Bifrost */
+ if (batch->pool.dev->quirks & IS_BIFROST) {
+ if (loc != FRAG_RESULT_DATA0)
+ return;
+
+ /* XXX: why align on *twice* the tile length? */
+ batch->minx = batch->minx & ~((MALI_TILE_LENGTH * 2) - 1);
+ batch->miny = batch->miny & ~((MALI_TILE_LENGTH * 2) - 1);
+ batch->maxx = MIN2(ALIGN_POT(batch->maxx, MALI_TILE_LENGTH * 2),
+ rsrc->base.width0);
+ batch->maxy = MIN2(ALIGN_POT(batch->maxy, MALI_TILE_LENGTH * 2),
+ rsrc->base.height0);
+
+ struct pipe_box rect;
+ batch->ctx->wallpaper_batch = batch;
+ u_box_2d(batch->minx, batch->miny, batch->maxx - batch->minx,
+ batch->maxy - batch->miny, &rect);
+ panfrost_blit_wallpaper(batch->ctx, &rect);
+ batch->ctx->wallpaper_batch = NULL;
+ return;
+ }
+
+ enum pipe_format format = rsrc->base.format;
+
+ if (loc == FRAG_RESULT_DEPTH) {
+ if (!util_format_has_depth(util_format_description(format)))
+ return;
+
+ format = util_format_get_depth_only(format);
+ } else if (loc == FRAG_RESULT_STENCIL) {
+ if (!util_format_has_stencil(util_format_description(format)))
+ return;
+
+ if (rsrc->separate_stencil) {
+ rsrc = rsrc->separate_stencil;
+ format = rsrc->base.format;
+ }
+
+ format = util_format_stencil_only(format);
+ }
+
+ enum mali_texture_dimension dim =
+ panfrost_translate_texture_dimension(rsrc->base.target);
+
+ struct pan_image img = {
+ .width0 = rsrc->base.width0,
+ .height0 = rsrc->base.height0,
+ .depth0 = rsrc->base.depth0,
+ .format = format,
+ .dim = dim,
+ .modifier = rsrc->modifier,
+ .array_size = rsrc->base.array_size,
+ .first_level = level,
+ .last_level = level,
+ .first_layer = surf->u.tex.first_layer,
+ .last_layer = surf->u.tex.last_layer,
+ .nr_samples = rsrc->base.nr_samples,
+ .cubemap_stride = rsrc->cubemap_stride,
+ .bo = rsrc->bo,
+ .slices = rsrc->slices
+ };
+
+ mali_ptr blend_shader = 0;
+
+ if (loc >= FRAG_RESULT_DATA0 && !panfrost_can_fixed_blend(rsrc->base.format)) {
+ struct panfrost_blend_shader *b =
+ panfrost_get_blend_shader(batch->ctx, &batch->ctx->blit_blend, rsrc->base.format, loc - FRAG_RESULT_DATA0);
+
+ struct panfrost_bo *bo = panfrost_batch_create_bo(batch, b->size,
+ PAN_BO_EXECUTE,
+ PAN_BO_ACCESS_PRIVATE |
+ PAN_BO_ACCESS_READ |
+ PAN_BO_ACCESS_FRAGMENT);
+
+ memcpy(bo->cpu, b->buffer, b->size);
+ assert(b->work_count <= 4);
+
+ blend_shader = bo->gpu | b->first_tag;
+ }
+
+ struct panfrost_transfer transfer = panfrost_pool_alloc_aligned(&batch->pool,
+ 4 * 4 * 6 * rsrc->damage.inverted_len, 64);
+
+ for (unsigned i = 0; i < rsrc->damage.inverted_len; ++i) {
+ float *o = (float *) (transfer.cpu + (4 * 4 * 6 * i));
+ struct pan_rect r = rsrc->damage.inverted_rects[i];