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