1 /*
2 * Copyright (C) 2019-2020 Collabora, Ltd.
3 * Copyright 2018-2019 Alyssa Rosenzweig
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 */
25
26 #include "pan_context.h"
27 #include "pan_util.h"
28 #include "panfrost-quirks.h"
29
30 #include "util/format/u_format.h"
31
32 /* Mark a surface as written */
33
34 static void
panfrost_initialize_surface(struct panfrost_batch * batch,struct pipe_surface * surf)35 panfrost_initialize_surface(
36 struct panfrost_batch *batch,
37 struct pipe_surface *surf)
38 {
39 if (!surf)
40 return;
41
42 unsigned level = surf->u.tex.level;
43 struct panfrost_resource *rsrc = pan_resource(surf->texture);
44
45 rsrc->slices[level].initialized = true;
46 }
47
48 /* Generate a fragment job. This should be called once per frame. (According to
49 * presentations, this is supposed to correspond to eglSwapBuffers) */
50
51 mali_ptr
panfrost_fragment_job(struct panfrost_batch * batch,bool has_draws)52 panfrost_fragment_job(struct panfrost_batch *batch, bool has_draws)
53 {
54 struct panfrost_device *dev = pan_device(batch->ctx->base.screen);
55
56 mali_ptr framebuffer = (dev->quirks & MIDGARD_SFBD) ?
57 panfrost_sfbd_fragment(batch, has_draws) :
58 panfrost_mfbd_fragment(batch, has_draws);
59
60 /* Mark the affected buffers as initialized, since we're writing to it.
61 * Also, add the surfaces we're writing to to the batch */
62
63 struct pipe_framebuffer_state *fb = &batch->key;
64
65 for (unsigned i = 0; i < fb->nr_cbufs; ++i) {
66 panfrost_initialize_surface(batch, fb->cbufs[i]);
67 }
68
69 if (fb->zsbuf)
70 panfrost_initialize_surface(batch, fb->zsbuf);
71
72 /* The passed tile coords can be out of range in some cases, so we need
73 * to clamp them to the framebuffer size to avoid a TILE_RANGE_FAULT.
74 * Theoretically we also need to clamp the coordinates positive, but we
75 * avoid that edge case as all four values are unsigned. Also,
76 * theoretically we could clamp the minima, but if that has to happen
77 * the asserts would fail anyway (since the maxima would get clamped
78 * and then be smaller than the minima). An edge case of sorts occurs
79 * when no scissors are added to draw, so by default min=~0 and max=0.
80 * But that can't happen if any actual drawing occurs (beyond a
81 * wallpaper reload), so this is again irrelevant in practice. */
82
83 batch->maxx = MIN2(batch->maxx, fb->width);
84 batch->maxy = MIN2(batch->maxy, fb->height);
85
86 /* Rendering region must be at least 1x1; otherwise, there is nothing
87 * to do and the whole job chain should have been discarded. */
88
89 assert(batch->maxx > batch->minx);
90 assert(batch->maxy > batch->miny);
91
92 struct panfrost_ptr transfer =
93 panfrost_pool_alloc_aligned(&batch->pool,
94 MALI_FRAGMENT_JOB_LENGTH, 64);
95
96 pan_section_pack(transfer.cpu, FRAGMENT_JOB, HEADER, header) {
97 header.type = MALI_JOB_TYPE_FRAGMENT;
98 header.index = 1;
99 }
100
101 pan_section_pack(transfer.cpu, FRAGMENT_JOB, PAYLOAD, payload) {
102 payload.bound_min_x = batch->minx >> MALI_TILE_SHIFT;
103 payload.bound_min_y = batch->miny >> MALI_TILE_SHIFT;
104
105 /* Batch max values are inclusive, we need to subtract 1. */
106 payload.bound_max_x = (batch->maxx - 1) >> MALI_TILE_SHIFT;
107 payload.bound_max_y = (batch->maxy - 1) >> MALI_TILE_SHIFT;
108 payload.framebuffer = framebuffer;
109 }
110
111 return transfer.gpu;
112 }
113