1 /*
2 * Copyright (C) 2020 Collabora Ltd.
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 #include "pan_context.h"
25 #include "util/u_vbuf.h"
26
27 void
panfrost_analyze_sysvals(struct panfrost_shader_state * ss)28 panfrost_analyze_sysvals(struct panfrost_shader_state *ss)
29 {
30 unsigned dirty = 0;
31 unsigned dirty_shader = PAN_DIRTY_STAGE_SHADER | PAN_DIRTY_STAGE_CONST;
32
33 for (unsigned i = 0; i < ss->info.sysvals.sysval_count; ++i) {
34 switch (PAN_SYSVAL_TYPE(ss->info.sysvals.sysvals[i])) {
35 case PAN_SYSVAL_VIEWPORT_SCALE:
36 case PAN_SYSVAL_VIEWPORT_OFFSET:
37 dirty |= PAN_DIRTY_VIEWPORT;
38 break;
39
40 case PAN_SYSVAL_TEXTURE_SIZE:
41 dirty_shader |= PAN_DIRTY_STAGE_TEXTURE;
42 break;
43
44 case PAN_SYSVAL_SSBO:
45 dirty_shader |= PAN_DIRTY_STAGE_SSBO;
46 break;
47
48 case PAN_SYSVAL_XFB:
49 dirty |= PAN_DIRTY_SO;
50 break;
51
52 case PAN_SYSVAL_SAMPLER:
53 dirty_shader |= PAN_DIRTY_STAGE_SAMPLER;
54 break;
55
56 case PAN_SYSVAL_IMAGE_SIZE:
57 dirty_shader |= PAN_DIRTY_STAGE_IMAGE;
58 break;
59
60 case PAN_SYSVAL_NUM_WORK_GROUPS:
61 case PAN_SYSVAL_LOCAL_GROUP_SIZE:
62 case PAN_SYSVAL_WORK_DIM:
63 case PAN_SYSVAL_VERTEX_INSTANCE_OFFSETS:
64 case PAN_SYSVAL_NUM_VERTICES:
65 dirty |= PAN_DIRTY_PARAMS;
66 break;
67
68 case PAN_SYSVAL_DRAWID:
69 dirty |= PAN_DIRTY_DRAWID;
70 break;
71
72 case PAN_SYSVAL_SAMPLE_POSITIONS:
73 case PAN_SYSVAL_MULTISAMPLED:
74 case PAN_SYSVAL_RT_CONVERSION:
75 /* Nothing beyond the batch itself */
76 break;
77 default:
78 unreachable("Invalid sysval");
79 }
80 }
81
82 ss->dirty_3d = dirty;
83 ss->dirty_shader = dirty_shader;
84 }
85
86 /*
87 * Gets a GPU address for the associated index buffer. Only gauranteed to be
88 * good for the duration of the draw (transient), could last longer. Bounds are
89 * not calculated.
90 */
91 mali_ptr
panfrost_get_index_buffer(struct panfrost_batch * batch,const struct pipe_draw_info * info,const struct pipe_draw_start_count_bias * draw)92 panfrost_get_index_buffer(struct panfrost_batch *batch,
93 const struct pipe_draw_info *info,
94 const struct pipe_draw_start_count_bias *draw)
95 {
96 struct panfrost_resource *rsrc = pan_resource(info->index.resource);
97 off_t offset = draw->start * info->index_size;
98
99 if (!info->has_user_indices) {
100 /* Only resources can be directly mapped */
101 panfrost_batch_read_rsrc(batch, rsrc, PIPE_SHADER_VERTEX);
102 return rsrc->image.data.bo->ptr.gpu + offset;
103 } else {
104 /* Otherwise, we need to upload to transient memory */
105 const uint8_t *ibuf8 = (const uint8_t *) info->index.user;
106 struct panfrost_ptr T =
107 pan_pool_alloc_aligned(&batch->pool.base,
108 draw->count *
109 info->index_size,
110 info->index_size);
111
112 memcpy(T.cpu, ibuf8 + offset, draw->count * info->index_size);
113 return T.gpu;
114 }
115 }
116
117 /* Gets a GPU address for the associated index buffer. Only gauranteed to be
118 * good for the duration of the draw (transient), could last longer. Also get
119 * the bounds on the index buffer for the range accessed by the draw. We do
120 * these operations together because there are natural optimizations which
121 * require them to be together. */
122
123 mali_ptr
panfrost_get_index_buffer_bounded(struct panfrost_batch * batch,const struct pipe_draw_info * info,const struct pipe_draw_start_count_bias * draw,unsigned * min_index,unsigned * max_index)124 panfrost_get_index_buffer_bounded(struct panfrost_batch *batch,
125 const struct pipe_draw_info *info,
126 const struct pipe_draw_start_count_bias *draw,
127 unsigned *min_index, unsigned *max_index)
128 {
129 struct panfrost_resource *rsrc = pan_resource(info->index.resource);
130 struct panfrost_context *ctx = batch->ctx;
131 bool needs_indices = true;
132
133 if (info->index_bounds_valid) {
134 *min_index = info->min_index;
135 *max_index = info->max_index;
136 needs_indices = false;
137 } else if (!info->has_user_indices) {
138 /* Check the cache */
139 needs_indices = !panfrost_minmax_cache_get(rsrc->index_cache,
140 draw->start,
141 draw->count,
142 min_index,
143 max_index);
144 }
145
146 if (needs_indices) {
147 /* Fallback */
148 u_vbuf_get_minmax_index(&ctx->base, info, draw, min_index, max_index);
149
150 if (!info->has_user_indices)
151 panfrost_minmax_cache_add(rsrc->index_cache,
152 draw->start, draw->count,
153 *min_index, *max_index);
154 }
155
156 return panfrost_get_index_buffer(batch, info, draw);
157 }
158
159 /**
160 * Given an (index, divisor) tuple, assign a vertex buffer. Midgard and
161 * Bifrost put divisor information on the attribute buffer descriptor, so this
162 * is the most we can compact in general. Crucially, this runs at vertex
163 * elements CSO create time, not at draw time.
164 */
165 unsigned
pan_assign_vertex_buffer(struct pan_vertex_buffer * buffers,unsigned * nr_bufs,unsigned vbi,unsigned divisor)166 pan_assign_vertex_buffer(struct pan_vertex_buffer *buffers,
167 unsigned *nr_bufs,
168 unsigned vbi,
169 unsigned divisor)
170 {
171 /* Look up the buffer */
172 for (unsigned i = 0; i < (*nr_bufs); ++i) {
173 if (buffers[i].vbi == vbi && buffers[i].divisor == divisor)
174 return i;
175 }
176
177 /* Else, create a new buffer */
178 unsigned idx = (*nr_bufs)++;
179
180 buffers[idx] = (struct pan_vertex_buffer) {
181 .vbi = vbi,
182 .divisor = divisor
183 };
184
185 return idx;
186 }
187
188 /*
189 * Helper to add a PIPE_CLEAR_* to batch->draws and batch->resolve together,
190 * meaning that we draw to a given target. Adding to only one mask does not
191 * generally make sense, except for clears which add to batch->clear and
192 * batch->resolve together.
193 */
194 static void
panfrost_draw_target(struct panfrost_batch * batch,unsigned target)195 panfrost_draw_target(struct panfrost_batch *batch, unsigned target)
196 {
197 batch->draws |= target;
198 batch->resolve |= target;
199 }
200
201 /*
202 * Draw time helper to set batch->{read, draws, resolve} based on current blend
203 * and depth-stencil state. To be called when blend or depth/stencil dirty state
204 * respectively changes.
205 */
206 void
panfrost_set_batch_masks_blend(struct panfrost_batch * batch)207 panfrost_set_batch_masks_blend(struct panfrost_batch *batch)
208 {
209 struct panfrost_context *ctx = batch->ctx;
210 struct panfrost_blend_state *blend = ctx->blend;
211
212 for (unsigned i = 0; i < batch->key.nr_cbufs; ++i) {
213 if (!blend->info[i].no_colour && batch->key.cbufs[i])
214 panfrost_draw_target(batch, PIPE_CLEAR_COLOR0 << i);
215 }
216 }
217
218 void
panfrost_set_batch_masks_zs(struct panfrost_batch * batch)219 panfrost_set_batch_masks_zs(struct panfrost_batch *batch)
220 {
221 struct panfrost_context *ctx = batch->ctx;
222 struct pipe_depth_stencil_alpha_state *zsa = (void *) ctx->depth_stencil;
223
224 /* Assume depth is read (TODO: perf) */
225 if (zsa->depth_enabled)
226 batch->read |= PIPE_CLEAR_DEPTH;
227
228 if (zsa->depth_writemask)
229 panfrost_draw_target(batch, PIPE_CLEAR_DEPTH);
230
231 if (zsa->stencil[0].enabled) {
232 panfrost_draw_target(batch, PIPE_CLEAR_STENCIL);
233
234 /* Assume stencil is read (TODO: perf) */
235 batch->read |= PIPE_CLEAR_STENCIL;
236 }
237 }
238
239 void
panfrost_track_image_access(struct panfrost_batch * batch,enum pipe_shader_type stage,struct pipe_image_view * image)240 panfrost_track_image_access(struct panfrost_batch *batch,
241 enum pipe_shader_type stage,
242 struct pipe_image_view *image)
243 {
244 struct panfrost_resource *rsrc = pan_resource(image->resource);
245
246 if (image->shader_access & PIPE_IMAGE_ACCESS_WRITE) {
247 panfrost_batch_write_rsrc(batch, rsrc, stage);
248
249 bool is_buffer = rsrc->base.target == PIPE_BUFFER;
250 unsigned level = is_buffer ? 0 : image->u.tex.level;
251 BITSET_SET(rsrc->valid.data, level);
252
253 if (is_buffer) {
254 util_range_add(&rsrc->base, &rsrc->valid_buffer_range,
255 0, rsrc->base.width0);
256 }
257 } else {
258 panfrost_batch_read_rsrc(batch, rsrc, stage);
259 }
260 }
261
262