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