• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 Alyssa Rosenzweig
3  * Copyright (C) 2020 Collabora Ltd.
4  * Copyright © 2017 Intel Corporation
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #ifndef __PAN_CMDSTREAM_H__
27 #define __PAN_CMDSTREAM_H__
28 
29 #ifndef PAN_ARCH
30 #error "PAN_ARCH undefined!"
31 #endif
32 
33 #include "genxml/gen_macros.h"
34 
35 #include "pan_context.h"
36 #include "pan_job.h"
37 
38 #include "pipe/p_defines.h"
39 #include "pipe/p_state.h"
40 
41 #include "util/u_prim.h"
42 
43 #define PAN_GPU_SUPPORTS_DISPATCH_INDIRECT (PAN_ARCH == 7 || PAN_ARCH >= 10)
44 #define PAN_GPU_SUPPORTS_DRAW_INDIRECT     (PAN_ARCH >= 10)
45 
46 struct panfrost_rasterizer {
47    struct pipe_rasterizer_state base;
48 
49 #if PAN_ARCH <= 7
50    /* Partially packed RSD words */
51    struct mali_multisample_misc_packed multisample;
52    struct mali_stencil_mask_misc_packed stencil_misc;
53 #endif
54 };
55 
56 struct panfrost_zsa_state {
57    struct pipe_depth_stencil_alpha_state base;
58 
59    /* Is any depth, stencil, or alpha testing enabled? */
60    bool enabled;
61 
62    /* Does the depth and stencil tests always pass? This ignores write
63     * masks, we are only interested in whether pixels may be killed.
64     */
65    bool zs_always_passes;
66 
67    /* Are depth or stencil writes possible? */
68    bool writes_zs;
69 
70 #if PAN_ARCH <= 7
71    /* Prepacked words from the RSD */
72    struct mali_multisample_misc_packed rsd_depth;
73    struct mali_stencil_mask_misc_packed rsd_stencil;
74    struct mali_stencil_packed stencil_front, stencil_back;
75 #else
76    /* Depth/stencil descriptor template */
77    struct mali_depth_stencil_packed desc;
78 #endif
79 };
80 
81 struct panfrost_vertex_state {
82    unsigned num_elements;
83    struct pipe_vertex_element pipe[PIPE_MAX_ATTRIBS];
84    uint16_t strides[PIPE_MAX_ATTRIBS];
85 
86 #if PAN_ARCH >= 9
87    /* Packed attribute descriptors */
88    struct mali_attribute_packed attributes[PIPE_MAX_ATTRIBS];
89 #else
90    /* buffers corresponds to attribute buffer, element_buffers corresponds
91     * to an index in buffers for each vertex element */
92    struct pan_vertex_buffer buffers[PIPE_MAX_ATTRIBS];
93    unsigned element_buffer[PIPE_MAX_ATTRIBS];
94    unsigned nr_bufs;
95 
96    /* Bitmask flagging attributes with a non-zero instance divisor which
97     * require an attribute offset adjustment when base_instance != 0.
98     * This is used to force attributes re-emission even if the vertex state
99     * isn't dirty to take the new base instance into account. */
100    uint32_t attr_depends_on_base_instance_mask;
101 
102    unsigned formats[PIPE_MAX_ATTRIBS];
103 #endif
104 };
105 
106 static inline bool
panfrost_is_implicit_prim_restart(const struct pipe_draw_info * info)107 panfrost_is_implicit_prim_restart(const struct pipe_draw_info *info)
108 {
109    /* As a reminder primitive_restart should always be checked before any
110       access to restart_index. */
111    return info->primitive_restart &&
112           info->restart_index == (unsigned)BITFIELD_MASK(info->index_size * 8);
113 }
114 
115 static inline bool
pan_allow_forward_pixel_to_kill(struct panfrost_context * ctx,struct panfrost_compiled_shader * fs)116 pan_allow_forward_pixel_to_kill(struct panfrost_context *ctx,
117                                 struct panfrost_compiled_shader *fs)
118 {
119    /* Track if any colour buffer is reused across draws, either
120     * from reading it directly, or from failing to write it
121     */
122    unsigned rt_mask = ctx->fb_rt_mask;
123    uint64_t rt_written = (fs->info.outputs_written >> FRAG_RESULT_DATA0) &
124                          ctx->blend->enabled_mask;
125    bool blend_reads_dest = (ctx->blend->load_dest_mask & rt_mask);
126    bool alpha_to_coverage = ctx->blend->base.alpha_to_coverage;
127 
128    return fs->info.fs.can_fpk && !(rt_mask & ~rt_written) &&
129           !alpha_to_coverage && !blend_reads_dest;
130 }
131 
132 /*
133  * Determine whether to set the respective overdraw alpha flag.
134  *
135  * The overdraw alpha=1 flag should be set when alpha=1 implies full overdraw,
136  * equivalently, all enabled render targets have alpha_one_store set. Likewise,
137  * overdraw alpha=0 should be set when alpha=0 implies no overdraw,
138  * equivalently, all enabled render targets have alpha_zero_nop set.
139  */
140 #if PAN_ARCH >= 6
141 static inline bool
panfrost_overdraw_alpha(const struct panfrost_context * ctx,bool zero)142 panfrost_overdraw_alpha(const struct panfrost_context *ctx, bool zero)
143 {
144    const struct panfrost_blend_state *so = ctx->blend;
145 
146    for (unsigned i = 0; i < ctx->pipe_framebuffer.nr_cbufs; ++i) {
147       const struct pan_blend_info info = so->info[i];
148 
149       bool enabled = ctx->pipe_framebuffer.cbufs[i] && !info.enabled;
150       bool flag = zero ? info.alpha_zero_nop : info.alpha_one_store;
151 
152       if (enabled && !flag)
153          return false;
154    }
155 
156    return true;
157 }
158 #endif
159 
160 static inline void
panfrost_emit_primitive_size(struct panfrost_context * ctx,bool points,uint64_t size_array,struct mali_primitive_size_packed * prim_size)161 panfrost_emit_primitive_size(struct panfrost_context *ctx, bool points,
162                              uint64_t size_array,
163                              struct mali_primitive_size_packed *prim_size)
164 {
165    struct panfrost_rasterizer *rast = ctx->rasterizer;
166 
167    pan_pack(prim_size, PRIMITIVE_SIZE, cfg) {
168       if (panfrost_writes_point_size(ctx)) {
169          cfg.size_array = size_array;
170       } else {
171          cfg.constant = points ? rast->base.point_size : rast->base.line_width;
172       }
173    }
174 }
175 
176 static inline uint8_t
pan_draw_mode(enum mesa_prim mode)177 pan_draw_mode(enum mesa_prim mode)
178 {
179    switch (mode) {
180 
181 #define DEFINE_CASE(c)                                                         \
182    case MESA_PRIM_##c:                                                         \
183       return MALI_DRAW_MODE_##c;
184 
185       DEFINE_CASE(POINTS);
186       DEFINE_CASE(LINES);
187       DEFINE_CASE(LINE_LOOP);
188       DEFINE_CASE(LINE_STRIP);
189       DEFINE_CASE(TRIANGLES);
190       DEFINE_CASE(TRIANGLE_STRIP);
191       DEFINE_CASE(TRIANGLE_FAN);
192       DEFINE_CASE(QUADS);
193       DEFINE_CASE(POLYGON);
194 #if PAN_ARCH <= 6
195       DEFINE_CASE(QUAD_STRIP);
196 #endif
197 
198 #undef DEFINE_CASE
199 
200    default:
201       unreachable("Invalid draw mode");
202    }
203 }
204 
205 static inline enum mali_index_type
panfrost_translate_index_size(unsigned size)206 panfrost_translate_index_size(unsigned size)
207 {
208    STATIC_ASSERT(MALI_INDEX_TYPE_NONE == 0);
209    STATIC_ASSERT(MALI_INDEX_TYPE_UINT8 == 1);
210    STATIC_ASSERT(MALI_INDEX_TYPE_UINT16 == 2);
211 
212    return (size == 4) ? MALI_INDEX_TYPE_UINT32 : size;
213 }
214 
215 static inline bool
panfrost_fs_required(struct panfrost_compiled_shader * fs,struct panfrost_blend_state * blend,struct pipe_framebuffer_state * state,const struct panfrost_zsa_state * zsa)216 panfrost_fs_required(struct panfrost_compiled_shader *fs,
217                      struct panfrost_blend_state *blend,
218                      struct pipe_framebuffer_state *state,
219                      const struct panfrost_zsa_state *zsa)
220 {
221    /* If we generally have side effects. This inclues use of discard,
222     * which can affect the results of an occlusion query. */
223    if (fs->info.fs.sidefx)
224       return true;
225 
226    /* Using an empty FS requires early-z to be enabled, but alpha test
227     * needs it disabled. Alpha test is only native on Midgard, so only
228     * check there.
229     */
230    if (PAN_ARCH <= 5 && zsa->base.alpha_func != PIPE_FUNC_ALWAYS)
231       return true;
232 
233    /* If colour is written we need to execute */
234    for (unsigned i = 0; i < state->nr_cbufs; ++i) {
235       if (state->cbufs[i] && blend->info[i].enabled)
236          return true;
237    }
238 
239    /* If depth is written and not implied we need to execute.
240     * TODO: Predicate on Z/S writes being enabled */
241    return (fs->info.fs.writes_depth || fs->info.fs.writes_stencil);
242 }
243 
244 #if PAN_ARCH >= 9
245 static inline uint64_t
panfrost_get_position_shader(struct panfrost_batch * batch,const struct pipe_draw_info * info)246 panfrost_get_position_shader(struct panfrost_batch *batch,
247                              const struct pipe_draw_info *info)
248 {
249    /* IDVS/points vertex shader */
250    uint64_t vs_ptr = batch->rsd[PIPE_SHADER_VERTEX];
251 
252    /* IDVS/triangle vertex shader */
253    if (vs_ptr && info->mode != MESA_PRIM_POINTS)
254       vs_ptr += pan_size(SHADER_PROGRAM);
255 
256    return vs_ptr;
257 }
258 
259 static inline uint64_t
panfrost_get_varying_shader(struct panfrost_batch * batch)260 panfrost_get_varying_shader(struct panfrost_batch *batch)
261 {
262    return batch->rsd[PIPE_SHADER_VERTEX] + (2 * pan_size(SHADER_PROGRAM));
263 }
264 
265 static inline unsigned
panfrost_vertex_attribute_stride(struct panfrost_compiled_shader * vs,struct panfrost_compiled_shader * fs)266 panfrost_vertex_attribute_stride(struct panfrost_compiled_shader *vs,
267                                  struct panfrost_compiled_shader *fs)
268 {
269    unsigned v = vs->info.varyings.output_count;
270    unsigned f = fs->info.varyings.input_count;
271    unsigned slots = MAX2(v, f);
272    slots += util_bitcount(fs->key.fs.fixed_varying_mask);
273 
274    /* Assumes 16 byte slots. We could do better. */
275    return slots * 16;
276 }
277 
278 static inline uint64_t
panfrost_emit_resources(struct panfrost_batch * batch,enum pipe_shader_type stage)279 panfrost_emit_resources(struct panfrost_batch *batch,
280                         enum pipe_shader_type stage)
281 {
282    struct panfrost_context *ctx = batch->ctx;
283    struct panfrost_ptr T;
284    unsigned nr_tables = PAN_NUM_RESOURCE_TABLES;
285 
286    /* Although individual resources need only 16 byte alignment, the
287     * resource table as a whole must be 64-byte aligned.
288     */
289    T = pan_pool_alloc_aligned(&batch->pool.base, nr_tables * pan_size(RESOURCE),
290                               64);
291    if (!T.cpu)
292       return 0;
293 
294    memset(T.cpu, 0, nr_tables * pan_size(RESOURCE));
295 
296    panfrost_make_resource_table(T, PAN_TABLE_UBO, batch->uniform_buffers[stage],
297                                 batch->nr_uniform_buffers[stage]);
298 
299    panfrost_make_resource_table(T, PAN_TABLE_TEXTURE, batch->textures[stage],
300                                 ctx->sampler_view_count[stage]);
301 
302    /* We always need at least 1 sampler for txf to work */
303    panfrost_make_resource_table(T, PAN_TABLE_SAMPLER, batch->samplers[stage],
304                                 MAX2(ctx->sampler_count[stage], 1));
305 
306    panfrost_make_resource_table(T, PAN_TABLE_IMAGE, batch->images[stage],
307                                 util_last_bit(ctx->image_mask[stage]));
308 
309    if (stage == PIPE_SHADER_VERTEX) {
310       panfrost_make_resource_table(T, PAN_TABLE_ATTRIBUTE,
311                                    batch->attribs[stage],
312                                    ctx->vertex->num_elements);
313 
314       panfrost_make_resource_table(T, PAN_TABLE_ATTRIBUTE_BUFFER,
315                                    batch->attrib_bufs[stage],
316                                    util_last_bit(ctx->vb_mask));
317    }
318 
319    panfrost_make_resource_table(T, PAN_TABLE_SSBO, batch->ssbos[stage],
320                                 util_last_bit(ctx->ssbo_mask[stage]));
321 
322    return T.gpu | nr_tables;
323 }
324 #endif /* PAN_ARCH >= 9 */
325 
326 static bool
allow_rotating_primitives(const struct panfrost_compiled_shader * fs,const struct pipe_draw_info * info)327 allow_rotating_primitives(const struct panfrost_compiled_shader *fs,
328                           const struct pipe_draw_info *info)
329 {
330    return u_reduced_prim(info->mode) != MESA_PRIM_LINES &&
331           !fs->info.bifrost.uses_flat_shading;
332 }
333 
334 #endif
335