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_bo.h"
27 #include "pan_context.h"
28 #include "pan_util.h"
29 
30 #include "util/format/u_format.h"
31 
32 static void
panfrost_sfbd_format(struct pipe_surface * surf,struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS * fb)33 panfrost_sfbd_format(struct pipe_surface *surf,
34                      struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS *fb)
35 {
36         /* Explode details on the format */
37 
38         const struct util_format_description *desc =
39                 util_format_description(surf->format);
40 
41         /* The swizzle for rendering is inverted from texturing */
42 
43         unsigned char swizzle[4];
44         panfrost_invert_swizzle(desc->swizzle, swizzle);
45 
46         fb->swizzle = panfrost_translate_swizzle_4(swizzle);
47 
48         struct pan_blendable_format fmt = panfrost_blend_format(surf->format);
49 
50         if (fmt.internal) {
51                 fb->internal_format = fmt.internal;
52                 fb->color_writeback_format = fmt.writeback;
53         } else {
54                 unreachable("raw formats not finished for SFBD");
55         }
56 }
57 
58 static void
panfrost_sfbd_clear(struct panfrost_batch * batch,struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS * sfbd)59 panfrost_sfbd_clear(
60         struct panfrost_batch *batch,
61         struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS *sfbd)
62 {
63         if (batch->clear & PIPE_CLEAR_COLOR) {
64                 sfbd->clear_color_0 = batch->clear_color[0][0];
65                 sfbd->clear_color_1 = batch->clear_color[0][1];
66                 sfbd->clear_color_2 = batch->clear_color[0][2];
67                 sfbd->clear_color_3 = batch->clear_color[0][3];
68         }
69 
70         if (batch->clear & PIPE_CLEAR_DEPTH)
71                 sfbd->z_clear = batch->clear_depth;
72 
73         if (batch->clear & PIPE_CLEAR_STENCIL)
74                 sfbd->s_clear = batch->clear_stencil & 0xff;
75 }
76 
77 static void
panfrost_sfbd_set_cbuf(struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS * fb,struct pipe_surface * surf)78 panfrost_sfbd_set_cbuf(
79         struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS *fb,
80         struct pipe_surface *surf)
81 {
82         struct panfrost_resource *rsrc = pan_resource(surf->texture);
83 
84         unsigned level = surf->u.tex.level;
85         unsigned first_layer = surf->u.tex.first_layer;
86         assert(surf->u.tex.last_layer == first_layer);
87         signed stride = rsrc->slices[level].stride;
88 
89         mali_ptr base = panfrost_get_texture_address(rsrc, level, first_layer, 0);
90 
91         panfrost_sfbd_format(surf, fb);
92 
93         fb->color_write_enable = true;
94         fb->color_writeback.base = base;
95         fb->color_writeback.row_stride = stride;
96 
97         if (rsrc->modifier == DRM_FORMAT_MOD_LINEAR)
98                 fb->color_block_format = MALI_BLOCK_FORMAT_LINEAR;
99         else if (rsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
100                 fb->color_block_format = MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED;
101                 fb->color_writeback.row_stride *= 16;
102         } else {
103                 fprintf(stderr, "Invalid render modifier\n");
104                 assert(0);
105         }
106 }
107 
108 static void
panfrost_sfbd_set_zsbuf(struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS * fb,struct pipe_surface * surf)109 panfrost_sfbd_set_zsbuf(
110         struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS *fb,
111         struct pipe_surface *surf)
112 {
113         struct panfrost_resource *rsrc = pan_resource(surf->texture);
114 
115         unsigned level = surf->u.tex.level;
116         assert(surf->u.tex.first_layer == 0);
117 
118         if (rsrc->modifier != DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED)
119                 unreachable("Invalid render modifier.");
120 
121         fb->zs_block_format = MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED;
122         fb->zs_writeback.base = rsrc->bo->ptr.gpu + rsrc->slices[level].offset;
123         fb->zs_writeback.row_stride = rsrc->slices[level].stride * 16;
124         switch (surf->format) {
125         case PIPE_FORMAT_Z16_UNORM:
126                 fb->zs_format = MALI_ZS_FORMAT_D16;
127                 break;
128         case PIPE_FORMAT_Z24_UNORM_S8_UINT:
129                 fb->zs_format = MALI_ZS_FORMAT_D24S8;
130                 break;
131         case PIPE_FORMAT_Z24X8_UNORM:
132                 fb->zs_format = MALI_ZS_FORMAT_D24X8;
133                 break;
134         case PIPE_FORMAT_Z32_FLOAT:
135                 fb->zs_format = MALI_ZS_FORMAT_D32;
136                 break;
137         case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
138                 fb->zs_format = MALI_ZS_FORMAT_D32_S8X24;
139                 break;
140         default:
141                 unreachable("Unsupported depth/stencil format.");
142         }
143 }
144 
145 static void
panfrost_init_sfbd_params(struct panfrost_batch * batch,struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS * sfbd)146 panfrost_init_sfbd_params(struct panfrost_batch *batch,
147                           struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS *sfbd)
148 {
149         sfbd->bound_max_x = batch->key.width - 1;
150         sfbd->bound_max_y = batch->key.height - 1;
151         sfbd->dithering_enable = true;
152         sfbd->clean_pixel_write_enable = true;
153         sfbd->tie_break_rule = MALI_TIE_BREAK_RULE_MINUS_180_IN_0_OUT;
154 }
155 
156 static void
panfrost_emit_sfdb_local_storage(struct panfrost_batch * batch,void * sfbd,unsigned vertex_count)157 panfrost_emit_sfdb_local_storage(struct panfrost_batch *batch, void *sfbd,
158                                  unsigned vertex_count)
159 {
160         struct panfrost_device *dev = pan_device(batch->ctx->base.screen);
161         /* TODO: Why do we need to make the stack bigger than other platforms? */
162         unsigned shift = panfrost_get_stack_shift(MAX2(batch->stack_size, 512));
163 
164         pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, LOCAL_STORAGE, ls) {
165                 ls.tls_size = shift;
166                 ls.wls_instances = MALI_LOCAL_STORAGE_NO_WORKGROUP_MEM;
167                 ls.tls_base_pointer =
168                         panfrost_batch_get_scratchpad(batch,
169                                                       shift,
170                                                       dev->thread_tls_alloc,
171                                                       dev->core_count)->ptr.gpu;
172         }
173 }
174 
175 static void
panfrost_emit_sfdb_tiler(struct panfrost_batch * batch,void * sfbd,unsigned vertex_count)176 panfrost_emit_sfdb_tiler(struct panfrost_batch *batch, void *sfbd,
177                          unsigned vertex_count)
178 {
179         void *tiler = pan_section_ptr(sfbd, SINGLE_TARGET_FRAMEBUFFER, TILER);
180 
181         panfrost_emit_midg_tiler(batch, tiler, vertex_count);
182 
183         /* All weights set to 0, nothing to do here */
184         pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, PADDING_1, padding) {}
185         pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, TILER_WEIGHTS, w) {}
186 }
187 
188 void
panfrost_attach_sfbd(struct panfrost_batch * batch,unsigned vertex_count)189 panfrost_attach_sfbd(struct panfrost_batch *batch, unsigned vertex_count)
190 {
191         void *sfbd = batch->framebuffer.cpu;
192 
193         panfrost_emit_sfdb_local_storage(batch, sfbd, vertex_count);
194         pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, PARAMETERS, params) {
195                 panfrost_init_sfbd_params(batch, &params);
196         }
197         panfrost_emit_sfdb_tiler(batch, sfbd, vertex_count);
198         pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, PADDING_2, padding) {}
199 }
200 
201 /* Creates an SFBD for the FRAGMENT section of the bound framebuffer */
202 
203 mali_ptr
panfrost_sfbd_fragment(struct panfrost_batch * batch,bool has_draws)204 panfrost_sfbd_fragment(struct panfrost_batch *batch, bool has_draws)
205 {
206         struct panfrost_ptr t =
207                 panfrost_pool_alloc_aligned(&batch->pool,
208                                             MALI_SINGLE_TARGET_FRAMEBUFFER_LENGTH,
209                                             64);
210         void *sfbd = t.cpu;
211 
212         panfrost_emit_sfdb_local_storage(batch, sfbd, has_draws);
213         pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, PARAMETERS, params) {
214                 panfrost_init_sfbd_params(batch, &params);
215                 panfrost_sfbd_clear(batch, &params);
216 
217                 /* SFBD does not support MRT natively; sanity check */
218                 assert(batch->key.nr_cbufs <= 1);
219                 if (batch->key.nr_cbufs) {
220                         struct pipe_surface *surf = batch->key.cbufs[0];
221                         struct panfrost_resource *rsrc = pan_resource(surf->texture);
222                         struct panfrost_bo *bo = rsrc->bo;
223 
224                         panfrost_sfbd_set_cbuf(&params, surf);
225 
226                         if (rsrc->checksummed) {
227                                 unsigned level = surf->u.tex.level;
228                                 struct panfrost_slice *slice = &rsrc->slices[level];
229 
230                                 params.crc_buffer.row_stride = slice->checksum_stride;
231                                 params.crc_buffer.base = bo->ptr.gpu + slice->checksum_offset;
232                         }
233                 }
234 
235                 if (batch->key.zsbuf)
236                         panfrost_sfbd_set_zsbuf(&params, batch->key.zsbuf);
237 
238                 if (batch->requirements & PAN_REQ_MSAA) {
239                         /* Only 4x MSAA supported right now. */
240                         params.sample_count = 4;
241                         params.msaa = MALI_MSAA_MULTIPLE;
242                 }
243         }
244         panfrost_emit_sfdb_tiler(batch, sfbd, has_draws);
245         pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, PADDING_2, padding) {}
246 
247         return t.gpu;
248 }
249