• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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