2 #include "util/u_inlines.h"
3 #include "util/u_memory.h"
4 #include "util/u_math.h"
5 #include "util/u_surface.h"
7 #include "nouveau_screen.h"
8 #include "nouveau_context.h"
9 #include "nouveau_winsys.h"
10 #include "nouveau_fence.h"
11 #include "nouveau_buffer.h"
12 #include "nouveau_mm.h"
14 #define NOUVEAU_TRANSFER_PUSHBUF_THRESHOLD 192
16 struct nouveau_transfer
{
17 struct pipe_transfer base
;
20 struct nouveau_bo
*bo
;
21 struct nouveau_mm_allocation
*mm
;
25 static INLINE
struct nouveau_transfer
*
26 nouveau_transfer(struct pipe_transfer
*transfer
)
28 return (struct nouveau_transfer
*)transfer
;
32 nouveau_buffer_malloc(struct nv04_resource
*buf
)
35 buf
->data
= align_malloc(buf
->base
.width0
, NOUVEAU_MIN_BUFFER_MAP_ALIGN
);
40 nouveau_buffer_allocate(struct nouveau_screen
*screen
,
41 struct nv04_resource
*buf
, unsigned domain
)
43 uint32_t size
= buf
->base
.width0
;
45 if (buf
->base
.bind
& (PIPE_BIND_CONSTANT_BUFFER
|
46 PIPE_BIND_COMPUTE_RESOURCE
|
47 PIPE_BIND_SHADER_RESOURCE
))
48 size
= align(size
, 0x100);
50 if (domain
== NOUVEAU_BO_VRAM
) {
51 buf
->mm
= nouveau_mm_allocate(screen
->mm_VRAM
, size
,
52 &buf
->bo
, &buf
->offset
);
54 return nouveau_buffer_allocate(screen
, buf
, NOUVEAU_BO_GART
);
55 NOUVEAU_DRV_STAT(screen
, buf_obj_current_bytes_vid
, buf
->base
.width0
);
57 if (domain
== NOUVEAU_BO_GART
) {
58 buf
->mm
= nouveau_mm_allocate(screen
->mm_GART
, size
,
59 &buf
->bo
, &buf
->offset
);
62 NOUVEAU_DRV_STAT(screen
, buf_obj_current_bytes_sys
, buf
->base
.width0
);
65 if (!nouveau_buffer_malloc(buf
))
70 buf
->address
= buf
->bo
->offset
+ buf
->offset
;
76 release_allocation(struct nouveau_mm_allocation
**mm
,
77 struct nouveau_fence
*fence
)
79 nouveau_fence_work(fence
, nouveau_mm_free_work
, *mm
);
84 nouveau_buffer_release_gpu_storage(struct nv04_resource
*buf
)
86 nouveau_bo_ref(NULL
, &buf
->bo
);
89 release_allocation(&buf
->mm
, buf
->fence
);
91 if (buf
->domain
== NOUVEAU_BO_VRAM
)
92 NOUVEAU_DRV_STAT_RES(buf
, buf_obj_current_bytes_vid
, -(uint64_t)buf
->base
.width0
);
93 if (buf
->domain
== NOUVEAU_BO_GART
)
94 NOUVEAU_DRV_STAT_RES(buf
, buf_obj_current_bytes_sys
, -(uint64_t)buf
->base
.width0
);
100 nouveau_buffer_reallocate(struct nouveau_screen
*screen
,
101 struct nv04_resource
*buf
, unsigned domain
)
103 nouveau_buffer_release_gpu_storage(buf
);
105 nouveau_fence_ref(NULL
, &buf
->fence
);
106 nouveau_fence_ref(NULL
, &buf
->fence_wr
);
108 buf
->status
&= NOUVEAU_BUFFER_STATUS_REALLOC_MASK
;
110 return nouveau_buffer_allocate(screen
, buf
, domain
);
114 nouveau_buffer_destroy(struct pipe_screen
*pscreen
,
115 struct pipe_resource
*presource
)
117 struct nv04_resource
*res
= nv04_resource(presource
);
119 nouveau_buffer_release_gpu_storage(res
);
121 if (res
->data
&& !(res
->status
& NOUVEAU_BUFFER_STATUS_USER_MEMORY
))
122 align_free(res
->data
);
124 nouveau_fence_ref(NULL
, &res
->fence
);
125 nouveau_fence_ref(NULL
, &res
->fence_wr
);
129 NOUVEAU_DRV_STAT(nouveau_screen(pscreen
), buf_obj_current_count
, -1);
133 nouveau_transfer_staging(struct nouveau_context
*nv
,
134 struct nouveau_transfer
*tx
, boolean permit_pb
)
136 const unsigned adj
= tx
->base
.box
.x
& NOUVEAU_MIN_BUFFER_MAP_ALIGN_MASK
;
137 const unsigned size
= align(tx
->base
.box
.width
, 4) + adj
;
142 if ((size
<= NOUVEAU_TRANSFER_PUSHBUF_THRESHOLD
) && permit_pb
) {
143 tx
->map
= align_malloc(size
, NOUVEAU_MIN_BUFFER_MAP_ALIGN
);
148 nouveau_mm_allocate(nv
->screen
->mm_GART
, size
, &tx
->bo
, &tx
->offset
);
151 if (!nouveau_bo_map(tx
->bo
, 0, NULL
))
152 tx
->map
= (uint8_t *)tx
->bo
->map
+ tx
->offset
;
158 /* Maybe just migrate to GART right away if we actually need to do this. */
160 nouveau_transfer_read(struct nouveau_context
*nv
, struct nouveau_transfer
*tx
)
162 struct nv04_resource
*buf
= nv04_resource(tx
->base
.resource
);
163 const unsigned base
= tx
->base
.box
.x
;
164 const unsigned size
= tx
->base
.box
.width
;
166 NOUVEAU_DRV_STAT(nv
->screen
, buf_read_bytes_staging_vid
, size
);
168 nv
->copy_data(nv
, tx
->bo
, tx
->offset
, NOUVEAU_BO_GART
,
169 buf
->bo
, buf
->offset
+ base
, buf
->domain
, size
);
171 if (nouveau_bo_wait(tx
->bo
, NOUVEAU_BO_RD
, nv
->client
))
175 memcpy(buf
->data
+ base
, tx
->map
, size
);
181 nouveau_transfer_write(struct nouveau_context
*nv
, struct nouveau_transfer
*tx
,
182 unsigned offset
, unsigned size
)
184 struct nv04_resource
*buf
= nv04_resource(tx
->base
.resource
);
185 uint8_t *data
= tx
->map
+ offset
;
186 const unsigned base
= tx
->base
.box
.x
+ offset
;
187 const boolean can_cb
= !((base
| size
) & 3);
190 memcpy(data
, buf
->data
+ base
, size
);
192 buf
->status
|= NOUVEAU_BUFFER_STATUS_DIRTY
;
194 if (buf
->domain
== NOUVEAU_BO_VRAM
)
195 NOUVEAU_DRV_STAT(nv
->screen
, buf_write_bytes_staging_vid
, size
);
196 if (buf
->domain
== NOUVEAU_BO_GART
)
197 NOUVEAU_DRV_STAT(nv
->screen
, buf_write_bytes_staging_sys
, size
);
200 nv
->copy_data(nv
, buf
->bo
, buf
->offset
+ base
, buf
->domain
,
201 tx
->bo
, tx
->offset
+ offset
, NOUVEAU_BO_GART
, size
);
203 if ((buf
->base
.bind
& PIPE_BIND_CONSTANT_BUFFER
) && nv
->push_cb
&& can_cb
)
204 nv
->push_cb(nv
, buf
->bo
, buf
->domain
, buf
->offset
, buf
->base
.width0
,
205 base
, size
/ 4, (const uint32_t *)data
);
207 nv
->push_data(nv
, buf
->bo
, buf
->offset
+ base
, buf
->domain
, size
, data
);
209 nouveau_fence_ref(nv
->screen
->fence
.current
, &buf
->fence
);
210 nouveau_fence_ref(nv
->screen
->fence
.current
, &buf
->fence_wr
);
214 static INLINE boolean
215 nouveau_buffer_sync(struct nv04_resource
*buf
, unsigned rw
)
217 if (rw
== PIPE_TRANSFER_READ
) {
220 NOUVEAU_DRV_STAT_RES(buf
, buf_non_kernel_fence_sync_count
,
221 !nouveau_fence_signalled(buf
->fence_wr
));
222 if (!nouveau_fence_wait(buf
->fence_wr
))
227 NOUVEAU_DRV_STAT_RES(buf
, buf_non_kernel_fence_sync_count
,
228 !nouveau_fence_signalled(buf
->fence
));
229 if (!nouveau_fence_wait(buf
->fence
))
232 nouveau_fence_ref(NULL
, &buf
->fence
);
234 nouveau_fence_ref(NULL
, &buf
->fence_wr
);
239 static INLINE boolean
240 nouveau_buffer_busy(struct nv04_resource
*buf
, unsigned rw
)
242 if (rw
== PIPE_TRANSFER_READ
)
243 return (buf
->fence_wr
&& !nouveau_fence_signalled(buf
->fence_wr
));
245 return (buf
->fence
&& !nouveau_fence_signalled(buf
->fence
));
249 nouveau_buffer_transfer_init(struct nouveau_transfer
*tx
,
250 struct pipe_resource
*resource
,
251 const struct pipe_box
*box
,
254 tx
->base
.resource
= resource
;
256 tx
->base
.usage
= usage
;
257 tx
->base
.box
.x
= box
->x
;
260 tx
->base
.box
.width
= box
->width
;
261 tx
->base
.box
.height
= 1;
262 tx
->base
.box
.depth
= 1;
264 tx
->base
.layer_stride
= 0;
271 nouveau_buffer_transfer_del(struct nouveau_context
*nv
,
272 struct nouveau_transfer
*tx
)
275 if (likely(tx
->bo
)) {
276 nouveau_bo_ref(NULL
, &tx
->bo
);
278 release_allocation(&tx
->mm
, nv
->screen
->fence
.current
);
281 (tx
->base
.box
.x
& NOUVEAU_MIN_BUFFER_MAP_ALIGN_MASK
));
287 nouveau_buffer_cache(struct nouveau_context
*nv
, struct nv04_resource
*buf
)
289 struct nouveau_transfer tx
;
291 tx
.base
.resource
= &buf
->base
;
293 tx
.base
.box
.width
= buf
->base
.width0
;
298 if (!nouveau_buffer_malloc(buf
))
300 if (!(buf
->status
& NOUVEAU_BUFFER_STATUS_DIRTY
))
302 nv
->stats
.buf_cache_count
++;
304 if (!nouveau_transfer_staging(nv
, &tx
, FALSE
))
307 ret
= nouveau_transfer_read(nv
, &tx
);
309 buf
->status
&= ~NOUVEAU_BUFFER_STATUS_DIRTY
;
310 memcpy(buf
->data
, tx
.map
, buf
->base
.width0
);
312 nouveau_buffer_transfer_del(nv
, &tx
);
317 #define NOUVEAU_TRANSFER_DISCARD \
318 (PIPE_TRANSFER_DISCARD_RANGE | PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE)
320 static INLINE boolean
321 nouveau_buffer_should_discard(struct nv04_resource
*buf
, unsigned usage
)
323 if (!(usage
& PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE
))
325 if (unlikely(buf
->base
.bind
& PIPE_BIND_SHARED
))
327 return buf
->mm
&& nouveau_buffer_busy(buf
, PIPE_TRANSFER_WRITE
);
331 nouveau_buffer_transfer_map(struct pipe_context
*pipe
,
332 struct pipe_resource
*resource
,
333 unsigned level
, unsigned usage
,
334 const struct pipe_box
*box
,
335 struct pipe_transfer
**ptransfer
)
337 struct nouveau_context
*nv
= nouveau_context(pipe
);
338 struct nv04_resource
*buf
= nv04_resource(resource
);
339 struct nouveau_transfer
*tx
= MALLOC_STRUCT(nouveau_transfer
);
345 nouveau_buffer_transfer_init(tx
, resource
, box
, usage
);
346 *ptransfer
= &tx
->base
;
348 if (usage
& PIPE_TRANSFER_READ
)
349 NOUVEAU_DRV_STAT(nv
->screen
, buf_transfers_rd
, 1);
350 if (usage
& PIPE_TRANSFER_WRITE
)
351 NOUVEAU_DRV_STAT(nv
->screen
, buf_transfers_wr
, 1);
353 if (buf
->domain
== NOUVEAU_BO_VRAM
) {
354 if (usage
& NOUVEAU_TRANSFER_DISCARD
) {
355 if (usage
& PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE
)
356 buf
->status
&= NOUVEAU_BUFFER_STATUS_REALLOC_MASK
;
357 nouveau_transfer_staging(nv
, tx
, TRUE
);
359 if (buf
->status
& NOUVEAU_BUFFER_STATUS_GPU_WRITING
) {
361 align_free(buf
->data
);
364 nouveau_transfer_staging(nv
, tx
, FALSE
);
365 nouveau_transfer_read(nv
, tx
);
367 if (usage
& PIPE_TRANSFER_WRITE
)
368 nouveau_transfer_staging(nv
, tx
, TRUE
);
370 nouveau_buffer_cache(nv
, buf
);
373 return buf
->data
? (buf
->data
+ box
->x
) : tx
->map
;
375 if (unlikely(buf
->domain
== 0)) {
376 return buf
->data
+ box
->x
;
379 if (nouveau_buffer_should_discard(buf
, usage
)) {
380 int ref
= buf
->base
.reference
.count
- 1;
381 nouveau_buffer_reallocate(nv
->screen
, buf
, buf
->domain
);
382 if (ref
> 0) /* any references inside context possible ? */
383 nv
->invalidate_resource_storage(nv
, &buf
->base
, ref
);
386 ret
= nouveau_bo_map(buf
->bo
,
387 buf
->mm
? 0 : nouveau_screen_transfer_flags(usage
),
393 map
= (uint8_t *)buf
->bo
->map
+ buf
->offset
+ box
->x
;
395 /* using kernel fences only if !buf->mm */
396 if ((usage
& PIPE_TRANSFER_UNSYNCHRONIZED
) || !buf
->mm
)
399 if (nouveau_buffer_busy(buf
, usage
& PIPE_TRANSFER_READ_WRITE
)) {
400 if (unlikely(usage
& PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE
)) {
401 /* Discarding was not possible, must sync because
402 * subsequent transfers might use UNSYNCHRONIZED. */
403 nouveau_buffer_sync(buf
, usage
& PIPE_TRANSFER_READ_WRITE
);
405 if (usage
& PIPE_TRANSFER_DISCARD_RANGE
) {
406 nouveau_transfer_staging(nv
, tx
, TRUE
);
409 if (nouveau_buffer_busy(buf
, PIPE_TRANSFER_READ
)) {
410 if (usage
& PIPE_TRANSFER_DONTBLOCK
)
413 nouveau_buffer_sync(buf
, usage
& PIPE_TRANSFER_READ_WRITE
);
415 nouveau_transfer_staging(nv
, tx
, TRUE
);
417 memcpy(tx
->map
, map
, box
->width
);
429 nouveau_buffer_transfer_flush_region(struct pipe_context
*pipe
,
430 struct pipe_transfer
*transfer
,
431 const struct pipe_box
*box
)
433 struct nouveau_transfer
*tx
= nouveau_transfer(transfer
);
435 nouveau_transfer_write(nouveau_context(pipe
), tx
, box
->x
, box
->width
);
439 nouveau_buffer_transfer_unmap(struct pipe_context
*pipe
,
440 struct pipe_transfer
*transfer
)
442 struct nouveau_context
*nv
= nouveau_context(pipe
);
443 struct nouveau_transfer
*tx
= nouveau_transfer(transfer
);
444 struct nv04_resource
*buf
= nv04_resource(transfer
->resource
);
446 if (tx
->base
.usage
& PIPE_TRANSFER_WRITE
) {
447 if (!(tx
->base
.usage
& PIPE_TRANSFER_FLUSH_EXPLICIT
) && tx
->map
)
448 nouveau_transfer_write(nv
, tx
, 0, tx
->base
.box
.width
);
450 if (likely(buf
->domain
)) {
451 const uint8_t bind
= buf
->base
.bind
;
452 /* make sure we invalidate dedicated caches */
453 if (bind
& (PIPE_BIND_VERTEX_BUFFER
| PIPE_BIND_INDEX_BUFFER
))
454 nv
->vbo_dirty
= TRUE
;
455 if (bind
& (PIPE_BIND_CONSTANT_BUFFER
))
460 if (!tx
->bo
&& (tx
->base
.usage
& PIPE_TRANSFER_WRITE
))
461 NOUVEAU_DRV_STAT(nv
->screen
, buf_write_bytes_direct
, tx
->base
.box
.width
);
463 nouveau_buffer_transfer_del(nv
, tx
);
469 nouveau_copy_buffer(struct nouveau_context
*nv
,
470 struct nv04_resource
*dst
, unsigned dstx
,
471 struct nv04_resource
*src
, unsigned srcx
, unsigned size
)
473 assert(dst
->base
.target
== PIPE_BUFFER
&& src
->base
.target
== PIPE_BUFFER
);
475 if (likely(dst
->domain
) && likely(src
->domain
)) {
477 dst
->bo
, dst
->offset
+ dstx
, dst
->domain
,
478 src
->bo
, src
->offset
+ srcx
, src
->domain
, size
);
480 dst
->status
|= NOUVEAU_BUFFER_STATUS_GPU_WRITING
;
481 nouveau_fence_ref(nv
->screen
->fence
.current
, &dst
->fence
);
482 nouveau_fence_ref(nv
->screen
->fence
.current
, &dst
->fence_wr
);
484 src
->status
|= NOUVEAU_BUFFER_STATUS_GPU_READING
;
485 nouveau_fence_ref(nv
->screen
->fence
.current
, &src
->fence
);
487 struct pipe_box src_box
;
491 src_box
.width
= size
;
494 util_resource_copy_region(&nv
->pipe
,
495 &dst
->base
, 0, dstx
, 0, 0,
496 &src
->base
, 0, &src_box
);
502 nouveau_resource_map_offset(struct nouveau_context
*nv
,
503 struct nv04_resource
*res
, uint32_t offset
,
506 if (unlikely(res
->status
& NOUVEAU_BUFFER_STATUS_USER_MEMORY
))
507 return res
->data
+ offset
;
509 if (res
->domain
== NOUVEAU_BO_VRAM
) {
510 if (!res
->data
|| (res
->status
& NOUVEAU_BUFFER_STATUS_GPU_WRITING
))
511 nouveau_buffer_cache(nv
, res
);
513 if (res
->domain
!= NOUVEAU_BO_GART
)
514 return res
->data
+ offset
;
518 rw
= (flags
& NOUVEAU_BO_WR
) ? PIPE_TRANSFER_WRITE
: PIPE_TRANSFER_READ
;
519 nouveau_buffer_sync(res
, rw
);
520 if (nouveau_bo_map(res
->bo
, 0, NULL
))
523 if (nouveau_bo_map(res
->bo
, flags
, nv
->client
))
526 return (uint8_t *)res
->bo
->map
+ res
->offset
+ offset
;
530 const struct u_resource_vtbl nouveau_buffer_vtbl
=
532 u_default_resource_get_handle
, /* get_handle */
533 nouveau_buffer_destroy
, /* resource_destroy */
534 nouveau_buffer_transfer_map
, /* transfer_map */
535 nouveau_buffer_transfer_flush_region
, /* transfer_flush_region */
536 nouveau_buffer_transfer_unmap
, /* transfer_unmap */
537 u_default_transfer_inline_write
/* transfer_inline_write */
540 struct pipe_resource
*
541 nouveau_buffer_create(struct pipe_screen
*pscreen
,
542 const struct pipe_resource
*templ
)
544 struct nouveau_screen
*screen
= nouveau_screen(pscreen
);
545 struct nv04_resource
*buffer
;
548 buffer
= CALLOC_STRUCT(nv04_resource
);
552 buffer
->base
= *templ
;
553 buffer
->vtbl
= &nouveau_buffer_vtbl
;
554 pipe_reference_init(&buffer
->base
.reference
, 1);
555 buffer
->base
.screen
= pscreen
;
557 if (buffer
->base
.bind
&
558 (screen
->vidmem_bindings
& screen
->sysmem_bindings
)) {
559 switch (buffer
->base
.usage
) {
560 case PIPE_USAGE_DEFAULT
:
561 case PIPE_USAGE_IMMUTABLE
:
562 case PIPE_USAGE_STATIC
:
563 buffer
->domain
= NOUVEAU_BO_VRAM
;
565 case PIPE_USAGE_DYNAMIC
:
566 /* For most apps, we'd have to do staging transfers to avoid sync
567 * with this usage, and GART -> GART copies would be suboptimal.
569 buffer
->domain
= NOUVEAU_BO_VRAM
;
571 case PIPE_USAGE_STAGING
:
572 case PIPE_USAGE_STREAM
:
573 buffer
->domain
= NOUVEAU_BO_GART
;
580 if (buffer
->base
.bind
& screen
->vidmem_bindings
)
581 buffer
->domain
= NOUVEAU_BO_VRAM
;
583 if (buffer
->base
.bind
& screen
->sysmem_bindings
)
584 buffer
->domain
= NOUVEAU_BO_GART
;
586 ret
= nouveau_buffer_allocate(screen
, buffer
, buffer
->domain
);
591 if (buffer
->domain
== NOUVEAU_BO_VRAM
&& screen
->hint_buf_keep_sysmem_copy
)
592 nouveau_buffer_cache(NULL
, buffer
);
594 NOUVEAU_DRV_STAT(screen
, buf_obj_current_count
, 1);
596 return &buffer
->base
;
604 struct pipe_resource
*
605 nouveau_user_buffer_create(struct pipe_screen
*pscreen
, void *ptr
,
606 unsigned bytes
, unsigned bind
)
608 struct nv04_resource
*buffer
;
610 buffer
= CALLOC_STRUCT(nv04_resource
);
614 pipe_reference_init(&buffer
->base
.reference
, 1);
615 buffer
->vtbl
= &nouveau_buffer_vtbl
;
616 buffer
->base
.screen
= pscreen
;
617 buffer
->base
.format
= PIPE_FORMAT_R8_UNORM
;
618 buffer
->base
.usage
= PIPE_USAGE_IMMUTABLE
;
619 buffer
->base
.bind
= bind
;
620 buffer
->base
.width0
= bytes
;
621 buffer
->base
.height0
= 1;
622 buffer
->base
.depth0
= 1;
625 buffer
->status
= NOUVEAU_BUFFER_STATUS_USER_MEMORY
;
627 return &buffer
->base
;
630 static INLINE boolean
631 nouveau_buffer_data_fetch(struct nouveau_context
*nv
, struct nv04_resource
*buf
,
632 struct nouveau_bo
*bo
, unsigned offset
, unsigned size
)
634 if (!nouveau_buffer_malloc(buf
))
636 if (nouveau_bo_map(bo
, NOUVEAU_BO_RD
, nv
->client
))
638 memcpy(buf
->data
, (uint8_t *)bo
->map
+ offset
, size
);
642 /* Migrate a linear buffer (vertex, index, constants) USER -> GART -> VRAM. */
644 nouveau_buffer_migrate(struct nouveau_context
*nv
,
645 struct nv04_resource
*buf
, const unsigned new_domain
)
647 struct nouveau_screen
*screen
= nv
->screen
;
648 struct nouveau_bo
*bo
;
649 const unsigned old_domain
= buf
->domain
;
650 unsigned size
= buf
->base
.width0
;
654 assert(new_domain
!= old_domain
);
656 if (new_domain
== NOUVEAU_BO_GART
&& old_domain
== 0) {
657 if (!nouveau_buffer_allocate(screen
, buf
, new_domain
))
659 ret
= nouveau_bo_map(buf
->bo
, 0, nv
->client
);
662 memcpy((uint8_t *)buf
->bo
->map
+ buf
->offset
, buf
->data
, size
);
663 align_free(buf
->data
);
665 if (old_domain
!= 0 && new_domain
!= 0) {
666 struct nouveau_mm_allocation
*mm
= buf
->mm
;
668 if (new_domain
== NOUVEAU_BO_VRAM
) {
669 /* keep a system memory copy of our data in case we hit a fallback */
670 if (!nouveau_buffer_data_fetch(nv
, buf
, buf
->bo
, buf
->offset
, size
))
672 if (nouveau_mesa_debug
)
673 debug_printf("migrating %u KiB to VRAM\n", size
/ 1024);
676 offset
= buf
->offset
;
680 nouveau_buffer_allocate(screen
, buf
, new_domain
);
682 nv
->copy_data(nv
, buf
->bo
, buf
->offset
, new_domain
,
683 bo
, offset
, old_domain
, buf
->base
.width0
);
685 nouveau_bo_ref(NULL
, &bo
);
687 release_allocation(&mm
, screen
->fence
.current
);
689 if (new_domain
== NOUVEAU_BO_VRAM
&& old_domain
== 0) {
690 struct nouveau_transfer tx
;
691 if (!nouveau_buffer_allocate(screen
, buf
, NOUVEAU_BO_VRAM
))
693 tx
.base
.resource
= &buf
->base
;
695 tx
.base
.box
.width
= buf
->base
.width0
;
698 if (!nouveau_transfer_staging(nv
, &tx
, FALSE
))
700 nouveau_transfer_write(nv
, &tx
, 0, tx
.base
.box
.width
);
701 nouveau_buffer_transfer_del(nv
, &tx
);
705 assert(buf
->domain
== new_domain
);
709 /* Migrate data from glVertexAttribPointer(non-VBO) user buffers to GART.
710 * We'd like to only allocate @size bytes here, but then we'd have to rebase
711 * the vertex indices ...
714 nouveau_user_buffer_upload(struct nouveau_context
*nv
,
715 struct nv04_resource
*buf
,
716 unsigned base
, unsigned size
)
718 struct nouveau_screen
*screen
= nouveau_screen(buf
->base
.screen
);
721 assert(buf
->status
& NOUVEAU_BUFFER_STATUS_USER_MEMORY
);
723 buf
->base
.width0
= base
+ size
;
724 if (!nouveau_buffer_reallocate(screen
, buf
, NOUVEAU_BO_GART
))
727 ret
= nouveau_bo_map(buf
->bo
, 0, nv
->client
);
730 memcpy((uint8_t *)buf
->bo
->map
+ buf
->offset
+ base
, buf
->data
+ base
, size
);
736 /* Scratch data allocation. */
739 nouveau_scratch_bo_alloc(struct nouveau_context
*nv
, struct nouveau_bo
**pbo
,
742 return nouveau_bo_new(nv
->screen
->device
, NOUVEAU_BO_GART
| NOUVEAU_BO_MAP
,
743 4096, size
, NULL
, pbo
);
747 nouveau_scratch_runout_release(struct nouveau_context
*nv
)
749 if (!nv
->scratch
.nr_runout
)
752 --nv
->scratch
.nr_runout
;
753 nouveau_bo_ref(NULL
, &nv
->scratch
.runout
[nv
->scratch
.nr_runout
]);
754 } while (nv
->scratch
.nr_runout
);
756 FREE(nv
->scratch
.runout
);
758 nv
->scratch
.runout
= NULL
;
761 /* Allocate an extra bo if we can't fit everything we need simultaneously.
762 * (Could happen for very large user arrays.)
764 static INLINE boolean
765 nouveau_scratch_runout(struct nouveau_context
*nv
, unsigned size
)
768 const unsigned n
= nv
->scratch
.nr_runout
++;
770 nv
->scratch
.runout
= REALLOC(nv
->scratch
.runout
,
771 (n
+ 0) * sizeof(*nv
->scratch
.runout
),
772 (n
+ 1) * sizeof(*nv
->scratch
.runout
));
773 nv
->scratch
.runout
[n
] = NULL
;
775 ret
= nouveau_scratch_bo_alloc(nv
, &nv
->scratch
.runout
[n
], size
);
777 ret
= nouveau_bo_map(nv
->scratch
.runout
[n
], 0, NULL
);
779 nouveau_bo_ref(NULL
, &nv
->scratch
.runout
[--nv
->scratch
.nr_runout
]);
782 nv
->scratch
.current
= nv
->scratch
.runout
[n
];
783 nv
->scratch
.offset
= 0;
784 nv
->scratch
.end
= size
;
785 nv
->scratch
.map
= nv
->scratch
.current
->map
;
790 /* Continue to next scratch buffer, if available (no wrapping, large enough).
791 * Allocate it if it has not yet been created.
793 static INLINE boolean
794 nouveau_scratch_next(struct nouveau_context
*nv
, unsigned size
)
796 struct nouveau_bo
*bo
;
798 const unsigned i
= (nv
->scratch
.id
+ 1) % NOUVEAU_MAX_SCRATCH_BUFS
;
800 if ((size
> nv
->scratch
.bo_size
) || (i
== nv
->scratch
.wrap
))
804 bo
= nv
->scratch
.bo
[i
];
806 ret
= nouveau_scratch_bo_alloc(nv
, &bo
, nv
->scratch
.bo_size
);
809 nv
->scratch
.bo
[i
] = bo
;
811 nv
->scratch
.current
= bo
;
812 nv
->scratch
.offset
= 0;
813 nv
->scratch
.end
= nv
->scratch
.bo_size
;
815 ret
= nouveau_bo_map(bo
, NOUVEAU_BO_WR
, nv
->client
);
817 nv
->scratch
.map
= bo
->map
;
822 nouveau_scratch_more(struct nouveau_context
*nv
, unsigned min_size
)
826 ret
= nouveau_scratch_next(nv
, min_size
);
828 ret
= nouveau_scratch_runout(nv
, min_size
);
833 /* Copy data to a scratch buffer and return address & bo the data resides in. */
835 nouveau_scratch_data(struct nouveau_context
*nv
,
836 const void *data
, unsigned base
, unsigned size
,
837 struct nouveau_bo
**bo
)
839 unsigned bgn
= MAX2(base
, nv
->scratch
.offset
);
840 unsigned end
= bgn
+ size
;
842 if (end
>= nv
->scratch
.end
) {
844 if (!nouveau_scratch_more(nv
, end
))
848 nv
->scratch
.offset
= align(end
, 4);
850 memcpy(nv
->scratch
.map
+ bgn
, (const uint8_t *)data
+ base
, size
);
852 *bo
= nv
->scratch
.current
;
853 return (*bo
)->offset
+ (bgn
- base
);
857 nouveau_scratch_get(struct nouveau_context
*nv
,
858 unsigned size
, uint64_t *gpu_addr
, struct nouveau_bo
**pbo
)
860 unsigned bgn
= nv
->scratch
.offset
;
861 unsigned end
= nv
->scratch
.offset
+ size
;
863 if (end
>= nv
->scratch
.end
) {
865 if (!nouveau_scratch_more(nv
, end
))
869 nv
->scratch
.offset
= align(end
, 4);
871 *pbo
= nv
->scratch
.current
;
872 *gpu_addr
= nv
->scratch
.current
->offset
+ bgn
;
873 return nv
->scratch
.map
+ bgn
;