4 #include "nouveau_bufferobj.h"
5 #include "nouveau_buffers.h"
6 #include "nouveau_context.h"
7 #include "nouveau_drm.h"
8 #include "nouveau_object.h"
9 #include "nouveau_msg.h"
11 #define NOUVEAU_MEM_FREE(mem) do { \
12 nouveau_mem_free(ctx, (mem)); \
16 #define DEBUG(fmt,args...) do { \
17 if (NOUVEAU_DEBUG & DEBUG_BUFFEROBJ) { \
18 fprintf(stderr, "%s: "fmt, __func__, ##args); \
23 nouveau_bo_download_from_screen(GLcontext
*ctx
, GLuint offset
, GLuint size
,
24 struct gl_buffer_object
*bo
)
26 nouveauContextPtr nmesa
= NOUVEAU_CONTEXT(ctx
);
27 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)bo
;
30 DEBUG("bo=%p, offset=%d, size=%d\n", bo
, offset
, size
);
32 /* If there's a permanent backing store, blit directly into it */
34 if (nbo
->cpu_mem
!= nbo
->gpu_mem
) {
36 nouveau_memformat_flat_emit(ctx
, nbo
->cpu_mem
,
38 offset
, offset
, size
);
42 in_mem
= nouveau_mem_alloc(ctx
, NOUVEAU_MEM_AGP
, size
, 0);
44 DEBUG("....via GART\n");
45 /* otherwise, try blitting to faster memory and
48 nouveau_memformat_flat_emit(ctx
, in_mem
, nbo
->gpu_mem
,
50 nouveau_notifier_wait_nop(ctx
, nmesa
->syncNotifier
,
52 _mesa_memcpy(nbo
->cpu_mem_sys
+ offset
,
54 NOUVEAU_MEM_FREE(in_mem
);
56 DEBUG("....direct VRAM copy\n");
57 /* worst case, copy directly from vram */
58 _mesa_memcpy(nbo
->cpu_mem_sys
+ offset
,
59 nbo
->gpu_mem
+ offset
,
68 nouveau_bo_upload_to_screen(GLcontext
*ctx
, GLuint offset
, GLuint size
,
69 struct gl_buffer_object
*bo
)
71 nouveauContextPtr nmesa
= NOUVEAU_CONTEXT(ctx
);
72 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)bo
;
75 DEBUG("bo=%p, offset=%d, size=%d\n", bo
, offset
, size
);
78 if (nbo
->cpu_mem
!= nbo
->gpu_mem
) {
80 nouveau_memformat_flat_emit(ctx
, nbo
->gpu_mem
,
82 offset
, offset
, size
);
85 out_mem
= nouveau_mem_alloc(ctx
, NOUVEAU_MEM_AGP
|
89 DEBUG("....via GART\n");
90 _mesa_memcpy(out_mem
->map
,
91 nbo
->cpu_mem_sys
+ offset
, size
);
92 nouveau_memformat_flat_emit(ctx
, nbo
->gpu_mem
, out_mem
,
94 nouveau_notifier_wait_nop(ctx
, nmesa
->syncNotifier
,
96 NOUVEAU_MEM_FREE(out_mem
);
98 DEBUG("....direct VRAM copy\n");
99 _mesa_memcpy(nbo
->gpu_mem
->map
+ offset
,
100 nbo
->cpu_mem_sys
+ offset
,
109 nouveau_bo_move_in(GLcontext
*ctx
, struct gl_buffer_object
*bo
)
111 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)bo
;
113 DEBUG("bo=%p\n", bo
);
117 assert(nbo
->gpu_mem_flags
);
119 nbo
->gpu_mem
= nouveau_mem_alloc(ctx
, nbo
->gpu_mem_flags
|
122 assert(nbo
->gpu_mem
);
124 if (nbo
->cpu_mem_flags
) {
125 if ((nbo
->cpu_mem_flags
|NOUVEAU_MEM_MAPPED
) != nbo
->gpu_mem
->type
) {
126 DEBUG("..need cpu_mem buffer\n");
128 nbo
->cpu_mem
= nouveau_mem_alloc(ctx
,
134 DEBUG("....alloc ok, kill sys_mem buffer\n");
135 _mesa_memcpy(nbo
->cpu_mem
->map
,
136 nbo
->cpu_mem_sys
, bo
->Size
);
137 FREE(nbo
->cpu_mem_sys
);
140 DEBUG("..cpu direct access to GPU buffer\n");
141 nbo
->cpu_mem
= nbo
->gpu_mem
;
144 nouveau_bo_upload_to_screen(ctx
, 0, bo
->Size
, bo
);
146 bo
->OnCard
= GL_TRUE
;
151 nouveau_bo_move_out(GLcontext
*ctx
, struct gl_buffer_object
*bo
)
153 nouveauContextPtr nmesa
= NOUVEAU_CONTEXT(ctx
);
154 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)bo
;
157 DEBUG("bo=%p\n", bo
);
161 nr_dirty
= nouveau_bo_download_dirty(ctx
, bo
);
163 if (nr_dirty
&& nbo
->cpu_mem
!= nbo
->gpu_mem
)
164 nouveau_notifier_wait_nop(ctx
, nmesa
->syncNotifier
,
166 DEBUG("..destroy cpu_mem buffer\n");
167 nbo
->cpu_mem_sys
= malloc(bo
->Size
);
168 assert(nbo
->cpu_mem_sys
);
169 _mesa_memcpy(nbo
->cpu_mem_sys
, nbo
->cpu_mem
->map
, bo
->Size
);
170 if (nbo
->cpu_mem
== nbo
->gpu_mem
)
173 NOUVEAU_MEM_FREE(nbo
->cpu_mem
);
175 NOUVEAU_MEM_FREE(nbo
->gpu_mem
);
177 bo
->OnCard
= GL_FALSE
;
182 nouveau_bo_choose_storage_method(GLcontext
*ctx
, GLenum usage
,
183 struct gl_buffer_object
*bo
)
185 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)bo
;
190 /* Client source, changes often, used by GL many times */
191 case GL_DYNAMIC_DRAW_ARB
:
192 gpu_type
= NOUVEAU_MEM_AGP
| NOUVEAU_MEM_FB_ACCEPTABLE
;
193 cpu_type
= NOUVEAU_MEM_AGP
;
195 /* GL source, changes often, client reads many times */
196 case GL_DYNAMIC_READ_ARB
:
197 /* Client source, specified once, used by GL many times */
198 case GL_STATIC_DRAW_ARB
:
199 /* GL source, specified once, client reads many times */
200 case GL_STATIC_READ_ARB
:
201 /* Client source, specified once, used by GL a few times */
202 case GL_STREAM_DRAW_ARB
:
203 /* GL source, specified once, client reads a few times */
204 case GL_STREAM_READ_ARB
:
205 /* GL source, changes often, used by GL many times*/
206 case GL_DYNAMIC_COPY_ARB
:
207 /* GL source, specified once, used by GL many times */
208 case GL_STATIC_COPY_ARB
:
209 /* GL source, specified once, used by GL a few times */
210 case GL_STREAM_COPY_ARB
:
211 gpu_type
= NOUVEAU_MEM_FB
;
217 nbo
->gpu_mem_flags
= gpu_type
;
218 nbo
->cpu_mem_flags
= cpu_type
;
223 nouveau_bo_init_storage(GLcontext
*ctx
, GLuint valid_gpu_access
,
227 struct gl_buffer_object
*bo
)
229 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)bo
;
231 DEBUG("bo=%p\n", bo
);
233 /* Free up previous buffers if we can't reuse them */
234 if (nbo
->usage
!= usage
||
235 (nbo
->gpu_mem
&& (nbo
->gpu_mem
->size
!= size
))) {
236 if (nbo
->cpu_mem_sys
)
237 FREE(nbo
->cpu_mem_sys
);
239 if (nbo
->cpu_mem
!= nbo
->gpu_mem
)
240 NOUVEAU_MEM_FREE(nbo
->cpu_mem
);
245 NOUVEAU_MEM_FREE(nbo
->gpu_mem
);
247 bo
->OnCard
= GL_FALSE
;
248 nbo
->cpu_mem_sys
= calloc(1, size
);
251 nouveau_bo_choose_storage_method(ctx
, usage
, bo
);
252 /* Force off flags that may not be ok for a given buffer */
253 nbo
->gpu_mem_flags
&= valid_gpu_access
;
259 GLvoid
*map
= nouveau_bo_map(ctx
, GL_WRITE_ONLY_ARB
, bo
);
260 _mesa_memcpy(map
, data
, size
);
261 nouveau_bo_dirty_all(ctx
, GL_FALSE
, bo
);
262 nouveau_bo_unmap(ctx
, bo
);
267 nouveau_bo_map(GLcontext
*ctx
, GLenum access
, struct gl_buffer_object
*bo
)
269 nouveauContextPtr nmesa
= NOUVEAU_CONTEXT(ctx
);
270 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)bo
;
272 DEBUG("bo=%p, access=%s\n", bo
, _mesa_lookup_enum_by_nr(access
));
275 (access
== GL_READ_ONLY_ARB
|| access
== GL_READ_WRITE_ARB
)) {
278 DEBUG("..on card\n");
279 nr_dirty
= nouveau_bo_download_dirty(ctx
, bo
);
281 /* nouveau_bo_download_dirty won't wait unless it needs to
282 * free a temp buffer, which isn't the case if cpu_mem is
285 if (nr_dirty
&& nbo
->cpu_mem
&& nbo
->cpu_mem
!= nbo
->gpu_mem
)
286 nouveau_notifier_wait_nop(ctx
, nmesa
->syncNotifier
,
291 DEBUG("..access via cpu_mem\n");
292 return nbo
->cpu_mem
->map
;
294 DEBUG("..access via cpu_mem_sys\n");
295 return nbo
->cpu_mem_sys
;
300 nouveau_bo_unmap(GLcontext
*ctx
, struct gl_buffer_object
*bo
)
302 DEBUG("unmap bo=%p\n", bo
);
306 nouveau_bo_gpu_ref(GLcontext
*ctx
, struct gl_buffer_object
*bo
)
308 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)bo
;
310 assert(nbo
->mapped
== GL_FALSE
);
315 nouveau_bo_move_in(ctx
, bo
);
316 bo
->OnCard
= GL_TRUE
;
318 nouveau_bo_upload_dirty(ctx
, bo
);
320 return nouveau_mem_gpu_offset_get(ctx
, nbo
->gpu_mem
);
324 nouveau_bo_dirty_linear(GLcontext
*ctx
, GLboolean on_card
,
325 uint32_t offset
, uint32_t size
,
326 struct gl_buffer_object
*bo
)
328 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)bo
;
329 nouveau_bufferobj_dirty
*dirty
;
330 uint32_t start
= offset
;
331 uint32_t end
= offset
+ size
;
334 if (nbo
->cpu_mem
== nbo
->gpu_mem
)
337 dirty
= on_card
? &nbo
->gpu_dirty
: &nbo
->cpu_dirty
;
339 DEBUG("on_card=%d, offset=%d, size=%d, bo=%p\n",
340 on_card
, offset
, size
, bo
);
342 for (i
=0; i
<dirty
->nr_dirty
; i
++) {
343 nouveau_bufferobj_region
*r
= &dirty
->dirty
[i
];
346 if (start
>= r
->start
&& end
<= r
->end
) {
347 DEBUG("..already dirty\n");
351 /* add to the end of a region */
352 if (start
>= r
->start
&& start
<= r
->end
) {
354 DEBUG("..extend end of region\n");
360 /* add to the start of a region */
361 if (start
< r
->start
&& end
>= r
->end
) {
362 DEBUG("..extend start of region\n");
364 /* .. and to the end */
366 DEBUG("....and end\n");
374 DEBUG("..new dirty\n");
376 dirty
->dirty
= realloc(dirty
->dirty
,
377 sizeof(nouveau_bufferobj_region
) *
379 dirty
->dirty
[dirty
->nr_dirty
- 1].start
= start
;
380 dirty
->dirty
[dirty
->nr_dirty
- 1].end
= end
;
384 nouveau_bo_dirty_all(GLcontext
*ctx
, GLboolean on_card
,
385 struct gl_buffer_object
*bo
)
387 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)bo
;
388 nouveau_bufferobj_dirty
*dirty
;
390 dirty
= on_card
? &nbo
->gpu_dirty
: &nbo
->cpu_dirty
;
392 DEBUG("dirty all\n");
393 if (dirty
->nr_dirty
) {
399 nouveau_bo_dirty_linear(ctx
, on_card
, 0, bo
->Size
, bo
);
403 nouveau_bo_upload_dirty(GLcontext
*ctx
, struct gl_buffer_object
*bo
)
405 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)bo
;
406 nouveau_bufferobj_dirty
*dirty
= &nbo
->cpu_dirty
;
410 nr_dirty
= dirty
->nr_dirty
;
416 for (i
=0; i
<nr_dirty
; i
++) {
417 nouveau_bufferobj_region
*r
= &dirty
->dirty
[i
];
419 DEBUG("dirty %d: o=0x%08x, s=0x%08x\n",
420 i
, r
->start
, r
->end
- r
->start
);
421 nouveau_bo_upload_to_screen(ctx
,
422 r
->start
, r
->end
- r
->start
, bo
);
433 nouveau_bo_download_dirty(GLcontext
*ctx
, struct gl_buffer_object
*bo
)
435 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)bo
;
436 nouveau_bufferobj_dirty
*dirty
= &nbo
->gpu_dirty
;
440 nr_dirty
= dirty
->nr_dirty
;
446 for (i
=0; i
<nr_dirty
; i
++) {
447 nouveau_bufferobj_region
*r
= &dirty
->dirty
[i
];
449 DEBUG("dirty %d: o=0x%08x, s=0x%08x\n",
450 i
, r
->start
, r
->end
- r
->start
);
451 nouveau_bo_download_from_screen(ctx
,
453 r
->end
- r
->start
, bo
);
464 nouveauBindBuffer(GLcontext
*ctx
, GLenum target
, struct gl_buffer_object
*obj
)
468 static struct gl_buffer_object
*
469 nouveauNewBufferObject(GLcontext
*ctx
, GLuint buffer
, GLenum target
)
471 nouveau_buffer_object
*nbo
;
473 nbo
= CALLOC_STRUCT(nouveau_buffer_object_t
);
475 _mesa_initialize_buffer_object(&nbo
->mesa
, buffer
, target
);
476 DEBUG("bo=%p\n", nbo
);
478 return nbo
? &nbo
->mesa
: NULL
;
482 nouveauDeleteBuffer(GLcontext
*ctx
, struct gl_buffer_object
*obj
)
484 nouveau_buffer_object
*nbo
= (nouveau_buffer_object
*)obj
;
486 if (nbo
->gpu_dirty
.nr_dirty
)
487 FREE(nbo
->gpu_dirty
.dirty
);
488 if (nbo
->cpu_dirty
.nr_dirty
)
489 FREE(nbo
->cpu_dirty
.dirty
);
490 if (nbo
->cpu_mem
) nouveau_mem_free(ctx
, nbo
->cpu_mem
);
491 if (nbo
->gpu_mem
) nouveau_mem_free(ctx
, nbo
->gpu_mem
);
493 _mesa_delete_buffer_object(ctx
, obj
);
497 nouveauBufferData(GLcontext
*ctx
, GLenum target
, GLsizeiptrARB size
,
498 const GLvoid
*data
, GLenum usage
,
499 struct gl_buffer_object
*obj
)
503 DEBUG("target=%s, size=%d, data=%p, usage=%s, obj=%p\n",
504 _mesa_lookup_enum_by_nr(target
),
506 _mesa_lookup_enum_by_nr(usage
),
510 case GL_ELEMENT_ARRAY_BUFFER_ARB
:
514 gpu_flags
= NOUVEAU_BO_VRAM_OK
| NOUVEAU_BO_GART_OK
;
517 nouveau_bo_init_storage(ctx
, gpu_flags
, size
, data
, usage
, obj
);
521 nouveauBufferSubData(GLcontext
*ctx
, GLenum target
, GLintptrARB offset
,
522 GLsizeiptrARB size
, const GLvoid
*data
,
523 struct gl_buffer_object
*obj
)
527 DEBUG("target=%s, offset=0x%x, size=%d, data=%p, obj=%p\n",
528 _mesa_lookup_enum_by_nr(target
),
529 (GLuint
)offset
, (GLuint
)size
, data
, obj
);
531 out
= nouveau_bo_map(ctx
, GL_WRITE_ONLY_ARB
, obj
);
532 _mesa_memcpy(out
+ offset
, data
, size
);
533 nouveau_bo_dirty_linear(ctx
, GL_FALSE
, offset
, size
, obj
);
534 nouveau_bo_unmap(ctx
, obj
);
538 nouveauGetBufferSubData(GLcontext
*ctx
, GLenum target
, GLintptrARB offset
,
539 GLsizeiptrARB size
, GLvoid
*data
,
540 struct gl_buffer_object
*obj
)
544 DEBUG("target=%s, offset=0x%x, size=%d, data=%p, obj=%p\n",
545 _mesa_lookup_enum_by_nr(target
),
546 (GLuint
)offset
, (GLuint
)size
, data
, obj
);
548 in
= nouveau_bo_map(ctx
, GL_READ_ONLY_ARB
, obj
);
549 _mesa_memcpy(data
, in
+ offset
, size
);
550 nouveau_bo_unmap(ctx
, obj
);
554 nouveauMapBuffer(GLcontext
*ctx
, GLenum target
, GLenum access
,
555 struct gl_buffer_object
*obj
)
557 DEBUG("target=%s, access=%s, obj=%p\n",
558 _mesa_lookup_enum_by_nr(target
),
559 _mesa_lookup_enum_by_nr(access
),
563 /* Already mapped.. */
567 /* Have to pass READ_WRITE here, nouveau_bo_map will only ensure that
568 * the cpu_mem buffer is up-to-date if we ask for read access.
570 * However, even if the client only asks for write access, we're still
571 * forced to reupload the entire buffer. So, we need the cpu_mem buffer
572 * to have the correct data all the time.
574 obj
->Pointer
= nouveau_bo_map(ctx
, GL_READ_WRITE_ARB
, obj
);
576 /* The GL spec says that a client attempting to write to a bufferobj
577 * mapped READ_ONLY object may have unpredictable results, possibly
578 * even program termination.
580 * We're going to use this, and only mark the buffer as dirtied if
581 * the client asks for write access.
583 if (target
!= GL_READ_ONLY_ARB
) {
584 /* We have no way of knowing what was modified by the client,
585 * so the entire buffer gets dirtied. */
586 nouveau_bo_dirty_all(ctx
, GL_FALSE
, obj
);
593 nouveauUnmapBuffer(GLcontext
*ctx
, GLenum target
, struct gl_buffer_object
*obj
)
595 DEBUG("target=%s, obj=%p\n", _mesa_lookup_enum_by_nr(target
), obj
);
597 assert(obj
->Pointer
);
599 nouveau_bo_unmap(ctx
, obj
);
605 nouveauInitBufferObjects(GLcontext
*ctx
)
607 ctx
->Driver
.BindBuffer
= nouveauBindBuffer
;
608 ctx
->Driver
.NewBufferObject
= nouveauNewBufferObject
;
609 ctx
->Driver
.DeleteBuffer
= nouveauDeleteBuffer
;
610 ctx
->Driver
.BufferData
= nouveauBufferData
;
611 ctx
->Driver
.BufferSubData
= nouveauBufferSubData
;
612 ctx
->Driver
.GetBufferSubData
= nouveauGetBufferSubData
;
613 ctx
->Driver
.MapBuffer
= nouveauMapBuffer
;
614 ctx
->Driver
.UnmapBuffer
= nouveauUnmapBuffer
;