2 * Copyright 2018-2019 Alyssa Rosenzweig
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:
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
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
26 #include "pan_context.h"
29 #include "util/format/u_format.h"
31 static struct mali_sfbd_format
32 panfrost_sfbd_format(struct pipe_surface
*surf
)
34 /* Explode details on the format */
36 const struct util_format_description
*desc
=
37 util_format_description(surf
->format
);
39 /* The swizzle for rendering is inverted from texturing */
41 unsigned char swizzle
[4];
42 panfrost_invert_swizzle(desc
->swizzle
, swizzle
);
44 struct mali_sfbd_format fmt
= {
46 .swizzle
= panfrost_translate_swizzle_4(swizzle
),
47 .nr_channels
= MALI_POSITIVE(desc
->nr_channels
),
52 if (desc
->colorspace
== UTIL_FORMAT_COLORSPACE_SRGB
)
53 fmt
.unk2
|= MALI_SFBD_FORMAT_SRGB
;
55 /* sRGB handled as a dedicated flag */
56 enum pipe_format linearized
= util_format_linear(surf
->format
);
58 /* If RGB, we're good to go */
59 if (util_format_is_unorm8(desc
))
63 case PIPE_FORMAT_B5G6R5_UNORM
:
65 fmt
.nr_channels
= MALI_POSITIVE(2);
69 case PIPE_FORMAT_A4B4G4R4_UNORM
:
70 case PIPE_FORMAT_B4G4R4A4_UNORM
:
71 case PIPE_FORMAT_R4G4B4A4_UNORM
:
73 fmt
.nr_channels
= MALI_POSITIVE(1);
78 unreachable("Invalid format rendering");
86 struct panfrost_batch
*batch
,
87 struct mali_single_framebuffer
*sfbd
)
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];
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
;
103 if (batch
->clear
& PIPE_CLEAR_STENCIL
) {
104 sfbd
->clear_stencil
= batch
->clear_stencil
;
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;
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 */
114 clear_flags
|= MALI_CLEAR_FAST
;
116 clear_flags
|= MALI_CLEAR_SLOW
;
118 if (batch
->clear
& PIPE_CLEAR_STENCIL
)
119 clear_flags
|= MALI_CLEAR_SLOW_STENCIL
;
122 sfbd
->clear_flags
= clear_flags
;
126 panfrost_sfbd_set_cbuf(
127 struct mali_single_framebuffer
*fb
,
128 struct pipe_surface
*surf
)
130 struct panfrost_resource
*rsrc
= pan_resource(surf
->texture
);
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
;
137 mali_ptr base
= panfrost_get_texture_address(rsrc
, level
, first_layer
, 0);
139 fb
->format
= panfrost_sfbd_format(surf
);
141 fb
->framebuffer
= base
;
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
;
150 fprintf(stderr
, "Invalid render modifier\n");
156 panfrost_sfbd_set_zsbuf(
157 struct mali_single_framebuffer
*fb
,
158 struct pipe_surface
*surf
)
160 struct panfrost_resource
*rsrc
= pan_resource(surf
->texture
);
161 struct panfrost_context
*ctx
= pan_context(surf
->context
);
163 unsigned level
= surf
->u
.tex
.level
;
164 assert(surf
->u
.tex
.first_layer
== 0);
166 if (rsrc
->modifier
!= DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED
)
167 unreachable("Invalid render modifier.");
169 fb
->depth_buffer
= rsrc
->bo
->gpu
+ rsrc
->slices
[level
].offset
;
170 fb
->depth_stride
= rsrc
->slices
[level
].stride
;
172 /* No stencil? Job done. */
173 if (!ctx
->depth_stencil
|| !ctx
->depth_stencil
->base
.stencil
[0].enabled
)
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
];
187 fb
->stencil_buffer
= stencil
->bo
->gpu
+ stencil_slice
.offset
;
188 fb
->stencil_stride
= stencil_slice
.stride
;
190 unreachable("Unsupported depth/stencil format.");
194 static struct mali_single_framebuffer
195 panfrost_emit_sfbd(struct panfrost_batch
*batch
, unsigned vertex_count
)
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
);
201 unsigned width
= batch
->key
.width
;
202 unsigned height
= batch
->key
.height
;
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));
207 struct mali_single_framebuffer framebuffer
= {
208 .width
= MALI_POSITIVE(width
),
209 .height
= MALI_POSITIVE(height
),
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
,
218 .clear_flags
= 0x1000,
219 .tiler
= panfrost_emit_midg_tiler(batch
, vertex_count
),
226 panfrost_attach_sfbd(struct panfrost_batch
*batch
, unsigned vertex_count
)
228 struct mali_single_framebuffer sfbd
=
229 panfrost_emit_sfbd(batch
, vertex_count
);
231 memcpy(batch
->framebuffer
.cpu
, &sfbd
, sizeof(sfbd
));
234 /* Creates an SFBD for the FRAGMENT section of the bound framebuffer */
237 panfrost_sfbd_fragment(struct panfrost_batch
*batch
, bool has_draws
)
239 struct mali_single_framebuffer fb
= panfrost_emit_sfbd(batch
, has_draws
);
241 panfrost_sfbd_clear(batch
, &fb
);
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
;
250 panfrost_sfbd_set_cbuf(&fb
, surf
);
252 if (rsrc
->checksummed
) {
253 unsigned level
= surf
->u
.tex
.level
;
254 struct panfrost_slice
*slice
= &rsrc
->slices
[level
];
256 fb
.checksum_stride
= slice
->checksum_stride
;
257 fb
.checksum
= bo
->gpu
+ slice
->checksum_offset
;
261 if (batch
->key
.zsbuf
)
262 panfrost_sfbd_set_zsbuf(&fb
, batch
->key
.zsbuf
);
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
;
269 return panfrost_pool_upload_aligned(&batch
->pool
, &fb
, sizeof(fb
), 64);