freedreno_resource.h revision 7ec681f3
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
50enum 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 */
76struct 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
98void __fd_resource_tracking_destroy(struct fd_resource_tracking *track);
99
100static inline void
101fd_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 */
117struct 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
172struct fd_memory_object {
173   struct pipe_memory_object b;
174   struct fd_bo *bo;
175};
176
177static inline struct fd_resource *
178fd_resource(struct pipe_resource *ptex)
179{
180   return (struct fd_resource *)ptex;
181}
182
183static inline const struct fd_resource *
184fd_resource_const(const struct pipe_resource *ptex)
185{
186   return (const struct fd_resource *)ptex;
187}
188
189static inline struct fd_memory_object *
190fd_memory_object(struct pipe_memory_object *pmemobj)
191{
192   return (struct fd_memory_object *)pmemobj;
193}
194
195static inline bool
196pending(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
212static inline bool
213resource_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
218int __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
223static inline void
224fd_resource_lock(struct fd_resource *rsc)
225{
226   simple_mtx_lock(&rsc->lock);
227}
228
229static inline void
230fd_resource_unlock(struct fd_resource *rsc)
231{
232   simple_mtx_unlock(&rsc->lock);
233}
234
235static inline void
236fd_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
251static inline bool
252has_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
258struct fd_transfer {
259   struct threaded_transfer b;
260   struct pipe_resource *staging_prsc;
261   struct pipe_box staging_box;
262};
263
264static inline struct fd_transfer *
265fd_transfer(struct pipe_transfer *ptrans)
266{
267   return (struct fd_transfer *)ptrans;
268}
269
270static inline struct fdl_slice *
271fd_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
277static inline uint32_t
278fd_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 */
284static inline uint32_t
285fd_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 */
294static inline uint32_t
295fd_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
302static inline uint32_t
303fd_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: */
311static inline bool
312fd_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
320static inline uint32_t
321fd_resource_tile_mode(struct pipe_resource *prsc, int level)
322{
323   return fdl_tile_mode(&fd_resource(prsc)->layout, level);
324}
325
326static inline const char *
327fd_resource_tile_mode_desc(const struct fd_resource *rsc, int level)
328{
329   return fdl_tile_mode_desc(&rsc->layout, level);
330}
331
332static inline bool
333fd_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 */
341static inline unsigned
342fd_resource_nr_samples(struct pipe_resource *prsc)
343{
344   return MAX2(1, prsc->nr_samples);
345}
346
347void fd_resource_screen_init(struct pipe_screen *pscreen);
348void fd_resource_context_init(struct pipe_context *pctx);
349
350uint32_t fd_setup_slices(struct fd_resource *rsc);
351void fd_resource_resize(struct pipe_resource *prsc, uint32_t sz);
352void 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;
358bool fd_resource_busy(struct pipe_screen *pscreen, struct pipe_resource *prsc,
359                      unsigned usage);
360
361void fd_resource_uncompress(struct fd_context *ctx,
362                            struct fd_resource *rsc,
363                            bool linear) assert_dt;
364void fd_resource_dump(struct fd_resource *rsc, const char *name);
365
366bool fd_render_condition_check(struct pipe_context *pctx) assert_dt;
367
368static inline bool
369fd_batch_references_resource(struct fd_batch *batch, struct fd_resource *rsc)
370{
371   return rsc->track->batch_mask & (1 << batch->idx);
372}
373
374static inline void
375fd_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
383static inline void
384fd_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