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