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