panfrost: Fix alignment on Bifrost
[mesa.git] / src / gallium / drivers / panfrost / pan_sfbd.c
1 /*
2 * Copyright 2018-2019 Alyssa Rosenzweig
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 */
24
25 #include "pan_bo.h"
26 #include "pan_context.h"
27 #include "pan_util.h"
28
29 #include "util/format/u_format.h"
30
31 static struct mali_sfbd_format
32 panfrost_sfbd_format(struct pipe_surface *surf)
33 {
34 /* Explode details on the format */
35
36 const struct util_format_description *desc =
37 util_format_description(surf->format);
38
39 /* The swizzle for rendering is inverted from texturing */
40
41 unsigned char swizzle[4];
42 panfrost_invert_swizzle(desc->swizzle, swizzle);
43
44 struct mali_sfbd_format fmt = {
45 .unk1 = 0x1,
46 .swizzle = panfrost_translate_swizzle_4(swizzle),
47 .nr_channels = MALI_POSITIVE(desc->nr_channels),
48 .unk2 = 0x4,
49 .unk3 = 0xb,
50 };
51
52 if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
53 fmt.unk2 |= MALI_SFBD_FORMAT_SRGB;
54
55 /* sRGB handled as a dedicated flag */
56 enum pipe_format linearized = util_format_linear(surf->format);
57
58 /* If RGB, we're good to go */
59 if (util_format_is_unorm8(desc))
60 return fmt;
61
62 switch (linearized) {
63 case PIPE_FORMAT_B5G6R5_UNORM:
64 fmt.unk1 = 0x5;
65 fmt.nr_channels = MALI_POSITIVE(2);
66 fmt.unk2 = 0x5;
67 break;
68
69 case PIPE_FORMAT_A4B4G4R4_UNORM:
70 case PIPE_FORMAT_B4G4R4A4_UNORM:
71 case PIPE_FORMAT_R4G4B4A4_UNORM:
72 fmt.unk1 = 0x4;
73 fmt.nr_channels = MALI_POSITIVE(1);
74 fmt.unk2 = 0x5;
75 break;
76
77 default:
78 unreachable("Invalid format rendering");
79 }
80
81 return fmt;
82 }
83
84 static void
85 panfrost_sfbd_clear(
86 struct panfrost_batch *batch,
87 struct mali_single_framebuffer *sfbd)
88 {
89 if (batch->clear & PIPE_CLEAR_COLOR) {
90 sfbd->clear_color_1 = batch->clear_color[0][0];
91 sfbd->clear_color_2 = batch->clear_color[0][1];
92 sfbd->clear_color_3 = batch->clear_color[0][2];
93 sfbd->clear_color_4 = batch->clear_color[0][3];
94 }
95
96 if (batch->clear & PIPE_CLEAR_DEPTH) {
97 sfbd->clear_depth_1 = batch->clear_depth;
98 sfbd->clear_depth_2 = batch->clear_depth;
99 sfbd->clear_depth_3 = batch->clear_depth;
100 sfbd->clear_depth_4 = batch->clear_depth;
101 }
102
103 if (batch->clear & PIPE_CLEAR_STENCIL) {
104 sfbd->clear_stencil = batch->clear_stencil;
105 }
106
107 /* Set flags based on what has been cleared, for the SFBD case */
108 /* XXX: What do these flags mean? */
109 int clear_flags = 0x101100;
110
111 if (!(batch->clear & ~(PIPE_CLEAR_COLOR | PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) {
112 /* On a tiler like this, it's fastest to clear all three buffers at once */
113
114 clear_flags |= MALI_CLEAR_FAST;
115 } else {
116 clear_flags |= MALI_CLEAR_SLOW;
117
118 if (batch->clear & PIPE_CLEAR_STENCIL)
119 clear_flags |= MALI_CLEAR_SLOW_STENCIL;
120 }
121
122 sfbd->clear_flags = clear_flags;
123 }
124
125 static void
126 panfrost_sfbd_set_cbuf(
127 struct mali_single_framebuffer *fb,
128 struct pipe_surface *surf)
129 {
130 struct panfrost_resource *rsrc = pan_resource(surf->texture);
131
132 unsigned level = surf->u.tex.level;
133 unsigned first_layer = surf->u.tex.first_layer;
134 assert(surf->u.tex.last_layer == first_layer);
135 signed stride = rsrc->slices[level].stride;
136
137 mali_ptr base = panfrost_get_texture_address(rsrc, level, first_layer, 0);
138
139 fb->format = panfrost_sfbd_format(surf);
140
141 fb->framebuffer = base;
142 fb->stride = stride;
143
144 if (rsrc->modifier == DRM_FORMAT_MOD_LINEAR)
145 fb->format.block = MALI_BLOCK_FORMAT_LINEAR;
146 else if (rsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
147 fb->format.block = MALI_BLOCK_FORMAT_TILED;
148 fb->stride *= 16;
149 } else {
150 fprintf(stderr, "Invalid render modifier\n");
151 assert(0);
152 }
153 }
154
155 static void
156 panfrost_sfbd_set_zsbuf(
157 struct mali_single_framebuffer *fb,
158 struct pipe_surface *surf)
159 {
160 struct panfrost_resource *rsrc = pan_resource(surf->texture);
161 struct panfrost_context *ctx = pan_context(surf->context);
162
163 unsigned level = surf->u.tex.level;
164 assert(surf->u.tex.first_layer == 0);
165
166 if (rsrc->modifier != DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED)
167 unreachable("Invalid render modifier.");
168
169 fb->depth_buffer = rsrc->bo->gpu + rsrc->slices[level].offset;
170 fb->depth_stride = rsrc->slices[level].stride;
171
172 /* No stencil? Job done. */
173 if (!ctx->depth_stencil || !ctx->depth_stencil->base.stencil[0].enabled)
174 return;
175
176 if (panfrost_is_z24s8_variant(surf->format)) {
177 /* Stencil data is interleaved with depth */
178 fb->stencil_buffer = fb->depth_buffer;
179 fb->stencil_stride = fb->depth_stride;
180 } else if (surf->format == PIPE_FORMAT_Z32_FLOAT) {
181 /* No stencil, nothing to do */
182 } else if (surf->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
183 /* Stencil data in separate buffer */
184 struct panfrost_resource *stencil = rsrc->separate_stencil;
185 struct panfrost_slice stencil_slice = stencil->slices[level];
186
187 fb->stencil_buffer = stencil->bo->gpu + stencil_slice.offset;
188 fb->stencil_stride = stencil_slice.stride;
189 } else
190 unreachable("Unsupported depth/stencil format.");
191 }
192
193
194 static struct mali_single_framebuffer
195 panfrost_emit_sfbd(struct panfrost_batch *batch, unsigned vertex_count)
196 {
197 struct panfrost_context *ctx = batch->ctx;
198 struct pipe_context *gallium = (struct pipe_context *) ctx;
199 struct panfrost_device *dev = pan_device(gallium->screen);
200
201 unsigned width = batch->key.width;
202 unsigned height = batch->key.height;
203
204 /* TODO: Why do we need to make the stack bigger than other platforms? */
205 unsigned shift = panfrost_get_stack_shift(MAX2(batch->stack_size, 512));
206
207 struct mali_single_framebuffer framebuffer = {
208 .width = MALI_POSITIVE(width),
209 .height = MALI_POSITIVE(height),
210 .shared_memory = {
211 .stack_shift = shift,
212 .shared_workgroup_count = ~0,
213 .scratchpad = panfrost_batch_get_scratchpad(batch, shift, dev->thread_tls_alloc, dev->core_count)->gpu,
214 },
215 .format = {
216 .unk3 = 0x3,
217 },
218 .clear_flags = 0x1000,
219 .tiler = panfrost_emit_midg_tiler(batch, vertex_count),
220 };
221
222 return framebuffer;
223 }
224
225 void
226 panfrost_attach_sfbd(struct panfrost_batch *batch, unsigned vertex_count)
227 {
228 struct mali_single_framebuffer sfbd =
229 panfrost_emit_sfbd(batch, vertex_count);
230
231 memcpy(batch->framebuffer.cpu, &sfbd, sizeof(sfbd));
232 }
233
234 /* Creates an SFBD for the FRAGMENT section of the bound framebuffer */
235
236 mali_ptr
237 panfrost_sfbd_fragment(struct panfrost_batch *batch, bool has_draws)
238 {
239 struct mali_single_framebuffer fb = panfrost_emit_sfbd(batch, has_draws);
240
241 panfrost_sfbd_clear(batch, &fb);
242
243 /* SFBD does not support MRT natively; sanity check */
244 assert(batch->key.nr_cbufs <= 1);
245 if (batch->key.nr_cbufs) {
246 struct pipe_surface *surf = batch->key.cbufs[0];
247 struct panfrost_resource *rsrc = pan_resource(surf->texture);
248 struct panfrost_bo *bo = rsrc->bo;
249
250 panfrost_sfbd_set_cbuf(&fb, surf);
251
252 if (rsrc->checksummed) {
253 unsigned level = surf->u.tex.level;
254 struct panfrost_slice *slice = &rsrc->slices[level];
255
256 fb.checksum_stride = slice->checksum_stride;
257 fb.checksum = bo->gpu + slice->checksum_offset;
258 }
259 }
260
261 if (batch->key.zsbuf)
262 panfrost_sfbd_set_zsbuf(&fb, batch->key.zsbuf);
263
264 if (batch->requirements & PAN_REQ_MSAA) {
265 fb.format.unk1 |= MALI_SFBD_FORMAT_MSAA_A;
266 fb.format.unk2 |= MALI_SFBD_FORMAT_MSAA_B;
267 }
268
269 return panfrost_pool_upload_aligned(&batch->pool, &fb, sizeof(fb), 64);
270 }