i965: drop brw->gen in favor of devinfo->gen
[mesa.git] / src / mesa / drivers / dri / i965 / intel_buffer_objects.c
1 /*
2 * Copyright 2003 VMware, Inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26 /**
27 * @file intel_buffer_objects.c
28 *
29 * This provides core GL buffer object functionality.
30 */
31
32 #include "main/imports.h"
33 #include "main/mtypes.h"
34 #include "main/macros.h"
35 #include "main/streaming-load-memcpy.h"
36 #include "main/bufferobj.h"
37 #include "x86/common_x86_asm.h"
38
39 #include "brw_context.h"
40 #include "intel_blit.h"
41 #include "intel_buffer_objects.h"
42 #include "intel_batchbuffer.h"
43 #include "intel_tiled_memcpy.h"
44
45 static void
46 mark_buffer_gpu_usage(struct intel_buffer_object *intel_obj,
47 uint32_t offset, uint32_t size)
48 {
49 intel_obj->gpu_active_start = MIN2(intel_obj->gpu_active_start, offset);
50 intel_obj->gpu_active_end = MAX2(intel_obj->gpu_active_end, offset + size);
51 }
52
53 static void
54 mark_buffer_inactive(struct intel_buffer_object *intel_obj)
55 {
56 intel_obj->gpu_active_start = ~0;
57 intel_obj->gpu_active_end = 0;
58 }
59
60 static void
61 mark_buffer_valid_data(struct intel_buffer_object *intel_obj,
62 uint32_t offset, uint32_t size)
63 {
64 intel_obj->valid_data_start = MIN2(intel_obj->valid_data_start, offset);
65 intel_obj->valid_data_end = MAX2(intel_obj->valid_data_end, offset + size);
66 }
67
68 static void
69 mark_buffer_invalid(struct intel_buffer_object *intel_obj)
70 {
71 intel_obj->valid_data_start = ~0;
72 intel_obj->valid_data_end = 0;
73 }
74
75 /** Allocates a new brw_bo to store the data for the buffer object. */
76 static void
77 alloc_buffer_object(struct brw_context *brw,
78 struct intel_buffer_object *intel_obj)
79 {
80 const struct gl_context *ctx = &brw->ctx;
81
82 uint64_t size = intel_obj->Base.Size;
83 if (ctx->Const.RobustAccess) {
84 /* Pad out buffer objects with an extra 2kB (half a page).
85 *
86 * When pushing UBOs, we need to safeguard against 3DSTATE_CONSTANT_*
87 * reading out of bounds memory. The application might bind a UBO that's
88 * smaller than what the program expects. Ideally, we'd bind an extra
89 * push buffer containing zeros, but we have a limited number of those,
90 * so it's not always viable. Our only safe option is to pad all buffer
91 * objects by the maximum push data length, so that it will never read
92 * past the end of a BO.
93 *
94 * This is unfortunate, but it should result in at most 1 extra page,
95 * which probably isn't too terrible.
96 */
97 size += 64 * 32; /* max read length of 64 256-bit units */
98 }
99 intel_obj->buffer = brw_bo_alloc(brw->bufmgr, "bufferobj", size, 64);
100
101 /* the buffer might be bound as a uniform buffer, need to update it
102 */
103 if (intel_obj->Base.UsageHistory & USAGE_UNIFORM_BUFFER)
104 brw->ctx.NewDriverState |= BRW_NEW_UNIFORM_BUFFER;
105 if (intel_obj->Base.UsageHistory & USAGE_SHADER_STORAGE_BUFFER)
106 brw->ctx.NewDriverState |= BRW_NEW_UNIFORM_BUFFER;
107 if (intel_obj->Base.UsageHistory & USAGE_TEXTURE_BUFFER)
108 brw->ctx.NewDriverState |= BRW_NEW_TEXTURE_BUFFER;
109 if (intel_obj->Base.UsageHistory & USAGE_ATOMIC_COUNTER_BUFFER)
110 brw->ctx.NewDriverState |= BRW_NEW_ATOMIC_BUFFER;
111
112 mark_buffer_inactive(intel_obj);
113 mark_buffer_invalid(intel_obj);
114 }
115
116 static void
117 release_buffer(struct intel_buffer_object *intel_obj)
118 {
119 brw_bo_unreference(intel_obj->buffer);
120 intel_obj->buffer = NULL;
121 }
122
123 /**
124 * The NewBufferObject() driver hook.
125 *
126 * Allocates a new intel_buffer_object structure and initializes it.
127 *
128 * There is some duplication between mesa's bufferobjects and our
129 * bufmgr buffers. Both have an integer handle and a hashtable to
130 * lookup an opaque structure. It would be nice if the handles and
131 * internal structure where somehow shared.
132 */
133 static struct gl_buffer_object *
134 brw_new_buffer_object(struct gl_context * ctx, GLuint name)
135 {
136 struct intel_buffer_object *obj = CALLOC_STRUCT(intel_buffer_object);
137 if (!obj) {
138 _mesa_error_no_memory(__func__);
139 return NULL;
140 }
141
142 _mesa_initialize_buffer_object(ctx, &obj->Base, name);
143
144 obj->buffer = NULL;
145
146 return &obj->Base;
147 }
148
149 /**
150 * The DeleteBuffer() driver hook.
151 *
152 * Deletes a single OpenGL buffer object. Used by glDeleteBuffers().
153 */
154 static void
155 brw_delete_buffer(struct gl_context * ctx, struct gl_buffer_object *obj)
156 {
157 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
158
159 assert(intel_obj);
160
161 /* Buffer objects are automatically unmapped when deleting according
162 * to the spec, but Mesa doesn't do UnmapBuffer for us at context destroy
163 * (though it does if you call glDeleteBuffers)
164 */
165 _mesa_buffer_unmap_all_mappings(ctx, obj);
166
167 brw_bo_unreference(intel_obj->buffer);
168 _mesa_delete_buffer_object(ctx, obj);
169 }
170
171
172 /**
173 * The BufferData() driver hook.
174 *
175 * Implements glBufferData(), which recreates a buffer object's data store
176 * and populates it with the given data, if present.
177 *
178 * Any data that was previously stored in the buffer object is lost.
179 *
180 * \return true for success, false if out of memory
181 */
182 static GLboolean
183 brw_buffer_data(struct gl_context *ctx,
184 GLenum target,
185 GLsizeiptrARB size,
186 const GLvoid *data,
187 GLenum usage,
188 GLbitfield storageFlags,
189 struct gl_buffer_object *obj)
190 {
191 struct brw_context *brw = brw_context(ctx);
192 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
193
194 /* Part of the ABI, but this function doesn't use it.
195 */
196 (void) target;
197
198 intel_obj->Base.Size = size;
199 intel_obj->Base.Usage = usage;
200 intel_obj->Base.StorageFlags = storageFlags;
201
202 assert(!obj->Mappings[MAP_USER].Pointer); /* Mesa should have unmapped it */
203 assert(!obj->Mappings[MAP_INTERNAL].Pointer);
204
205 if (intel_obj->buffer != NULL)
206 release_buffer(intel_obj);
207
208 if (size != 0) {
209 alloc_buffer_object(brw, intel_obj);
210 if (!intel_obj->buffer)
211 return false;
212
213 if (data != NULL) {
214 brw_bo_subdata(intel_obj->buffer, 0, size, data);
215 mark_buffer_valid_data(intel_obj, 0, size);
216 }
217 }
218
219 return true;
220 }
221
222
223 /**
224 * The BufferSubData() driver hook.
225 *
226 * Implements glBufferSubData(), which replaces a portion of the data in a
227 * buffer object.
228 *
229 * If the data range specified by (size + offset) extends beyond the end of
230 * the buffer or if data is NULL, no copy is performed.
231 */
232 static void
233 brw_buffer_subdata(struct gl_context *ctx,
234 GLintptrARB offset,
235 GLsizeiptrARB size,
236 const GLvoid *data,
237 struct gl_buffer_object *obj)
238 {
239 struct brw_context *brw = brw_context(ctx);
240 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
241 bool busy;
242
243 if (size == 0)
244 return;
245
246 assert(intel_obj);
247
248 /* See if we can unsynchronized write the data into the user's BO. This
249 * avoids GPU stalls in unfortunately common user patterns (uploading
250 * sequentially into a BO, with draw calls in between each upload).
251 *
252 * Once we've hit this path, we mark this GL BO as preferring stalling to
253 * blits, so that we can hopefully hit this path again in the future
254 * (otherwise, an app that might occasionally stall but mostly not will end
255 * up with blitting all the time, at the cost of bandwidth)
256 */
257 if (offset + size <= intel_obj->gpu_active_start ||
258 intel_obj->gpu_active_end <= offset ||
259 offset + size <= intel_obj->valid_data_start ||
260 intel_obj->valid_data_end <= offset) {
261 void *map = brw_bo_map(brw, intel_obj->buffer, MAP_WRITE | MAP_ASYNC);
262 memcpy(map + offset, data, size);
263 brw_bo_unmap(intel_obj->buffer);
264
265 if (intel_obj->gpu_active_end > intel_obj->gpu_active_start)
266 intel_obj->prefer_stall_to_blit = true;
267
268 mark_buffer_valid_data(intel_obj, offset, size);
269 return;
270 }
271
272 busy =
273 brw_bo_busy(intel_obj->buffer) ||
274 brw_batch_references(&brw->batch, intel_obj->buffer);
275
276 if (busy) {
277 if (size == intel_obj->Base.Size ||
278 (intel_obj->valid_data_start >= offset &&
279 intel_obj->valid_data_end <= offset + size)) {
280 /* Replace the current busy bo so the subdata doesn't stall. */
281 brw_bo_unreference(intel_obj->buffer);
282 alloc_buffer_object(brw, intel_obj);
283 } else if (!intel_obj->prefer_stall_to_blit) {
284 perf_debug("Using a blit copy to avoid stalling on "
285 "glBufferSubData(%ld, %ld) (%ldkb) to a busy "
286 "(%d-%d) / valid (%d-%d) buffer object.\n",
287 (long)offset, (long)offset + size, (long)(size/1024),
288 intel_obj->gpu_active_start,
289 intel_obj->gpu_active_end,
290 intel_obj->valid_data_start,
291 intel_obj->valid_data_end);
292 struct brw_bo *temp_bo =
293 brw_bo_alloc(brw->bufmgr, "subdata temp", size, 64);
294
295 brw_bo_subdata(temp_bo, 0, size, data);
296
297 intel_emit_linear_blit(brw,
298 intel_obj->buffer, offset,
299 temp_bo, 0,
300 size);
301
302 brw_bo_unreference(temp_bo);
303 mark_buffer_valid_data(intel_obj, offset, size);
304 return;
305 } else {
306 perf_debug("Stalling on glBufferSubData(%ld, %ld) (%ldkb) to a busy "
307 "(%d-%d) buffer object. Use glMapBufferRange() to "
308 "avoid this.\n",
309 (long)offset, (long)offset + size, (long)(size/1024),
310 intel_obj->gpu_active_start,
311 intel_obj->gpu_active_end);
312 intel_batchbuffer_flush(brw);
313 }
314 }
315
316 brw_bo_subdata(intel_obj->buffer, offset, size, data);
317 mark_buffer_inactive(intel_obj);
318 mark_buffer_valid_data(intel_obj, offset, size);
319 }
320
321
322 /**
323 * The GetBufferSubData() driver hook.
324 *
325 * Implements glGetBufferSubData(), which copies a subrange of a buffer
326 * object into user memory.
327 */
328 static void
329 brw_get_buffer_subdata(struct gl_context *ctx,
330 GLintptrARB offset,
331 GLsizeiptrARB size,
332 GLvoid *data,
333 struct gl_buffer_object *obj)
334 {
335 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
336 struct brw_context *brw = brw_context(ctx);
337
338 assert(intel_obj);
339 if (brw_batch_references(&brw->batch, intel_obj->buffer)) {
340 intel_batchbuffer_flush(brw);
341 }
342
343 unsigned int map_flags = MAP_READ;
344 mem_copy_fn memcpy_fn = memcpy;
345 #ifdef USE_SSE41
346 if (!intel_obj->buffer->cache_coherent && cpu_has_sse4_1) {
347 /* Rather than acquire a new WB mmaping of the buffer object and pull
348 * it into the CPU cache, keep using the WC mmap that we have for writes,
349 * and use the magic movntd instructions instead.
350 */
351 map_flags |= MAP_COHERENT;
352 memcpy_fn = (mem_copy_fn) _mesa_streaming_load_memcpy;
353 }
354 #endif
355
356 void *map = brw_bo_map(brw, intel_obj->buffer, map_flags);
357 if (unlikely(!map)) {
358 _mesa_error_no_memory(__func__);
359 return;
360 }
361 memcpy_fn(data, map + offset, size);
362 brw_bo_unmap(intel_obj->buffer);
363
364 mark_buffer_inactive(intel_obj);
365 }
366
367
368 /**
369 * The MapBufferRange() driver hook.
370 *
371 * This implements both glMapBufferRange() and glMapBuffer().
372 *
373 * The goal of this extension is to allow apps to accumulate their rendering
374 * at the same time as they accumulate their buffer object. Without it,
375 * you'd end up blocking on execution of rendering every time you mapped
376 * the buffer to put new data in.
377 *
378 * We support it in 3 ways: If unsynchronized, then don't bother
379 * flushing the batchbuffer before mapping the buffer, which can save blocking
380 * in many cases. If we would still block, and they allow the whole buffer
381 * to be invalidated, then just allocate a new buffer to replace the old one.
382 * If not, and we'd block, and they allow the subrange of the buffer to be
383 * invalidated, then we can make a new little BO, let them write into that,
384 * and blit it into the real BO at unmap time.
385 */
386 static void *
387 brw_map_buffer_range(struct gl_context *ctx,
388 GLintptr offset, GLsizeiptr length,
389 GLbitfield access, struct gl_buffer_object *obj,
390 gl_map_buffer_index index)
391 {
392 struct brw_context *brw = brw_context(ctx);
393 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
394
395 assert(intel_obj);
396
397 STATIC_ASSERT(GL_MAP_UNSYNCHRONIZED_BIT == MAP_ASYNC);
398 STATIC_ASSERT(GL_MAP_WRITE_BIT == MAP_WRITE);
399 STATIC_ASSERT(GL_MAP_READ_BIT == MAP_READ);
400 STATIC_ASSERT(GL_MAP_PERSISTENT_BIT == MAP_PERSISTENT);
401 STATIC_ASSERT(GL_MAP_COHERENT_BIT == MAP_COHERENT);
402 assert((access & MAP_INTERNAL_MASK) == 0);
403
404 /* _mesa_MapBufferRange (GL entrypoint) sets these, but the vbo module also
405 * internally uses our functions directly.
406 */
407 obj->Mappings[index].Offset = offset;
408 obj->Mappings[index].Length = length;
409 obj->Mappings[index].AccessFlags = access;
410
411 if (intel_obj->buffer == NULL) {
412 obj->Mappings[index].Pointer = NULL;
413 return NULL;
414 }
415
416 /* If the access is synchronized (like a normal buffer mapping), then get
417 * things flushed out so the later mapping syncs appropriately through GEM.
418 * If the user doesn't care about existing buffer contents and mapping would
419 * cause us to block, then throw out the old buffer.
420 *
421 * If they set INVALIDATE_BUFFER, we can pitch the current contents to
422 * achieve the required synchronization.
423 */
424 if (!(access & GL_MAP_UNSYNCHRONIZED_BIT)) {
425 if (brw_batch_references(&brw->batch, intel_obj->buffer)) {
426 if (access & GL_MAP_INVALIDATE_BUFFER_BIT) {
427 brw_bo_unreference(intel_obj->buffer);
428 alloc_buffer_object(brw, intel_obj);
429 } else {
430 perf_debug("Stalling on the GPU for mapping a busy buffer "
431 "object\n");
432 intel_batchbuffer_flush(brw);
433 }
434 } else if (brw_bo_busy(intel_obj->buffer) &&
435 (access & GL_MAP_INVALIDATE_BUFFER_BIT)) {
436 brw_bo_unreference(intel_obj->buffer);
437 alloc_buffer_object(brw, intel_obj);
438 }
439 }
440
441 if (access & MAP_WRITE)
442 mark_buffer_valid_data(intel_obj, offset, length);
443
444 /* If the user is mapping a range of an active buffer object but
445 * doesn't require the current contents of that range, make a new
446 * BO, and we'll copy what they put in there out at unmap or
447 * FlushRange time.
448 *
449 * That is, unless they're looking for a persistent mapping -- we would
450 * need to do blits in the MemoryBarrier call, and it's easier to just do a
451 * GPU stall and do a mapping.
452 */
453 if (!(access & (GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_PERSISTENT_BIT)) &&
454 (access & GL_MAP_INVALIDATE_RANGE_BIT) &&
455 brw_bo_busy(intel_obj->buffer)) {
456 /* Ensure that the base alignment of the allocation meets the alignment
457 * guarantees the driver has advertised to the application.
458 */
459 const unsigned alignment = ctx->Const.MinMapBufferAlignment;
460
461 intel_obj->map_extra[index] = (uintptr_t) offset % alignment;
462 intel_obj->range_map_bo[index] =
463 brw_bo_alloc(brw->bufmgr, "BO blit temp",
464 length + intel_obj->map_extra[index], alignment);
465 void *map = brw_bo_map(brw, intel_obj->range_map_bo[index], access);
466 obj->Mappings[index].Pointer = map + intel_obj->map_extra[index];
467 return obj->Mappings[index].Pointer;
468 }
469
470 void *map = brw_bo_map(brw, intel_obj->buffer, access);
471 if (!(access & GL_MAP_UNSYNCHRONIZED_BIT)) {
472 mark_buffer_inactive(intel_obj);
473 }
474
475 obj->Mappings[index].Pointer = map + offset;
476 return obj->Mappings[index].Pointer;
477 }
478
479 /**
480 * The FlushMappedBufferRange() driver hook.
481 *
482 * Implements glFlushMappedBufferRange(), which signifies that modifications
483 * have been made to a range of a mapped buffer, and it should be flushed.
484 *
485 * This is only used for buffers mapped with GL_MAP_FLUSH_EXPLICIT_BIT.
486 *
487 * Ideally we'd use a BO to avoid taking up cache space for the temporary
488 * data, but FlushMappedBufferRange may be followed by further writes to
489 * the pointer, so we would have to re-map after emitting our blit, which
490 * would defeat the point.
491 */
492 static void
493 brw_flush_mapped_buffer_range(struct gl_context *ctx,
494 GLintptr offset, GLsizeiptr length,
495 struct gl_buffer_object *obj,
496 gl_map_buffer_index index)
497 {
498 struct brw_context *brw = brw_context(ctx);
499 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
500
501 assert(obj->Mappings[index].AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT);
502
503 /* If we gave a direct mapping of the buffer instead of using a temporary,
504 * then there's nothing to do.
505 */
506 if (intel_obj->range_map_bo[index] == NULL)
507 return;
508
509 if (length == 0)
510 return;
511
512 /* Note that we're not unmapping our buffer while executing the blit. We
513 * need to have a mapping still at the end of this call, since the user
514 * gets to make further modifications and glFlushMappedBufferRange() calls.
515 * This is safe, because:
516 *
517 * - On LLC platforms, we're using a CPU mapping that's coherent with the
518 * GPU (except for the render caches), so the kernel doesn't need to do
519 * any flushing work for us except for what happens at batch exec time
520 * anyway.
521 *
522 * - On non-LLC platforms, we're using a GTT mapping that writes directly
523 * to system memory (except for the chipset cache that gets flushed at
524 * batch exec time).
525 *
526 * In both cases we don't need to stall for the previous blit to complete
527 * so we can re-map (and we definitely don't want to, since that would be
528 * slow): If the user edits a part of their buffer that's previously been
529 * blitted, then our lack of synchoronization is fine, because either
530 * they'll get some too-new data in the first blit and not do another blit
531 * of that area (but in that case the results are undefined), or they'll do
532 * another blit of that area and the complete newer data will land the
533 * second time.
534 */
535 intel_emit_linear_blit(brw,
536 intel_obj->buffer,
537 obj->Mappings[index].Offset + offset,
538 intel_obj->range_map_bo[index],
539 intel_obj->map_extra[index] + offset,
540 length);
541 mark_buffer_gpu_usage(intel_obj,
542 obj->Mappings[index].Offset + offset,
543 length);
544 }
545
546
547 /**
548 * The UnmapBuffer() driver hook.
549 *
550 * Implements glUnmapBuffer().
551 */
552 static GLboolean
553 brw_unmap_buffer(struct gl_context *ctx,
554 struct gl_buffer_object *obj,
555 gl_map_buffer_index index)
556 {
557 struct brw_context *brw = brw_context(ctx);
558 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
559
560 assert(intel_obj);
561 assert(obj->Mappings[index].Pointer);
562 if (intel_obj->range_map_bo[index] != NULL) {
563 brw_bo_unmap(intel_obj->range_map_bo[index]);
564
565 if (!(obj->Mappings[index].AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT)) {
566 intel_emit_linear_blit(brw,
567 intel_obj->buffer, obj->Mappings[index].Offset,
568 intel_obj->range_map_bo[index],
569 intel_obj->map_extra[index],
570 obj->Mappings[index].Length);
571 mark_buffer_gpu_usage(intel_obj, obj->Mappings[index].Offset,
572 obj->Mappings[index].Length);
573 }
574
575 /* Since we've emitted some blits to buffers that will (likely) be used
576 * in rendering operations in other cache domains in this batch, emit a
577 * flush. Once again, we wish for a domain tracker in libdrm to cover
578 * usage inside of a batchbuffer.
579 */
580 brw_emit_mi_flush(brw);
581
582 brw_bo_unreference(intel_obj->range_map_bo[index]);
583 intel_obj->range_map_bo[index] = NULL;
584 } else if (intel_obj->buffer != NULL) {
585 brw_bo_unmap(intel_obj->buffer);
586 }
587 obj->Mappings[index].Pointer = NULL;
588 obj->Mappings[index].Offset = 0;
589 obj->Mappings[index].Length = 0;
590
591 return true;
592 }
593
594 /**
595 * Gets a pointer to the object's BO, and marks the given range as being used
596 * on the GPU.
597 *
598 * Anywhere that uses buffer objects in the pipeline should be using this to
599 * mark the range of the buffer that is being accessed by the pipeline.
600 */
601 struct brw_bo *
602 intel_bufferobj_buffer(struct brw_context *brw,
603 struct intel_buffer_object *intel_obj,
604 uint32_t offset, uint32_t size, bool write)
605 {
606 /* This is needed so that things like transform feedback and texture buffer
607 * objects that need a BO but don't want to check that they exist for
608 * draw-time validation can just always get a BO from a GL buffer object.
609 */
610 if (intel_obj->buffer == NULL)
611 alloc_buffer_object(brw, intel_obj);
612
613 mark_buffer_gpu_usage(intel_obj, offset, size);
614
615 /* If writing, (conservatively) mark this section as having valid data. */
616 if (write)
617 mark_buffer_valid_data(intel_obj, offset, size);
618
619 return intel_obj->buffer;
620 }
621
622 /**
623 * The CopyBufferSubData() driver hook.
624 *
625 * Implements glCopyBufferSubData(), which copies a portion of one buffer
626 * object's data to another. Independent source and destination offsets
627 * are allowed.
628 */
629 static void
630 brw_copy_buffer_subdata(struct gl_context *ctx,
631 struct gl_buffer_object *src,
632 struct gl_buffer_object *dst,
633 GLintptr read_offset, GLintptr write_offset,
634 GLsizeiptr size)
635 {
636 struct brw_context *brw = brw_context(ctx);
637 struct intel_buffer_object *intel_src = intel_buffer_object(src);
638 struct intel_buffer_object *intel_dst = intel_buffer_object(dst);
639 struct brw_bo *src_bo, *dst_bo;
640
641 if (size == 0)
642 return;
643
644 dst_bo = intel_bufferobj_buffer(brw, intel_dst, write_offset, size, true);
645 src_bo = intel_bufferobj_buffer(brw, intel_src, read_offset, size, false);
646
647 intel_emit_linear_blit(brw,
648 dst_bo, write_offset,
649 src_bo, read_offset, size);
650
651 /* Since we've emitted some blits to buffers that will (likely) be used
652 * in rendering operations in other cache domains in this batch, emit a
653 * flush. Once again, we wish for a domain tracker in libdrm to cover
654 * usage inside of a batchbuffer.
655 */
656 brw_emit_mi_flush(brw);
657 }
658
659 void
660 intelInitBufferObjectFuncs(struct dd_function_table *functions)
661 {
662 functions->NewBufferObject = brw_new_buffer_object;
663 functions->DeleteBuffer = brw_delete_buffer;
664 functions->BufferData = brw_buffer_data;
665 functions->BufferSubData = brw_buffer_subdata;
666 functions->GetBufferSubData = brw_get_buffer_subdata;
667 functions->MapBufferRange = brw_map_buffer_range;
668 functions->FlushMappedBufferRange = brw_flush_mapped_buffer_range;
669 functions->UnmapBuffer = brw_unmap_buffer;
670 functions->CopyBufferSubData = brw_copy_buffer_subdata;
671 }