1 /*
2 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
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 * Authors:
24 * Rob Clark <robclark@freedesktop.org>
25 */
26
27 #ifndef FREEDRENO_RESOURCE_H_
28 #define FREEDRENO_RESOURCE_H_
29
30 #include "util/list.h"
31 #include "util/simple_mtx.h"
32 #include "util/u_dump.h"
33 #include "util/u_range.h"
34 #include "util/u_transfer_helper.h"
35
36 #include "freedreno/fdl/freedreno_layout.h"
37 #include "freedreno_batch.h"
38 #include "freedreno_util.h"
39
40 BEGINC;
41
42 #define PRSC_FMT \
43 "p: target=%s, format=%s, %ux%ux%u, " \
44 "array_size=%u, last_level=%u, " \
45 "nr_samples=%u, usage=%u, bind=%x, flags=%x"
46 #define PRSC_ARGS(p) \
47 (p), util_str_tex_target((p)->target, true), \
48 util_format_short_name((p)->format), (p)->width0, (p)->height0, \
49 (p)->depth0, (p)->array_size, (p)->last_level, (p)->nr_samples, \
50 (p)->usage, (p)->bind, (p)->flags
51
52 enum fd_lrz_direction {
53 FD_LRZ_UNKNOWN,
54 /* Depth func less/less-than: */
55 FD_LRZ_LESS,
56 /* Depth func greater/greater-than: */
57 FD_LRZ_GREATER,
58 };
59
60 /**
61 * State related to batch/resource tracking.
62 *
63 * With threaded_context we need to support replace_buffer_storage, in
64 * which case we can end up in transfer_map with tres->latest, but other
65 * pipe_context APIs using the original prsc pointer. This allows TC to
66 * not have to synchronize the front-end thread with the buffer storage
67 * replacement called on driver thread. But it complicates the batch/
68 * resource tracking.
69 *
70 * To handle this, we need to split the tracking out into it's own ref-
71 * counted structure, so as needed both "versions" of the resource can
72 * point to the same tracking.
73 *
74 * We could *almost* just push this down to fd_bo, except for a3xx/a4xx
75 * hw queries, where we don't know up-front the size to allocate for
76 * per-tile query results.
77 */
78 struct fd_resource_tracking {
79 struct pipe_reference reference;
80
81 /* bitmask of in-flight batches which reference this resource. Note
82 * that the batch doesn't hold reference to resources (but instead
83 * the fd_ringbuffer holds refs to the underlying fd_bo), but in case
84 * the resource is destroyed we need to clean up the batch's weak
85 * references to us.
86 */
87 uint32_t batch_mask;
88
89 /* reference to batch that writes this resource: */
90 struct fd_batch *write_batch;
91
92 /* Set of batches whose batch-cache key references this resource.
93 * We need to track this to know which batch-cache entries to
94 * invalidate if, for example, the resource is invalidated or
95 * shadowed.
96 */
97 uint32_t bc_batch_mask;
98 };
99
100 void __fd_resource_tracking_destroy(struct fd_resource_tracking *track);
101
102 static inline void
fd_resource_tracking_reference(struct fd_resource_tracking ** ptr,struct fd_resource_tracking * track)103 fd_resource_tracking_reference(struct fd_resource_tracking **ptr,
104 struct fd_resource_tracking *track)
105 {
106 struct fd_resource_tracking *old_track = *ptr;
107
108 if (pipe_reference(&(*ptr)->reference, &track->reference)) {
109 assert(!old_track->write_batch);
110 free(old_track);
111 }
112
113 *ptr = track;
114 }
115
116 /**
117 * A resource (any buffer/texture/image/etc)
118 */
119 struct fd_resource {
120 struct threaded_resource b;
121 struct fd_bo *bo; /* use fd_resource_set_bo() to write */
122 enum pipe_format internal_format;
123 uint32_t hash; /* _mesa_hash_pointer() on this resource's address. */
124 struct fdl_layout layout;
125
126 /* buffer range that has been initialized */
127 struct util_range valid_buffer_range;
128 bool valid;
129 struct renderonly_scanout *scanout;
130
131 /* reference to the resource holding stencil data for a z32_s8 texture */
132 /* TODO rename to secondary or auxiliary? */
133 struct fd_resource *stencil;
134
135 struct fd_resource_tracking *track;
136
137 simple_mtx_t lock;
138
139 /* bitmask of state this resource could potentially dirty when rebound,
140 * see rebind_resource()
141 */
142 BITMASK_ENUM(fd_dirty_3d_state) dirty;
143
144 /* Sequence # incremented each time bo changes: */
145 uint16_t seqno;
146
147 /* Is this buffer a replacement created by threaded_context to avoid
148 * a stall in PIPE_MAP_DISCARD_WHOLE_RESOURCE|PIPE_MAP_WRITE case?
149 * If so, it no longer "owns" it's rsc->track, and so should not
150 * invalidate when the rsc is destroyed.
151 */
152 bool is_replacement : 1;
153
154 /* Uninitialized resources with UBWC format need their UBWC flag data
155 * cleared before writes, as the UBWC state is read and used during
156 * writes, so undefined UBWC flag data results in undefined results.
157 */
158 bool needs_ubwc_clear : 1;
159
160 /*
161 * LRZ
162 *
163 * TODO lrz width/height/pitch should probably also move to
164 * fdl_layout
165 */
166 bool lrz_valid : 1;
167 enum fd_lrz_direction lrz_direction : 2;
168 uint16_t lrz_width; // for lrz clear, does this differ from lrz_pitch?
169 uint16_t lrz_height;
170 uint16_t lrz_pitch;
171 struct fd_bo *lrz;
172 };
173
174 struct fd_memory_object {
175 struct pipe_memory_object b;
176 struct fd_bo *bo;
177 };
178
179 static inline struct fd_resource *
fd_resource(struct pipe_resource * ptex)180 fd_resource(struct pipe_resource *ptex)
181 {
182 return (struct fd_resource *)ptex;
183 }
184
185 static inline struct fd_memory_object *
fd_memory_object(struct pipe_memory_object * pmemobj)186 fd_memory_object(struct pipe_memory_object *pmemobj)
187 {
188 return (struct fd_memory_object *)pmemobj;
189 }
190
191 static inline bool
pending(struct fd_resource * rsc,bool write)192 pending(struct fd_resource *rsc, bool write)
193 {
194 /* if we have a pending GPU write, we are busy in any case: */
195 if (rsc->track->write_batch)
196 return true;
197
198 /* if CPU wants to write, but we are pending a GPU read, we are busy: */
199 if (write && rsc->track->batch_mask)
200 return true;
201
202 if (rsc->stencil && pending(rsc->stencil, write))
203 return true;
204
205 return false;
206 }
207
208 static inline bool
resource_busy(struct fd_resource * rsc,unsigned op)209 resource_busy(struct fd_resource *rsc, unsigned op)
210 {
211 return fd_bo_cpu_prep(rsc->bo, NULL, op | FD_BO_PREP_NOSYNC) != 0;
212 }
213
214 int __fd_resource_wait(struct fd_context *ctx, struct fd_resource *rsc,
215 unsigned op, const char *func);
216 #define fd_resource_wait(ctx, rsc, op) ({ \
217 MESA_TRACE_FUNC(); \
218 __fd_resource_wait(ctx, rsc, op, __func__); \
219 })
220
221 static inline void
fd_resource_lock(struct fd_resource * rsc)222 fd_resource_lock(struct fd_resource *rsc)
223 {
224 simple_mtx_lock(&rsc->lock);
225 }
226
227 static inline void
fd_resource_unlock(struct fd_resource * rsc)228 fd_resource_unlock(struct fd_resource *rsc)
229 {
230 simple_mtx_unlock(&rsc->lock);
231 }
232
233 static inline void
fd_resource_set_usage(struct pipe_resource * prsc,enum fd_dirty_3d_state usage)234 fd_resource_set_usage(struct pipe_resource *prsc, enum fd_dirty_3d_state usage)
235 {
236 if (!prsc)
237 return;
238 struct fd_resource *rsc = fd_resource(prsc);
239 /* Bits are only ever ORed in, and we expect many set_usage() per
240 * resource, so do the quick check outside of the lock.
241 */
242 if (likely(rsc->dirty & usage))
243 return;
244 fd_resource_lock(rsc);
245 rsc->dirty |= usage;
246 fd_resource_unlock(rsc);
247 }
248
249 static inline bool
has_depth(enum pipe_format format)250 has_depth(enum pipe_format format)
251 {
252 const struct util_format_description *desc = util_format_description(format);
253 return util_format_has_depth(desc);
254 }
255
256 static inline bool
is_z32(enum pipe_format format)257 is_z32(enum pipe_format format)
258 {
259 switch (format) {
260 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
261 case PIPE_FORMAT_Z32_UNORM:
262 case PIPE_FORMAT_Z32_FLOAT:
263 return true;
264 default:
265 return false;
266 }
267 }
268
269 struct fd_transfer {
270 struct threaded_transfer b;
271 struct pipe_resource *staging_prsc;
272 struct pipe_box staging_box;
273 void *upload_ptr;
274 };
275
276 static inline struct fd_transfer *
fd_transfer(struct pipe_transfer * ptrans)277 fd_transfer(struct pipe_transfer *ptrans)
278 {
279 return (struct fd_transfer *)ptrans;
280 }
281
282 static inline struct fdl_slice *
fd_resource_slice(struct fd_resource * rsc,unsigned level)283 fd_resource_slice(struct fd_resource *rsc, unsigned level)
284 {
285 assert(level <= rsc->b.b.last_level);
286 return &rsc->layout.slices[level];
287 }
288
289 static inline uint32_t
fd_resource_layer_stride(struct fd_resource * rsc,unsigned level)290 fd_resource_layer_stride(struct fd_resource *rsc, unsigned level)
291 {
292 return fdl_layer_stride(&rsc->layout, level);
293 }
294
295 /* get pitch (in bytes) for specified mipmap level */
296 static inline uint32_t
fd_resource_pitch(struct fd_resource * rsc,unsigned level)297 fd_resource_pitch(struct fd_resource *rsc, unsigned level)
298 {
299 if (is_a2xx(fd_screen(rsc->b.b.screen)))
300 return fdl2_pitch(&rsc->layout, level);
301
302 return fdl_pitch(&rsc->layout, level);
303 }
304
305 /* get offset for specified mipmap level and texture/array layer */
306 static inline uint32_t
fd_resource_offset(struct fd_resource * rsc,unsigned level,unsigned layer)307 fd_resource_offset(struct fd_resource *rsc, unsigned level, unsigned layer)
308 {
309 uint32_t offset = fdl_surface_offset(&rsc->layout, level, layer);
310 assert(offset < fd_bo_size(rsc->bo));
311 return offset;
312 }
313
314 static inline uint32_t
fd_resource_ubwc_offset(struct fd_resource * rsc,unsigned level,unsigned layer)315 fd_resource_ubwc_offset(struct fd_resource *rsc, unsigned level, unsigned layer)
316 {
317 uint32_t offset = fdl_ubwc_offset(&rsc->layout, level, layer);
318 assert(offset < fd_bo_size(rsc->bo));
319 return offset;
320 }
321
322 static inline uint32_t
fd_resource_tile_mode(struct pipe_resource * prsc,int level)323 fd_resource_tile_mode(struct pipe_resource *prsc, int level)
324 {
325 return fdl_tile_mode(&fd_resource(prsc)->layout, level);
326 }
327
328 static inline const char *
fd_resource_tile_mode_desc(const struct fd_resource * rsc,int level)329 fd_resource_tile_mode_desc(const struct fd_resource *rsc, int level)
330 {
331 return fdl_tile_mode_desc(&rsc->layout, level);
332 }
333
334 static inline bool
fd_resource_ubwc_enabled(struct fd_resource * rsc,int level)335 fd_resource_ubwc_enabled(struct fd_resource *rsc, int level)
336 {
337 return fdl_ubwc_enabled(&rsc->layout, level);
338 }
339
340 /* access # of samples, with 0 normalized to 1 (which is what we care about
341 * most of the time)
342 */
343 static inline unsigned
fd_resource_nr_samples(const struct pipe_resource * prsc)344 fd_resource_nr_samples(const struct pipe_resource *prsc)
345 {
346 return MAX2(1, prsc->nr_samples);
347 }
348
349 void fd_resource_screen_init(struct pipe_screen *pscreen);
350 void fd_resource_context_init(struct pipe_context *pctx);
351
352 uint32_t fd_setup_slices(struct fd_resource *rsc);
353 void fd_resource_resize(struct pipe_resource *prsc, uint32_t sz);
354 void fd_replace_buffer_storage(struct pipe_context *ctx,
355 struct pipe_resource *dst,
356 struct pipe_resource *src,
357 unsigned num_rebinds,
358 uint32_t rebind_mask,
359 uint32_t delete_buffer_id) in_dt;
360 bool fd_resource_busy(struct pipe_screen *pscreen, struct pipe_resource *prsc,
361 unsigned usage);
362
363 void fd_resource_uncompress(struct fd_context *ctx,
364 struct fd_resource *rsc,
365 bool linear) assert_dt;
366 void fd_resource_dump(struct fd_resource *rsc, const char *name);
367
368 bool fd_render_condition_check(struct pipe_context *pctx) assert_dt;
369
370 static inline bool
fd_batch_references_resource(struct fd_batch * batch,struct fd_resource * rsc)371 fd_batch_references_resource(struct fd_batch *batch, struct fd_resource *rsc)
372 {
373 return rsc->track->batch_mask & (1 << batch->idx);
374 }
375
376 static inline void
fd_batch_write_prep(struct fd_batch * batch,struct fd_resource * rsc)377 fd_batch_write_prep(struct fd_batch *batch, struct fd_resource *rsc) assert_dt
378 {
379 if (unlikely(rsc->needs_ubwc_clear)) {
380 batch->ctx->clear_ubwc(batch, rsc);
381 rsc->needs_ubwc_clear = false;
382 }
383 }
384
385 static inline void
fd_batch_resource_read(struct fd_batch * batch,struct fd_resource * rsc)386 fd_batch_resource_read(struct fd_batch *batch,
387 struct fd_resource *rsc) assert_dt
388 {
389 /* Fast path: if we hit this then we know we don't have anyone else
390 * writing to it (since both _write and _read flush other writers), and
391 * that we've already recursed for stencil.
392 */
393 if (unlikely(!fd_batch_references_resource(batch, rsc)))
394 fd_batch_resource_read_slowpath(batch, rsc);
395 }
396
397 static inline bool
needs_dirty_resource(struct fd_context * ctx,struct pipe_resource * prsc,bool write)398 needs_dirty_resource(struct fd_context *ctx, struct pipe_resource *prsc, bool write)
399 assert_dt
400 {
401 if (!prsc)
402 return false;
403
404 struct fd_resource *rsc = fd_resource(prsc);
405
406 /* Switching between draw and non_draw will dirty all state, so if
407 * we pick the wrong one, all the bits in the dirty_resource state
408 * will be set anyways.. so no harm, no foul.
409 */
410 struct fd_batch *batch = ctx->batch_nondraw ? ctx->batch_nondraw : ctx->batch;
411
412 if (!batch)
413 return false;
414
415 if (write)
416 return rsc->track->write_batch != batch;
417
418 return !fd_batch_references_resource(batch, rsc);
419 }
420
421 static inline void
fd_dirty_resource(struct fd_context * ctx,struct pipe_resource * prsc,BITMASK_ENUM (fd_dirty_3d_state)dirty,bool write)422 fd_dirty_resource(struct fd_context *ctx, struct pipe_resource *prsc,
423 BITMASK_ENUM(fd_dirty_3d_state) dirty, bool write)
424 assert_dt
425 {
426 fd_context_dirty(ctx, dirty);
427
428 if (ctx->dirty_resource & dirty)
429 return;
430
431 if (!needs_dirty_resource(ctx, prsc, write))
432 return;
433
434 ctx->dirty_resource |= dirty;
435 }
436
437 static inline void
fd_dirty_shader_resource(struct fd_context * ctx,struct pipe_resource * prsc,enum pipe_shader_type shader,BITMASK_ENUM (fd_dirty_shader_state)dirty,bool write)438 fd_dirty_shader_resource(struct fd_context *ctx, struct pipe_resource *prsc,
439 enum pipe_shader_type shader,
440 BITMASK_ENUM(fd_dirty_shader_state) dirty,
441 bool write)
442 assert_dt
443 {
444 fd_context_dirty_shader(ctx, shader, dirty);
445
446 if (ctx->dirty_shader_resource[shader] & dirty)
447 return;
448
449 if (!needs_dirty_resource(ctx, prsc, write))
450 return;
451
452 ctx->dirty_shader_resource[shader] |= dirty;
453 ctx->dirty_resource |= dirty_shader_to_dirty_state(dirty);
454 }
455
456 static inline enum fdl_view_type
fdl_type_from_pipe_target(enum pipe_texture_target target)457 fdl_type_from_pipe_target(enum pipe_texture_target target) {
458 switch (target) {
459 case PIPE_TEXTURE_1D:
460 case PIPE_TEXTURE_1D_ARRAY:
461 return FDL_VIEW_TYPE_1D;
462 case PIPE_TEXTURE_2D:
463 case PIPE_TEXTURE_RECT:
464 case PIPE_TEXTURE_2D_ARRAY:
465 return FDL_VIEW_TYPE_2D;
466 case PIPE_TEXTURE_CUBE:
467 case PIPE_TEXTURE_CUBE_ARRAY:
468 return FDL_VIEW_TYPE_CUBE;
469 case PIPE_TEXTURE_3D:
470 return FDL_VIEW_TYPE_3D;
471 case PIPE_MAX_TEXTURE_TYPES:
472 default:
473 unreachable("bad texture type");
474 }
475 }
476
477 ENDC;
478
479 #endif /* FREEDRENO_RESOURCE_H_ */
480