1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2013 Advanced Micro Devices, Inc. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub 8bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom 9bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci * Authors: 24bf215546Sopenharmony_ci * Marek Olšák 25bf215546Sopenharmony_ci */ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include "r600_cs.h" 28bf215546Sopenharmony_ci#include "evergreen_compute.h" 29bf215546Sopenharmony_ci#include "compute_memory_pool.h" 30bf215546Sopenharmony_ci#include "util/u_memory.h" 31bf215546Sopenharmony_ci#include "util/u_upload_mgr.h" 32bf215546Sopenharmony_ci#include <inttypes.h> 33bf215546Sopenharmony_ci#include <stdio.h> 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_cibool r600_rings_is_buffer_referenced(struct r600_common_context *ctx, 36bf215546Sopenharmony_ci struct pb_buffer *buf, 37bf215546Sopenharmony_ci unsigned usage) 38bf215546Sopenharmony_ci{ 39bf215546Sopenharmony_ci if (ctx->ws->cs_is_buffer_referenced(&ctx->gfx.cs, buf, usage)) { 40bf215546Sopenharmony_ci return true; 41bf215546Sopenharmony_ci } 42bf215546Sopenharmony_ci if (radeon_emitted(&ctx->dma.cs, 0) && 43bf215546Sopenharmony_ci ctx->ws->cs_is_buffer_referenced(&ctx->dma.cs, buf, usage)) { 44bf215546Sopenharmony_ci return true; 45bf215546Sopenharmony_ci } 46bf215546Sopenharmony_ci return false; 47bf215546Sopenharmony_ci} 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_civoid *r600_buffer_map_sync_with_rings(struct r600_common_context *ctx, 50bf215546Sopenharmony_ci struct r600_resource *resource, 51bf215546Sopenharmony_ci unsigned usage) 52bf215546Sopenharmony_ci{ 53bf215546Sopenharmony_ci unsigned rusage = RADEON_USAGE_READWRITE; 54bf215546Sopenharmony_ci bool busy = false; 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci assert(!(resource->flags & RADEON_FLAG_SPARSE)); 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci if (usage & PIPE_MAP_UNSYNCHRONIZED) { 59bf215546Sopenharmony_ci return ctx->ws->buffer_map(ctx->ws, resource->buf, NULL, usage); 60bf215546Sopenharmony_ci } 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci if (!(usage & PIPE_MAP_WRITE)) { 63bf215546Sopenharmony_ci /* have to wait for the last write */ 64bf215546Sopenharmony_ci rusage = RADEON_USAGE_WRITE; 65bf215546Sopenharmony_ci } 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci if (radeon_emitted(&ctx->gfx.cs, ctx->initial_gfx_cs_size) && 68bf215546Sopenharmony_ci ctx->ws->cs_is_buffer_referenced(&ctx->gfx.cs, 69bf215546Sopenharmony_ci resource->buf, rusage)) { 70bf215546Sopenharmony_ci if (usage & PIPE_MAP_DONTBLOCK) { 71bf215546Sopenharmony_ci ctx->gfx.flush(ctx, PIPE_FLUSH_ASYNC, NULL); 72bf215546Sopenharmony_ci return NULL; 73bf215546Sopenharmony_ci } else { 74bf215546Sopenharmony_ci ctx->gfx.flush(ctx, 0, NULL); 75bf215546Sopenharmony_ci busy = true; 76bf215546Sopenharmony_ci } 77bf215546Sopenharmony_ci } 78bf215546Sopenharmony_ci if (radeon_emitted(&ctx->dma.cs, 0) && 79bf215546Sopenharmony_ci ctx->ws->cs_is_buffer_referenced(&ctx->dma.cs, 80bf215546Sopenharmony_ci resource->buf, rusage)) { 81bf215546Sopenharmony_ci if (usage & PIPE_MAP_DONTBLOCK) { 82bf215546Sopenharmony_ci ctx->dma.flush(ctx, PIPE_FLUSH_ASYNC, NULL); 83bf215546Sopenharmony_ci return NULL; 84bf215546Sopenharmony_ci } else { 85bf215546Sopenharmony_ci ctx->dma.flush(ctx, 0, NULL); 86bf215546Sopenharmony_ci busy = true; 87bf215546Sopenharmony_ci } 88bf215546Sopenharmony_ci } 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci if (busy || !ctx->ws->buffer_wait(ctx->ws, resource->buf, 0, rusage)) { 91bf215546Sopenharmony_ci if (usage & PIPE_MAP_DONTBLOCK) { 92bf215546Sopenharmony_ci return NULL; 93bf215546Sopenharmony_ci } else { 94bf215546Sopenharmony_ci /* We will be wait for the GPU. Wait for any offloaded 95bf215546Sopenharmony_ci * CS flush to complete to avoid busy-waiting in the winsys. */ 96bf215546Sopenharmony_ci ctx->ws->cs_sync_flush(&ctx->gfx.cs); 97bf215546Sopenharmony_ci if (ctx->dma.cs.priv) 98bf215546Sopenharmony_ci ctx->ws->cs_sync_flush(&ctx->dma.cs); 99bf215546Sopenharmony_ci } 100bf215546Sopenharmony_ci } 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci /* Setting the CS to NULL will prevent doing checks we have done already. */ 103bf215546Sopenharmony_ci return ctx->ws->buffer_map(ctx->ws, resource->buf, NULL, usage); 104bf215546Sopenharmony_ci} 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_civoid r600_init_resource_fields(struct r600_common_screen *rscreen, 107bf215546Sopenharmony_ci struct r600_resource *res, 108bf215546Sopenharmony_ci uint64_t size, unsigned alignment) 109bf215546Sopenharmony_ci{ 110bf215546Sopenharmony_ci struct r600_texture *rtex = (struct r600_texture*)res; 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci res->bo_size = size; 113bf215546Sopenharmony_ci res->bo_alignment = alignment; 114bf215546Sopenharmony_ci res->flags = 0; 115bf215546Sopenharmony_ci res->texture_handle_allocated = false; 116bf215546Sopenharmony_ci res->image_handle_allocated = false; 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci switch (res->b.b.usage) { 119bf215546Sopenharmony_ci case PIPE_USAGE_STREAM: 120bf215546Sopenharmony_ci res->flags = RADEON_FLAG_GTT_WC; 121bf215546Sopenharmony_ci FALLTHROUGH; 122bf215546Sopenharmony_ci case PIPE_USAGE_STAGING: 123bf215546Sopenharmony_ci /* Transfers are likely to occur more often with these 124bf215546Sopenharmony_ci * resources. */ 125bf215546Sopenharmony_ci res->domains = RADEON_DOMAIN_GTT; 126bf215546Sopenharmony_ci break; 127bf215546Sopenharmony_ci case PIPE_USAGE_DYNAMIC: 128bf215546Sopenharmony_ci case PIPE_USAGE_DEFAULT: 129bf215546Sopenharmony_ci case PIPE_USAGE_IMMUTABLE: 130bf215546Sopenharmony_ci default: 131bf215546Sopenharmony_ci /* Not listing GTT here improves performance in some 132bf215546Sopenharmony_ci * apps. */ 133bf215546Sopenharmony_ci res->domains = RADEON_DOMAIN_VRAM; 134bf215546Sopenharmony_ci res->flags |= RADEON_FLAG_GTT_WC; 135bf215546Sopenharmony_ci break; 136bf215546Sopenharmony_ci } 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci /* Tiled textures are unmappable. Always put them in VRAM. */ 139bf215546Sopenharmony_ci if ((res->b.b.target != PIPE_BUFFER && !rtex->surface.is_linear) || 140bf215546Sopenharmony_ci res->flags & R600_RESOURCE_FLAG_UNMAPPABLE) { 141bf215546Sopenharmony_ci res->domains = RADEON_DOMAIN_VRAM; 142bf215546Sopenharmony_ci res->flags |= RADEON_FLAG_NO_CPU_ACCESS | 143bf215546Sopenharmony_ci RADEON_FLAG_GTT_WC; 144bf215546Sopenharmony_ci } 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci /* Displayable and shareable surfaces are not suballocated. */ 147bf215546Sopenharmony_ci if (res->b.b.bind & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT)) 148bf215546Sopenharmony_ci res->flags |= RADEON_FLAG_NO_SUBALLOC; /* shareable */ 149bf215546Sopenharmony_ci else 150bf215546Sopenharmony_ci res->flags |= RADEON_FLAG_NO_INTERPROCESS_SHARING; 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_ci if (rscreen->debug_flags & DBG_NO_WC) 153bf215546Sopenharmony_ci res->flags &= ~RADEON_FLAG_GTT_WC; 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci /* Set expected VRAM and GART usage for the buffer. */ 156bf215546Sopenharmony_ci res->vram_usage = 0; 157bf215546Sopenharmony_ci res->gart_usage = 0; 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci if (res->domains & RADEON_DOMAIN_VRAM) 160bf215546Sopenharmony_ci res->vram_usage = size; 161bf215546Sopenharmony_ci else if (res->domains & RADEON_DOMAIN_GTT) 162bf215546Sopenharmony_ci res->gart_usage = size; 163bf215546Sopenharmony_ci} 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_cibool r600_alloc_resource(struct r600_common_screen *rscreen, 166bf215546Sopenharmony_ci struct r600_resource *res) 167bf215546Sopenharmony_ci{ 168bf215546Sopenharmony_ci struct pb_buffer *old_buf, *new_buf; 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci /* Allocate a new resource. */ 171bf215546Sopenharmony_ci new_buf = rscreen->ws->buffer_create(rscreen->ws, res->bo_size, 172bf215546Sopenharmony_ci res->bo_alignment, 173bf215546Sopenharmony_ci res->domains, res->flags); 174bf215546Sopenharmony_ci if (!new_buf) { 175bf215546Sopenharmony_ci return false; 176bf215546Sopenharmony_ci } 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci /* Replace the pointer such that if res->buf wasn't NULL, it won't be 179bf215546Sopenharmony_ci * NULL. This should prevent crashes with multiple contexts using 180bf215546Sopenharmony_ci * the same buffer where one of the contexts invalidates it while 181bf215546Sopenharmony_ci * the others are using it. */ 182bf215546Sopenharmony_ci old_buf = res->buf; 183bf215546Sopenharmony_ci res->buf = new_buf; /* should be atomic */ 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci if (rscreen->info.r600_has_virtual_memory) 186bf215546Sopenharmony_ci res->gpu_address = rscreen->ws->buffer_get_virtual_address(res->buf); 187bf215546Sopenharmony_ci else 188bf215546Sopenharmony_ci res->gpu_address = 0; 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci pb_reference(&old_buf, NULL); 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci util_range_set_empty(&res->valid_buffer_range); 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci /* Print debug information. */ 195bf215546Sopenharmony_ci if (rscreen->debug_flags & DBG_VM && res->b.b.target == PIPE_BUFFER) { 196bf215546Sopenharmony_ci fprintf(stderr, "VM start=0x%"PRIX64" end=0x%"PRIX64" | Buffer %"PRIu64" bytes\n", 197bf215546Sopenharmony_ci res->gpu_address, res->gpu_address + res->buf->size, 198bf215546Sopenharmony_ci res->buf->size); 199bf215546Sopenharmony_ci } 200bf215546Sopenharmony_ci return true; 201bf215546Sopenharmony_ci} 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_civoid r600_buffer_destroy(struct pipe_screen *screen, struct pipe_resource *buf) 204bf215546Sopenharmony_ci{ 205bf215546Sopenharmony_ci struct r600_resource *rbuffer = r600_resource(buf); 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci threaded_resource_deinit(buf); 208bf215546Sopenharmony_ci util_range_destroy(&rbuffer->valid_buffer_range); 209bf215546Sopenharmony_ci pipe_resource_reference((struct pipe_resource**)&rbuffer->immed_buffer, NULL); 210bf215546Sopenharmony_ci pb_reference(&rbuffer->buf, NULL); 211bf215546Sopenharmony_ci FREE(rbuffer); 212bf215546Sopenharmony_ci} 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_cistatic bool 215bf215546Sopenharmony_cir600_invalidate_buffer(struct r600_common_context *rctx, 216bf215546Sopenharmony_ci struct r600_resource *rbuffer) 217bf215546Sopenharmony_ci{ 218bf215546Sopenharmony_ci /* Shared buffers can't be reallocated. */ 219bf215546Sopenharmony_ci if (rbuffer->b.is_shared) 220bf215546Sopenharmony_ci return false; 221bf215546Sopenharmony_ci 222bf215546Sopenharmony_ci /* Sparse buffers can't be reallocated. */ 223bf215546Sopenharmony_ci if (rbuffer->flags & RADEON_FLAG_SPARSE) 224bf215546Sopenharmony_ci return false; 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci /* In AMD_pinned_memory, the user pointer association only gets 227bf215546Sopenharmony_ci * broken when the buffer is explicitly re-allocated. 228bf215546Sopenharmony_ci */ 229bf215546Sopenharmony_ci if (rbuffer->b.is_user_ptr) 230bf215546Sopenharmony_ci return false; 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci /* Check if mapping this buffer would cause waiting for the GPU. */ 233bf215546Sopenharmony_ci if (r600_rings_is_buffer_referenced(rctx, rbuffer->buf, RADEON_USAGE_READWRITE) || 234bf215546Sopenharmony_ci !rctx->ws->buffer_wait(rctx->ws, rbuffer->buf, 0, RADEON_USAGE_READWRITE)) { 235bf215546Sopenharmony_ci rctx->invalidate_buffer(&rctx->b, &rbuffer->b.b); 236bf215546Sopenharmony_ci } else { 237bf215546Sopenharmony_ci util_range_set_empty(&rbuffer->valid_buffer_range); 238bf215546Sopenharmony_ci } 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci return true; 241bf215546Sopenharmony_ci} 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci/* Replace the storage of dst with src. */ 244bf215546Sopenharmony_civoid r600_replace_buffer_storage(struct pipe_context *ctx, 245bf215546Sopenharmony_ci struct pipe_resource *dst, 246bf215546Sopenharmony_ci struct pipe_resource *src) 247bf215546Sopenharmony_ci{ 248bf215546Sopenharmony_ci struct r600_common_context *rctx = (struct r600_common_context *)ctx; 249bf215546Sopenharmony_ci struct r600_resource *rdst = r600_resource(dst); 250bf215546Sopenharmony_ci struct r600_resource *rsrc = r600_resource(src); 251bf215546Sopenharmony_ci uint64_t old_gpu_address = rdst->gpu_address; 252bf215546Sopenharmony_ci 253bf215546Sopenharmony_ci pb_reference(&rdst->buf, rsrc->buf); 254bf215546Sopenharmony_ci rdst->gpu_address = rsrc->gpu_address; 255bf215546Sopenharmony_ci rdst->b.b.bind = rsrc->b.b.bind; 256bf215546Sopenharmony_ci rdst->flags = rsrc->flags; 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci assert(rdst->vram_usage == rsrc->vram_usage); 259bf215546Sopenharmony_ci assert(rdst->gart_usage == rsrc->gart_usage); 260bf215546Sopenharmony_ci assert(rdst->bo_size == rsrc->bo_size); 261bf215546Sopenharmony_ci assert(rdst->bo_alignment == rsrc->bo_alignment); 262bf215546Sopenharmony_ci assert(rdst->domains == rsrc->domains); 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci rctx->rebind_buffer(ctx, dst, old_gpu_address); 265bf215546Sopenharmony_ci} 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_civoid r600_invalidate_resource(struct pipe_context *ctx, 268bf215546Sopenharmony_ci struct pipe_resource *resource) 269bf215546Sopenharmony_ci{ 270bf215546Sopenharmony_ci struct r600_common_context *rctx = (struct r600_common_context*)ctx; 271bf215546Sopenharmony_ci struct r600_resource *rbuffer = r600_resource(resource); 272bf215546Sopenharmony_ci 273bf215546Sopenharmony_ci /* We currently only do anyting here for buffers */ 274bf215546Sopenharmony_ci if (resource->target == PIPE_BUFFER) 275bf215546Sopenharmony_ci (void)r600_invalidate_buffer(rctx, rbuffer); 276bf215546Sopenharmony_ci} 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_cistatic void *r600_buffer_get_transfer(struct pipe_context *ctx, 279bf215546Sopenharmony_ci struct pipe_resource *resource, 280bf215546Sopenharmony_ci unsigned usage, 281bf215546Sopenharmony_ci const struct pipe_box *box, 282bf215546Sopenharmony_ci struct pipe_transfer **ptransfer, 283bf215546Sopenharmony_ci void *data, struct r600_resource *staging, 284bf215546Sopenharmony_ci unsigned offset) 285bf215546Sopenharmony_ci{ 286bf215546Sopenharmony_ci struct r600_common_context *rctx = (struct r600_common_context*)ctx; 287bf215546Sopenharmony_ci struct r600_transfer *transfer; 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) 290bf215546Sopenharmony_ci transfer = slab_zalloc(&rctx->pool_transfers_unsync); 291bf215546Sopenharmony_ci else 292bf215546Sopenharmony_ci transfer = slab_zalloc(&rctx->pool_transfers); 293bf215546Sopenharmony_ci 294bf215546Sopenharmony_ci pipe_resource_reference(&transfer->b.b.resource, resource); 295bf215546Sopenharmony_ci transfer->b.b.usage = usage; 296bf215546Sopenharmony_ci transfer->b.b.box = *box; 297bf215546Sopenharmony_ci transfer->b.b.offset = offset; 298bf215546Sopenharmony_ci transfer->staging = staging; 299bf215546Sopenharmony_ci *ptransfer = &transfer->b.b; 300bf215546Sopenharmony_ci return data; 301bf215546Sopenharmony_ci} 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_cistatic bool r600_can_dma_copy_buffer(struct r600_common_context *rctx, 304bf215546Sopenharmony_ci unsigned dstx, unsigned srcx, unsigned size) 305bf215546Sopenharmony_ci{ 306bf215546Sopenharmony_ci bool dword_aligned = !(dstx % 4) && !(srcx % 4) && !(size % 4); 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci return rctx->screen->has_cp_dma || 309bf215546Sopenharmony_ci (dword_aligned && (rctx->dma.cs.priv || 310bf215546Sopenharmony_ci rctx->screen->has_streamout)); 311bf215546Sopenharmony_ci 312bf215546Sopenharmony_ci} 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_civoid *r600_buffer_transfer_map(struct pipe_context *ctx, 315bf215546Sopenharmony_ci struct pipe_resource *resource, 316bf215546Sopenharmony_ci unsigned level, 317bf215546Sopenharmony_ci unsigned usage, 318bf215546Sopenharmony_ci const struct pipe_box *box, 319bf215546Sopenharmony_ci struct pipe_transfer **ptransfer) 320bf215546Sopenharmony_ci{ 321bf215546Sopenharmony_ci struct r600_common_context *rctx = (struct r600_common_context*)ctx; 322bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen*)ctx->screen; 323bf215546Sopenharmony_ci struct r600_resource *rbuffer = r600_resource(resource); 324bf215546Sopenharmony_ci uint8_t *data; 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci if (r600_resource(resource)->compute_global_bo) { 327bf215546Sopenharmony_ci if ((data = r600_compute_global_transfer_map(ctx, resource, level, usage, box, ptransfer))) 328bf215546Sopenharmony_ci return data; 329bf215546Sopenharmony_ci } 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci assert(box->x + box->width <= resource->width0); 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci /* From GL_AMD_pinned_memory issues: 334bf215546Sopenharmony_ci * 335bf215546Sopenharmony_ci * 4) Is glMapBuffer on a shared buffer guaranteed to return the 336bf215546Sopenharmony_ci * same system address which was specified at creation time? 337bf215546Sopenharmony_ci * 338bf215546Sopenharmony_ci * RESOLVED: NO. The GL implementation might return a different 339bf215546Sopenharmony_ci * virtual mapping of that memory, although the same physical 340bf215546Sopenharmony_ci * page will be used. 341bf215546Sopenharmony_ci * 342bf215546Sopenharmony_ci * So don't ever use staging buffers. 343bf215546Sopenharmony_ci */ 344bf215546Sopenharmony_ci if (rbuffer->b.is_user_ptr) 345bf215546Sopenharmony_ci usage |= PIPE_MAP_PERSISTENT; 346bf215546Sopenharmony_ci 347bf215546Sopenharmony_ci /* See if the buffer range being mapped has never been initialized, 348bf215546Sopenharmony_ci * in which case it can be mapped unsynchronized. */ 349bf215546Sopenharmony_ci if (!(usage & (PIPE_MAP_UNSYNCHRONIZED | 350bf215546Sopenharmony_ci TC_TRANSFER_MAP_NO_INFER_UNSYNCHRONIZED)) && 351bf215546Sopenharmony_ci usage & PIPE_MAP_WRITE && 352bf215546Sopenharmony_ci !rbuffer->b.is_shared && 353bf215546Sopenharmony_ci !util_ranges_intersect(&rbuffer->valid_buffer_range, box->x, box->x + box->width)) { 354bf215546Sopenharmony_ci usage |= PIPE_MAP_UNSYNCHRONIZED; 355bf215546Sopenharmony_ci } 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci /* If discarding the entire range, discard the whole resource instead. */ 358bf215546Sopenharmony_ci if (usage & PIPE_MAP_DISCARD_RANGE && 359bf215546Sopenharmony_ci box->x == 0 && box->width == resource->width0) { 360bf215546Sopenharmony_ci usage |= PIPE_MAP_DISCARD_WHOLE_RESOURCE; 361bf215546Sopenharmony_ci } 362bf215546Sopenharmony_ci 363bf215546Sopenharmony_ci if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE && 364bf215546Sopenharmony_ci !(usage & (PIPE_MAP_UNSYNCHRONIZED | 365bf215546Sopenharmony_ci TC_TRANSFER_MAP_NO_INVALIDATE))) { 366bf215546Sopenharmony_ci assert(usage & PIPE_MAP_WRITE); 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_ci if (r600_invalidate_buffer(rctx, rbuffer)) { 369bf215546Sopenharmony_ci /* At this point, the buffer is always idle. */ 370bf215546Sopenharmony_ci usage |= PIPE_MAP_UNSYNCHRONIZED; 371bf215546Sopenharmony_ci } else { 372bf215546Sopenharmony_ci /* Fall back to a temporary buffer. */ 373bf215546Sopenharmony_ci usage |= PIPE_MAP_DISCARD_RANGE; 374bf215546Sopenharmony_ci } 375bf215546Sopenharmony_ci } 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_ci if ((usage & PIPE_MAP_DISCARD_RANGE) && 378bf215546Sopenharmony_ci !(rscreen->debug_flags & DBG_NO_DISCARD_RANGE) && 379bf215546Sopenharmony_ci ((!(usage & (PIPE_MAP_UNSYNCHRONIZED | 380bf215546Sopenharmony_ci PIPE_MAP_PERSISTENT)) && 381bf215546Sopenharmony_ci r600_can_dma_copy_buffer(rctx, box->x, 0, box->width)) || 382bf215546Sopenharmony_ci (rbuffer->flags & RADEON_FLAG_SPARSE))) { 383bf215546Sopenharmony_ci assert(usage & PIPE_MAP_WRITE); 384bf215546Sopenharmony_ci 385bf215546Sopenharmony_ci /* Check if mapping this buffer would cause waiting for the GPU. 386bf215546Sopenharmony_ci */ 387bf215546Sopenharmony_ci if (rbuffer->flags & RADEON_FLAG_SPARSE || 388bf215546Sopenharmony_ci r600_rings_is_buffer_referenced(rctx, rbuffer->buf, RADEON_USAGE_READWRITE) || 389bf215546Sopenharmony_ci !rctx->ws->buffer_wait(rctx->ws, rbuffer->buf, 0, RADEON_USAGE_READWRITE)) { 390bf215546Sopenharmony_ci /* Do a wait-free write-only transfer using a temporary buffer. */ 391bf215546Sopenharmony_ci unsigned offset; 392bf215546Sopenharmony_ci struct r600_resource *staging = NULL; 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_ci u_upload_alloc(ctx->stream_uploader, 0, 395bf215546Sopenharmony_ci box->width + (box->x % R600_MAP_BUFFER_ALIGNMENT), 396bf215546Sopenharmony_ci rctx->screen->info.tcc_cache_line_size, 397bf215546Sopenharmony_ci &offset, (struct pipe_resource**)&staging, 398bf215546Sopenharmony_ci (void**)&data); 399bf215546Sopenharmony_ci 400bf215546Sopenharmony_ci if (staging) { 401bf215546Sopenharmony_ci data += box->x % R600_MAP_BUFFER_ALIGNMENT; 402bf215546Sopenharmony_ci return r600_buffer_get_transfer(ctx, resource, usage, box, 403bf215546Sopenharmony_ci ptransfer, data, staging, offset); 404bf215546Sopenharmony_ci } else if (rbuffer->flags & RADEON_FLAG_SPARSE) { 405bf215546Sopenharmony_ci return NULL; 406bf215546Sopenharmony_ci } 407bf215546Sopenharmony_ci } else { 408bf215546Sopenharmony_ci /* At this point, the buffer is always idle (we checked it above). */ 409bf215546Sopenharmony_ci usage |= PIPE_MAP_UNSYNCHRONIZED; 410bf215546Sopenharmony_ci } 411bf215546Sopenharmony_ci } 412bf215546Sopenharmony_ci /* Use a staging buffer in cached GTT for reads. */ 413bf215546Sopenharmony_ci else if (((usage & PIPE_MAP_READ) && 414bf215546Sopenharmony_ci !(usage & PIPE_MAP_PERSISTENT) && 415bf215546Sopenharmony_ci (rbuffer->domains & RADEON_DOMAIN_VRAM || 416bf215546Sopenharmony_ci rbuffer->flags & RADEON_FLAG_GTT_WC) && 417bf215546Sopenharmony_ci r600_can_dma_copy_buffer(rctx, 0, box->x, box->width)) || 418bf215546Sopenharmony_ci (rbuffer->flags & RADEON_FLAG_SPARSE)) { 419bf215546Sopenharmony_ci struct r600_resource *staging; 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci assert(!(usage & TC_TRANSFER_MAP_THREADED_UNSYNC)); 422bf215546Sopenharmony_ci staging = (struct r600_resource*) pipe_buffer_create( 423bf215546Sopenharmony_ci ctx->screen, 0, PIPE_USAGE_STAGING, 424bf215546Sopenharmony_ci box->width + (box->x % R600_MAP_BUFFER_ALIGNMENT)); 425bf215546Sopenharmony_ci if (staging) { 426bf215546Sopenharmony_ci /* Copy the VRAM buffer to the staging buffer. */ 427bf215546Sopenharmony_ci rctx->dma_copy(ctx, &staging->b.b, 0, 428bf215546Sopenharmony_ci box->x % R600_MAP_BUFFER_ALIGNMENT, 429bf215546Sopenharmony_ci 0, 0, resource, 0, box); 430bf215546Sopenharmony_ci 431bf215546Sopenharmony_ci data = r600_buffer_map_sync_with_rings(rctx, staging, 432bf215546Sopenharmony_ci usage & ~PIPE_MAP_UNSYNCHRONIZED); 433bf215546Sopenharmony_ci if (!data) { 434bf215546Sopenharmony_ci r600_resource_reference(&staging, NULL); 435bf215546Sopenharmony_ci return NULL; 436bf215546Sopenharmony_ci } 437bf215546Sopenharmony_ci data += box->x % R600_MAP_BUFFER_ALIGNMENT; 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci return r600_buffer_get_transfer(ctx, resource, usage, box, 440bf215546Sopenharmony_ci ptransfer, data, staging, 0); 441bf215546Sopenharmony_ci } else if (rbuffer->flags & RADEON_FLAG_SPARSE) { 442bf215546Sopenharmony_ci return NULL; 443bf215546Sopenharmony_ci } 444bf215546Sopenharmony_ci } 445bf215546Sopenharmony_ci 446bf215546Sopenharmony_ci data = r600_buffer_map_sync_with_rings(rctx, rbuffer, usage); 447bf215546Sopenharmony_ci if (!data) { 448bf215546Sopenharmony_ci return NULL; 449bf215546Sopenharmony_ci } 450bf215546Sopenharmony_ci data += box->x; 451bf215546Sopenharmony_ci 452bf215546Sopenharmony_ci return r600_buffer_get_transfer(ctx, resource, usage, box, 453bf215546Sopenharmony_ci ptransfer, data, NULL, 0); 454bf215546Sopenharmony_ci} 455bf215546Sopenharmony_ci 456bf215546Sopenharmony_cistatic void r600_buffer_do_flush_region(struct pipe_context *ctx, 457bf215546Sopenharmony_ci struct pipe_transfer *transfer, 458bf215546Sopenharmony_ci const struct pipe_box *box) 459bf215546Sopenharmony_ci{ 460bf215546Sopenharmony_ci struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; 461bf215546Sopenharmony_ci struct r600_resource *rbuffer = r600_resource(transfer->resource); 462bf215546Sopenharmony_ci 463bf215546Sopenharmony_ci if (rtransfer->staging) { 464bf215546Sopenharmony_ci struct pipe_resource *dst, *src; 465bf215546Sopenharmony_ci unsigned soffset; 466bf215546Sopenharmony_ci struct pipe_box dma_box; 467bf215546Sopenharmony_ci 468bf215546Sopenharmony_ci dst = transfer->resource; 469bf215546Sopenharmony_ci src = &rtransfer->staging->b.b; 470bf215546Sopenharmony_ci soffset = rtransfer->b.b.offset + box->x % R600_MAP_BUFFER_ALIGNMENT; 471bf215546Sopenharmony_ci 472bf215546Sopenharmony_ci u_box_1d(soffset, box->width, &dma_box); 473bf215546Sopenharmony_ci 474bf215546Sopenharmony_ci /* Copy the staging buffer into the original one. */ 475bf215546Sopenharmony_ci ctx->resource_copy_region(ctx, dst, 0, box->x, 0, 0, src, 0, &dma_box); 476bf215546Sopenharmony_ci } 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_ci util_range_add(&rbuffer->b.b, &rbuffer->valid_buffer_range, box->x, 479bf215546Sopenharmony_ci box->x + box->width); 480bf215546Sopenharmony_ci} 481bf215546Sopenharmony_ci 482bf215546Sopenharmony_civoid r600_buffer_flush_region(struct pipe_context *ctx, 483bf215546Sopenharmony_ci struct pipe_transfer *transfer, 484bf215546Sopenharmony_ci const struct pipe_box *rel_box) 485bf215546Sopenharmony_ci{ 486bf215546Sopenharmony_ci unsigned required_usage = PIPE_MAP_WRITE | 487bf215546Sopenharmony_ci PIPE_MAP_FLUSH_EXPLICIT; 488bf215546Sopenharmony_ci 489bf215546Sopenharmony_ci if (r600_resource(transfer->resource)->compute_global_bo) 490bf215546Sopenharmony_ci return; 491bf215546Sopenharmony_ci 492bf215546Sopenharmony_ci if ((transfer->usage & required_usage) == required_usage) { 493bf215546Sopenharmony_ci struct pipe_box box; 494bf215546Sopenharmony_ci 495bf215546Sopenharmony_ci u_box_1d(transfer->box.x + rel_box->x, rel_box->width, &box); 496bf215546Sopenharmony_ci r600_buffer_do_flush_region(ctx, transfer, &box); 497bf215546Sopenharmony_ci } 498bf215546Sopenharmony_ci} 499bf215546Sopenharmony_ci 500bf215546Sopenharmony_civoid r600_buffer_transfer_unmap(struct pipe_context *ctx, 501bf215546Sopenharmony_ci struct pipe_transfer *transfer) 502bf215546Sopenharmony_ci{ 503bf215546Sopenharmony_ci struct r600_common_context *rctx = (struct r600_common_context*)ctx; 504bf215546Sopenharmony_ci struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; 505bf215546Sopenharmony_ci struct r600_resource *rtransferr = r600_resource(transfer->resource); 506bf215546Sopenharmony_ci 507bf215546Sopenharmony_ci if (rtransferr->compute_global_bo && !rtransferr->b.is_user_ptr) { 508bf215546Sopenharmony_ci r600_compute_global_transfer_unmap(ctx, transfer); 509bf215546Sopenharmony_ci return; 510bf215546Sopenharmony_ci } 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_ci if (transfer->usage & PIPE_MAP_WRITE && 513bf215546Sopenharmony_ci !(transfer->usage & PIPE_MAP_FLUSH_EXPLICIT)) 514bf215546Sopenharmony_ci r600_buffer_do_flush_region(ctx, transfer, &transfer->box); 515bf215546Sopenharmony_ci 516bf215546Sopenharmony_ci r600_resource_reference(&rtransfer->staging, NULL); 517bf215546Sopenharmony_ci assert(rtransfer->b.staging == NULL); /* for threaded context only */ 518bf215546Sopenharmony_ci pipe_resource_reference(&transfer->resource, NULL); 519bf215546Sopenharmony_ci 520bf215546Sopenharmony_ci /* Don't use pool_transfers_unsync. We are always in the driver 521bf215546Sopenharmony_ci * thread. */ 522bf215546Sopenharmony_ci slab_free(&rctx->pool_transfers, transfer); 523bf215546Sopenharmony_ci} 524bf215546Sopenharmony_ci 525bf215546Sopenharmony_civoid r600_buffer_subdata(struct pipe_context *ctx, 526bf215546Sopenharmony_ci struct pipe_resource *buffer, 527bf215546Sopenharmony_ci unsigned usage, unsigned offset, 528bf215546Sopenharmony_ci unsigned size, const void *data) 529bf215546Sopenharmony_ci{ 530bf215546Sopenharmony_ci struct pipe_transfer *transfer = NULL; 531bf215546Sopenharmony_ci struct pipe_box box; 532bf215546Sopenharmony_ci uint8_t *map = NULL; 533bf215546Sopenharmony_ci 534bf215546Sopenharmony_ci usage |= PIPE_MAP_WRITE; 535bf215546Sopenharmony_ci 536bf215546Sopenharmony_ci if (!(usage & PIPE_MAP_DIRECTLY)) 537bf215546Sopenharmony_ci usage |= PIPE_MAP_DISCARD_RANGE; 538bf215546Sopenharmony_ci 539bf215546Sopenharmony_ci u_box_1d(offset, size, &box); 540bf215546Sopenharmony_ci map = r600_buffer_transfer_map(ctx, buffer, 0, usage, &box, &transfer); 541bf215546Sopenharmony_ci if (!map) 542bf215546Sopenharmony_ci return; 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_ci memcpy(map, data, size); 545bf215546Sopenharmony_ci r600_buffer_transfer_unmap(ctx, transfer); 546bf215546Sopenharmony_ci} 547bf215546Sopenharmony_ci 548bf215546Sopenharmony_cistatic struct r600_resource * 549bf215546Sopenharmony_cir600_alloc_buffer_struct(struct pipe_screen *screen, 550bf215546Sopenharmony_ci const struct pipe_resource *templ) 551bf215546Sopenharmony_ci{ 552bf215546Sopenharmony_ci struct r600_resource *rbuffer; 553bf215546Sopenharmony_ci 554bf215546Sopenharmony_ci rbuffer = MALLOC_STRUCT(r600_resource); 555bf215546Sopenharmony_ci 556bf215546Sopenharmony_ci rbuffer->b.b = *templ; 557bf215546Sopenharmony_ci rbuffer->b.b.next = NULL; 558bf215546Sopenharmony_ci pipe_reference_init(&rbuffer->b.b.reference, 1); 559bf215546Sopenharmony_ci rbuffer->b.b.screen = screen; 560bf215546Sopenharmony_ci 561bf215546Sopenharmony_ci threaded_resource_init(&rbuffer->b.b, false); 562bf215546Sopenharmony_ci 563bf215546Sopenharmony_ci rbuffer->buf = NULL; 564bf215546Sopenharmony_ci rbuffer->bind_history = 0; 565bf215546Sopenharmony_ci rbuffer->immed_buffer = NULL; 566bf215546Sopenharmony_ci rbuffer->compute_global_bo = false; 567bf215546Sopenharmony_ci util_range_init(&rbuffer->valid_buffer_range); 568bf215546Sopenharmony_ci return rbuffer; 569bf215546Sopenharmony_ci} 570bf215546Sopenharmony_ci 571bf215546Sopenharmony_cistruct pipe_resource *r600_buffer_create(struct pipe_screen *screen, 572bf215546Sopenharmony_ci const struct pipe_resource *templ, 573bf215546Sopenharmony_ci unsigned alignment) 574bf215546Sopenharmony_ci{ 575bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; 576bf215546Sopenharmony_ci struct r600_resource *rbuffer = r600_alloc_buffer_struct(screen, templ); 577bf215546Sopenharmony_ci 578bf215546Sopenharmony_ci r600_init_resource_fields(rscreen, rbuffer, templ->width0, alignment); 579bf215546Sopenharmony_ci 580bf215546Sopenharmony_ci if (templ->flags & PIPE_RESOURCE_FLAG_SPARSE) 581bf215546Sopenharmony_ci rbuffer->flags |= RADEON_FLAG_SPARSE; 582bf215546Sopenharmony_ci 583bf215546Sopenharmony_ci if (!r600_alloc_resource(rscreen, rbuffer)) { 584bf215546Sopenharmony_ci FREE(rbuffer); 585bf215546Sopenharmony_ci return NULL; 586bf215546Sopenharmony_ci } 587bf215546Sopenharmony_ci return &rbuffer->b.b; 588bf215546Sopenharmony_ci} 589bf215546Sopenharmony_ci 590bf215546Sopenharmony_cistruct pipe_resource *r600_aligned_buffer_create(struct pipe_screen *screen, 591bf215546Sopenharmony_ci unsigned flags, 592bf215546Sopenharmony_ci unsigned usage, 593bf215546Sopenharmony_ci unsigned size, 594bf215546Sopenharmony_ci unsigned alignment) 595bf215546Sopenharmony_ci{ 596bf215546Sopenharmony_ci struct pipe_resource buffer; 597bf215546Sopenharmony_ci 598bf215546Sopenharmony_ci memset(&buffer, 0, sizeof buffer); 599bf215546Sopenharmony_ci buffer.target = PIPE_BUFFER; 600bf215546Sopenharmony_ci buffer.format = PIPE_FORMAT_R8_UNORM; 601bf215546Sopenharmony_ci buffer.bind = 0; 602bf215546Sopenharmony_ci buffer.usage = usage; 603bf215546Sopenharmony_ci buffer.flags = flags; 604bf215546Sopenharmony_ci buffer.width0 = size; 605bf215546Sopenharmony_ci buffer.height0 = 1; 606bf215546Sopenharmony_ci buffer.depth0 = 1; 607bf215546Sopenharmony_ci buffer.array_size = 1; 608bf215546Sopenharmony_ci return r600_buffer_create(screen, &buffer, alignment); 609bf215546Sopenharmony_ci} 610bf215546Sopenharmony_ci 611bf215546Sopenharmony_cistruct pipe_resource * 612bf215546Sopenharmony_cir600_buffer_from_user_memory(struct pipe_screen *screen, 613bf215546Sopenharmony_ci const struct pipe_resource *templ, 614bf215546Sopenharmony_ci void *user_memory) 615bf215546Sopenharmony_ci{ 616bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; 617bf215546Sopenharmony_ci struct radeon_winsys *ws = rscreen->ws; 618bf215546Sopenharmony_ci struct r600_resource *rbuffer; 619bf215546Sopenharmony_ci 620bf215546Sopenharmony_ci if ((templ->bind & PIPE_BIND_GLOBAL) && 621bf215546Sopenharmony_ci (templ->bind & PIPE_BIND_COMPUTE_RESOURCE)) { 622bf215546Sopenharmony_ci rbuffer = r600_resource(r600_compute_global_buffer_create(screen, templ)); 623bf215546Sopenharmony_ci ((struct r600_resource_global *)rbuffer)->chunk->real_buffer = rbuffer; 624bf215546Sopenharmony_ci } else { 625bf215546Sopenharmony_ci rbuffer = r600_alloc_buffer_struct(screen, templ); 626bf215546Sopenharmony_ci } 627bf215546Sopenharmony_ci 628bf215546Sopenharmony_ci rbuffer->domains = RADEON_DOMAIN_GTT; 629bf215546Sopenharmony_ci rbuffer->flags = 0; 630bf215546Sopenharmony_ci rbuffer->b.is_user_ptr = true; 631bf215546Sopenharmony_ci util_range_add(&rbuffer->b.b, &rbuffer->valid_buffer_range, 0, templ->width0); 632bf215546Sopenharmony_ci util_range_add(&rbuffer->b.b, &rbuffer->b.valid_buffer_range, 0, templ->width0); 633bf215546Sopenharmony_ci 634bf215546Sopenharmony_ci /* Convert a user pointer to a buffer. */ 635bf215546Sopenharmony_ci rbuffer->buf = ws->buffer_from_ptr(ws, user_memory, templ->width0, 636bf215546Sopenharmony_ci templ->usage == PIPE_USAGE_IMMUTABLE? RADEON_FLAG_READ_ONLY : 0); 637bf215546Sopenharmony_ci if (!rbuffer->buf) { 638bf215546Sopenharmony_ci FREE(rbuffer); 639bf215546Sopenharmony_ci return NULL; 640bf215546Sopenharmony_ci } 641bf215546Sopenharmony_ci 642bf215546Sopenharmony_ci if (rscreen->info.r600_has_virtual_memory) 643bf215546Sopenharmony_ci rbuffer->gpu_address = 644bf215546Sopenharmony_ci ws->buffer_get_virtual_address(rbuffer->buf); 645bf215546Sopenharmony_ci else 646bf215546Sopenharmony_ci rbuffer->gpu_address = 0; 647bf215546Sopenharmony_ci 648bf215546Sopenharmony_ci rbuffer->vram_usage = 0; 649bf215546Sopenharmony_ci rbuffer->gart_usage = templ->width0; 650bf215546Sopenharmony_ci 651bf215546Sopenharmony_ci return &rbuffer->b.b; 652bf215546Sopenharmony_ci} 653