i965/wm: use proper API buffer size for the surfaces.
[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/bufferobj.h"
36
37 #include "brw_context.h"
38 #include "intel_blit.h"
39 #include "intel_buffer_objects.h"
40 #include "intel_batchbuffer.h"
41
42 /**
43 * Map a buffer object; issue performance warnings if mapping causes stalls.
44 *
45 * This matches the drm_intel_bo_map API, but takes an additional human-readable
46 * name for the buffer object to use in the performance debug message.
47 */
48 int
49 brw_bo_map(struct brw_context *brw,
50 drm_intel_bo *bo, int write_enable,
51 const char *bo_name)
52 {
53 if (likely(!brw->perf_debug) || !drm_intel_bo_busy(bo))
54 return drm_intel_bo_map(bo, write_enable);
55
56 double start_time = get_time();
57
58 int ret = drm_intel_bo_map(bo, write_enable);
59
60 perf_debug("CPU mapping a busy %s BO stalled and took %.03f ms.\n",
61 bo_name, (get_time() - start_time) * 1000);
62
63 return ret;
64 }
65
66 int
67 brw_bo_map_gtt(struct brw_context *brw, drm_intel_bo *bo, const char *bo_name)
68 {
69 if (likely(!brw->perf_debug) || !drm_intel_bo_busy(bo))
70 return drm_intel_gem_bo_map_gtt(bo);
71
72 double start_time = get_time();
73
74 int ret = drm_intel_gem_bo_map_gtt(bo);
75
76 perf_debug("GTT mapping a busy %s BO stalled and took %.03f ms.\n",
77 bo_name, (get_time() - start_time) * 1000);
78
79 return ret;
80 }
81
82 static void
83 mark_buffer_gpu_usage(struct intel_buffer_object *intel_obj,
84 uint32_t offset, uint32_t size)
85 {
86 intel_obj->gpu_active_start = MIN2(intel_obj->gpu_active_start, offset);
87 intel_obj->gpu_active_end = MAX2(intel_obj->gpu_active_end, offset + size);
88 }
89
90 static void
91 mark_buffer_inactive(struct intel_buffer_object *intel_obj)
92 {
93 intel_obj->gpu_active_start = ~0;
94 intel_obj->gpu_active_end = 0;
95 }
96
97 /** Allocates a new drm_intel_bo to store the data for the buffer object. */
98 static void
99 alloc_buffer_object(struct brw_context *brw,
100 struct intel_buffer_object *intel_obj)
101 {
102 intel_obj->buffer = drm_intel_bo_alloc(brw->bufmgr, "bufferobj",
103 intel_obj->Base.Size, 64);
104
105 /* the buffer might be bound as a uniform buffer, need to update it
106 */
107 if (intel_obj->Base.UsageHistory & USAGE_UNIFORM_BUFFER)
108 brw->ctx.NewDriverState |= BRW_NEW_UNIFORM_BUFFER;
109 if (intel_obj->Base.UsageHistory & USAGE_SHADER_STORAGE_BUFFER)
110 brw->ctx.NewDriverState |= BRW_NEW_UNIFORM_BUFFER;
111 if (intel_obj->Base.UsageHistory & USAGE_TEXTURE_BUFFER)
112 brw->ctx.NewDriverState |= BRW_NEW_TEXTURE_BUFFER;
113 if (intel_obj->Base.UsageHistory & USAGE_ATOMIC_COUNTER_BUFFER)
114 brw->ctx.NewDriverState |= BRW_NEW_ATOMIC_BUFFER;
115
116 mark_buffer_inactive(intel_obj);
117 }
118
119 static void
120 release_buffer(struct intel_buffer_object *intel_obj)
121 {
122 drm_intel_bo_unreference(intel_obj->buffer);
123 intel_obj->buffer = NULL;
124 }
125
126 /**
127 * The NewBufferObject() driver hook.
128 *
129 * Allocates a new intel_buffer_object structure and initializes it.
130 *
131 * There is some duplication between mesa's bufferobjects and our
132 * bufmgr buffers. Both have an integer handle and a hashtable to
133 * lookup an opaque structure. It would be nice if the handles and
134 * internal structure where somehow shared.
135 */
136 static struct gl_buffer_object *
137 brw_new_buffer_object(struct gl_context * ctx, GLuint name)
138 {
139 struct intel_buffer_object *obj = CALLOC_STRUCT(intel_buffer_object);
140 if (!obj) {
141 _mesa_error_no_memory(__func__);
142 }
143
144 _mesa_initialize_buffer_object(ctx, &obj->Base, name);
145
146 obj->buffer = NULL;
147
148 return &obj->Base;
149 }
150
151 /**
152 * The DeleteBuffer() driver hook.
153 *
154 * Deletes a single OpenGL buffer object. Used by glDeleteBuffers().
155 */
156 static void
157 brw_delete_buffer(struct gl_context * ctx, struct gl_buffer_object *obj)
158 {
159 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
160
161 assert(intel_obj);
162
163 /* Buffer objects are automatically unmapped when deleting according
164 * to the spec, but Mesa doesn't do UnmapBuffer for us at context destroy
165 * (though it does if you call glDeleteBuffers)
166 */
167 _mesa_buffer_unmap_all_mappings(ctx, obj);
168
169 drm_intel_bo_unreference(intel_obj->buffer);
170 free(intel_obj);
171 }
172
173
174 /**
175 * The BufferData() driver hook.
176 *
177 * Implements glBufferData(), which recreates a buffer object's data store
178 * and populates it with the given data, if present.
179 *
180 * Any data that was previously stored in the buffer object is lost.
181 *
182 * \return true for success, false if out of memory
183 */
184 static GLboolean
185 brw_buffer_data(struct gl_context *ctx,
186 GLenum target,
187 GLsizeiptrARB size,
188 const GLvoid *data,
189 GLenum usage,
190 GLbitfield storageFlags,
191 struct gl_buffer_object *obj)
192 {
193 struct brw_context *brw = brw_context(ctx);
194 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
195
196 /* Part of the ABI, but this function doesn't use it.
197 */
198 (void) target;
199
200 intel_obj->Base.Size = size;
201 intel_obj->Base.BufferRangeSize = size;
202 intel_obj->Base.Usage = usage;
203 intel_obj->Base.StorageFlags = storageFlags;
204
205 assert(!obj->Mappings[MAP_USER].Pointer); /* Mesa should have unmapped it */
206 assert(!obj->Mappings[MAP_INTERNAL].Pointer);
207
208 if (intel_obj->buffer != NULL)
209 release_buffer(intel_obj);
210
211 if (size != 0) {
212 alloc_buffer_object(brw, intel_obj);
213 if (!intel_obj->buffer)
214 return false;
215
216 if (data != NULL)
217 drm_intel_bo_subdata(intel_obj->buffer, 0, size, data);
218 }
219
220 return true;
221 }
222
223
224 /**
225 * The BufferSubData() driver hook.
226 *
227 * Implements glBufferSubData(), which replaces a portion of the data in a
228 * buffer object.
229 *
230 * If the data range specified by (size + offset) extends beyond the end of
231 * the buffer or if data is NULL, no copy is performed.
232 */
233 static void
234 brw_buffer_subdata(struct gl_context *ctx,
235 GLintptrARB offset,
236 GLsizeiptrARB size,
237 const GLvoid *data,
238 struct gl_buffer_object *obj)
239 {
240 struct brw_context *brw = brw_context(ctx);
241 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
242 bool busy;
243
244 if (size == 0)
245 return;
246
247 assert(intel_obj);
248
249 /* See if we can unsynchronized write the data into the user's BO. This
250 * avoids GPU stalls in unfortunately common user patterns (uploading
251 * sequentially into a BO, with draw calls in between each upload).
252 *
253 * Once we've hit this path, we mark this GL BO as preferring stalling to
254 * blits, so that we can hopefully hit this path again in the future
255 * (otherwise, an app that might occasionally stall but mostly not will end
256 * up with blitting all the time, at the cost of bandwidth)
257 */
258 if (offset + size <= intel_obj->gpu_active_start ||
259 intel_obj->gpu_active_end <= offset) {
260 if (brw->has_llc) {
261 drm_intel_gem_bo_map_unsynchronized(intel_obj->buffer);
262 memcpy(intel_obj->buffer->virtual + offset, data, size);
263 drm_intel_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 return;
268 } else {
269 perf_debug("BufferSubData could be unsynchronized, but !LLC doesn't support it yet\n");
270 }
271 }
272
273 busy =
274 drm_intel_bo_busy(intel_obj->buffer) ||
275 drm_intel_bo_references(brw->batch.bo, intel_obj->buffer);
276
277 if (busy) {
278 if (size == intel_obj->Base.Size) {
279 /* Replace the current busy bo so the subdata doesn't stall. */
280 drm_intel_bo_unreference(intel_obj->buffer);
281 alloc_buffer_object(brw, intel_obj);
282 } else if (!intel_obj->prefer_stall_to_blit) {
283 perf_debug("Using a blit copy to avoid stalling on "
284 "glBufferSubData(%ld, %ld) (%ldkb) to a busy "
285 "(%d-%d) buffer object.\n",
286 (long)offset, (long)offset + size, (long)(size/1024),
287 intel_obj->gpu_active_start,
288 intel_obj->gpu_active_end);
289 drm_intel_bo *temp_bo =
290 drm_intel_bo_alloc(brw->bufmgr, "subdata temp", size, 64);
291
292 drm_intel_bo_subdata(temp_bo, 0, size, data);
293
294 intel_emit_linear_blit(brw,
295 intel_obj->buffer, offset,
296 temp_bo, 0,
297 size);
298
299 drm_intel_bo_unreference(temp_bo);
300 return;
301 } else {
302 perf_debug("Stalling on glBufferSubData(%ld, %ld) (%ldkb) to a busy "
303 "(%d-%d) buffer object. Use glMapBufferRange() to "
304 "avoid this.\n",
305 (long)offset, (long)offset + size, (long)(size/1024),
306 intel_obj->gpu_active_start,
307 intel_obj->gpu_active_end);
308 intel_batchbuffer_flush(brw);
309 }
310 }
311
312 drm_intel_bo_subdata(intel_obj->buffer, offset, size, data);
313 mark_buffer_inactive(intel_obj);
314 }
315
316
317 /**
318 * The GetBufferSubData() driver hook.
319 *
320 * Implements glGetBufferSubData(), which copies a subrange of a buffer
321 * object into user memory.
322 */
323 static void
324 brw_get_buffer_subdata(struct gl_context *ctx,
325 GLintptrARB offset,
326 GLsizeiptrARB size,
327 GLvoid *data,
328 struct gl_buffer_object *obj)
329 {
330 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
331 struct brw_context *brw = brw_context(ctx);
332
333 assert(intel_obj);
334 if (drm_intel_bo_references(brw->batch.bo, intel_obj->buffer)) {
335 intel_batchbuffer_flush(brw);
336 }
337 drm_intel_bo_get_subdata(intel_obj->buffer, offset, size, data);
338
339 mark_buffer_inactive(intel_obj);
340 }
341
342
343 /**
344 * The MapBufferRange() driver hook.
345 *
346 * This implements both glMapBufferRange() and glMapBuffer().
347 *
348 * The goal of this extension is to allow apps to accumulate their rendering
349 * at the same time as they accumulate their buffer object. Without it,
350 * you'd end up blocking on execution of rendering every time you mapped
351 * the buffer to put new data in.
352 *
353 * We support it in 3 ways: If unsynchronized, then don't bother
354 * flushing the batchbuffer before mapping the buffer, which can save blocking
355 * in many cases. If we would still block, and they allow the whole buffer
356 * to be invalidated, then just allocate a new buffer to replace the old one.
357 * If not, and we'd block, and they allow the subrange of the buffer to be
358 * invalidated, then we can make a new little BO, let them write into that,
359 * and blit it into the real BO at unmap time.
360 */
361 static void *
362 brw_map_buffer_range(struct gl_context *ctx,
363 GLintptr offset, GLsizeiptr length,
364 GLbitfield access, struct gl_buffer_object *obj,
365 gl_map_buffer_index index)
366 {
367 struct brw_context *brw = brw_context(ctx);
368 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
369
370 assert(intel_obj);
371
372 /* _mesa_MapBufferRange (GL entrypoint) sets these, but the vbo module also
373 * internally uses our functions directly.
374 */
375 obj->Mappings[index].Offset = offset;
376 obj->Mappings[index].Length = length;
377 obj->Mappings[index].AccessFlags = access;
378
379 if (intel_obj->buffer == NULL) {
380 obj->Mappings[index].Pointer = NULL;
381 return NULL;
382 }
383
384 /* If the access is synchronized (like a normal buffer mapping), then get
385 * things flushed out so the later mapping syncs appropriately through GEM.
386 * If the user doesn't care about existing buffer contents and mapping would
387 * cause us to block, then throw out the old buffer.
388 *
389 * If they set INVALIDATE_BUFFER, we can pitch the current contents to
390 * achieve the required synchronization.
391 */
392 if (!(access & GL_MAP_UNSYNCHRONIZED_BIT)) {
393 if (drm_intel_bo_references(brw->batch.bo, intel_obj->buffer)) {
394 if (access & GL_MAP_INVALIDATE_BUFFER_BIT) {
395 drm_intel_bo_unreference(intel_obj->buffer);
396 alloc_buffer_object(brw, intel_obj);
397 } else {
398 perf_debug("Stalling on the GPU for mapping a busy buffer "
399 "object\n");
400 intel_batchbuffer_flush(brw);
401 }
402 } else if (drm_intel_bo_busy(intel_obj->buffer) &&
403 (access & GL_MAP_INVALIDATE_BUFFER_BIT)) {
404 drm_intel_bo_unreference(intel_obj->buffer);
405 alloc_buffer_object(brw, intel_obj);
406 }
407 }
408
409 /* If the user is mapping a range of an active buffer object but
410 * doesn't require the current contents of that range, make a new
411 * BO, and we'll copy what they put in there out at unmap or
412 * FlushRange time.
413 *
414 * That is, unless they're looking for a persistent mapping -- we would
415 * need to do blits in the MemoryBarrier call, and it's easier to just do a
416 * GPU stall and do a mapping.
417 */
418 if (!(access & (GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_PERSISTENT_BIT)) &&
419 (access & GL_MAP_INVALIDATE_RANGE_BIT) &&
420 drm_intel_bo_busy(intel_obj->buffer)) {
421 /* Ensure that the base alignment of the allocation meets the alignment
422 * guarantees the driver has advertised to the application.
423 */
424 const unsigned alignment = ctx->Const.MinMapBufferAlignment;
425
426 intel_obj->map_extra[index] = (uintptr_t) offset % alignment;
427 intel_obj->range_map_bo[index] = drm_intel_bo_alloc(brw->bufmgr,
428 "BO blit temp",
429 length +
430 intel_obj->map_extra[index],
431 alignment);
432 if (brw->has_llc) {
433 brw_bo_map(brw, intel_obj->range_map_bo[index],
434 (access & GL_MAP_WRITE_BIT) != 0, "range-map");
435 } else {
436 drm_intel_gem_bo_map_gtt(intel_obj->range_map_bo[index]);
437 }
438 obj->Mappings[index].Pointer =
439 intel_obj->range_map_bo[index]->virtual + intel_obj->map_extra[index];
440 return obj->Mappings[index].Pointer;
441 }
442
443 if (access & GL_MAP_UNSYNCHRONIZED_BIT) {
444 if (!brw->has_llc && brw->perf_debug &&
445 drm_intel_bo_busy(intel_obj->buffer)) {
446 perf_debug("MapBufferRange with GL_MAP_UNSYNCHRONIZED_BIT stalling (it's actually synchronized on non-LLC platforms)\n");
447 }
448 drm_intel_gem_bo_map_unsynchronized(intel_obj->buffer);
449 } else if (!brw->has_llc && (!(access & GL_MAP_READ_BIT) ||
450 (access & GL_MAP_PERSISTENT_BIT))) {
451 drm_intel_gem_bo_map_gtt(intel_obj->buffer);
452 mark_buffer_inactive(intel_obj);
453 } else {
454 brw_bo_map(brw, intel_obj->buffer, (access & GL_MAP_WRITE_BIT) != 0,
455 "MapBufferRange");
456 mark_buffer_inactive(intel_obj);
457 }
458
459 obj->Mappings[index].Pointer = intel_obj->buffer->virtual + offset;
460 return obj->Mappings[index].Pointer;
461 }
462
463 /**
464 * The FlushMappedBufferRange() driver hook.
465 *
466 * Implements glFlushMappedBufferRange(), which signifies that modifications
467 * have been made to a range of a mapped buffer, and it should be flushed.
468 *
469 * This is only used for buffers mapped with GL_MAP_FLUSH_EXPLICIT_BIT.
470 *
471 * Ideally we'd use a BO to avoid taking up cache space for the temporary
472 * data, but FlushMappedBufferRange may be followed by further writes to
473 * the pointer, so we would have to re-map after emitting our blit, which
474 * would defeat the point.
475 */
476 static void
477 brw_flush_mapped_buffer_range(struct gl_context *ctx,
478 GLintptr offset, GLsizeiptr length,
479 struct gl_buffer_object *obj,
480 gl_map_buffer_index index)
481 {
482 struct brw_context *brw = brw_context(ctx);
483 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
484
485 assert(obj->Mappings[index].AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT);
486
487 /* If we gave a direct mapping of the buffer instead of using a temporary,
488 * then there's nothing to do.
489 */
490 if (intel_obj->range_map_bo[index] == NULL)
491 return;
492
493 if (length == 0)
494 return;
495
496 /* Note that we're not unmapping our buffer while executing the blit. We
497 * need to have a mapping still at the end of this call, since the user
498 * gets to make further modifications and glFlushMappedBufferRange() calls.
499 * This is safe, because:
500 *
501 * - On LLC platforms, we're using a CPU mapping that's coherent with the
502 * GPU (except for the render caches), so the kernel doesn't need to do
503 * any flushing work for us except for what happens at batch exec time
504 * anyway.
505 *
506 * - On non-LLC platforms, we're using a GTT mapping that writes directly
507 * to system memory (except for the chipset cache that gets flushed at
508 * batch exec time).
509 *
510 * In both cases we don't need to stall for the previous blit to complete
511 * so we can re-map (and we definitely don't want to, since that would be
512 * slow): If the user edits a part of their buffer that's previously been
513 * blitted, then our lack of synchoronization is fine, because either
514 * they'll get some too-new data in the first blit and not do another blit
515 * of that area (but in that case the results are undefined), or they'll do
516 * another blit of that area and the complete newer data will land the
517 * second time.
518 */
519 intel_emit_linear_blit(brw,
520 intel_obj->buffer,
521 obj->Mappings[index].Offset + offset,
522 intel_obj->range_map_bo[index],
523 intel_obj->map_extra[index] + offset,
524 length);
525 mark_buffer_gpu_usage(intel_obj,
526 obj->Mappings[index].Offset + offset,
527 length);
528 }
529
530
531 /**
532 * The UnmapBuffer() driver hook.
533 *
534 * Implements glUnmapBuffer().
535 */
536 static GLboolean
537 brw_unmap_buffer(struct gl_context *ctx,
538 struct gl_buffer_object *obj,
539 gl_map_buffer_index index)
540 {
541 struct brw_context *brw = brw_context(ctx);
542 struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
543
544 assert(intel_obj);
545 assert(obj->Mappings[index].Pointer);
546 if (intel_obj->range_map_bo[index] != NULL) {
547 drm_intel_bo_unmap(intel_obj->range_map_bo[index]);
548
549 if (!(obj->Mappings[index].AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT)) {
550 intel_emit_linear_blit(brw,
551 intel_obj->buffer, obj->Mappings[index].Offset,
552 intel_obj->range_map_bo[index],
553 intel_obj->map_extra[index],
554 obj->Mappings[index].Length);
555 mark_buffer_gpu_usage(intel_obj, obj->Mappings[index].Offset,
556 obj->Mappings[index].Length);
557 }
558
559 /* Since we've emitted some blits to buffers that will (likely) be used
560 * in rendering operations in other cache domains in this batch, emit a
561 * flush. Once again, we wish for a domain tracker in libdrm to cover
562 * usage inside of a batchbuffer.
563 */
564 brw_emit_mi_flush(brw);
565
566 drm_intel_bo_unreference(intel_obj->range_map_bo[index]);
567 intel_obj->range_map_bo[index] = NULL;
568 } else if (intel_obj->buffer != NULL) {
569 drm_intel_bo_unmap(intel_obj->buffer);
570 }
571 obj->Mappings[index].Pointer = NULL;
572 obj->Mappings[index].Offset = 0;
573 obj->Mappings[index].Length = 0;
574
575 return true;
576 }
577
578 /**
579 * Gets a pointer to the object's BO, and marks the given range as being used
580 * on the GPU.
581 *
582 * Anywhere that uses buffer objects in the pipeline should be using this to
583 * mark the range of the buffer that is being accessed by the pipeline.
584 */
585 drm_intel_bo *
586 intel_bufferobj_buffer(struct brw_context *brw,
587 struct intel_buffer_object *intel_obj,
588 uint32_t offset, uint32_t size)
589 {
590 /* This is needed so that things like transform feedback and texture buffer
591 * objects that need a BO but don't want to check that they exist for
592 * draw-time validation can just always get a BO from a GL buffer object.
593 */
594 if (intel_obj->buffer == NULL)
595 alloc_buffer_object(brw, intel_obj);
596
597 mark_buffer_gpu_usage(intel_obj, offset, size);
598
599 return intel_obj->buffer;
600 }
601
602 /**
603 * The CopyBufferSubData() driver hook.
604 *
605 * Implements glCopyBufferSubData(), which copies a portion of one buffer
606 * object's data to another. Independent source and destination offsets
607 * are allowed.
608 */
609 static void
610 brw_copy_buffer_subdata(struct gl_context *ctx,
611 struct gl_buffer_object *src,
612 struct gl_buffer_object *dst,
613 GLintptr read_offset, GLintptr write_offset,
614 GLsizeiptr size)
615 {
616 struct brw_context *brw = brw_context(ctx);
617 struct intel_buffer_object *intel_src = intel_buffer_object(src);
618 struct intel_buffer_object *intel_dst = intel_buffer_object(dst);
619 drm_intel_bo *src_bo, *dst_bo;
620
621 if (size == 0)
622 return;
623
624 dst_bo = intel_bufferobj_buffer(brw, intel_dst, write_offset, size);
625 src_bo = intel_bufferobj_buffer(brw, intel_src, read_offset, size);
626
627 intel_emit_linear_blit(brw,
628 dst_bo, write_offset,
629 src_bo, read_offset, size);
630
631 /* Since we've emitted some blits to buffers that will (likely) be used
632 * in rendering operations in other cache domains in this batch, emit a
633 * flush. Once again, we wish for a domain tracker in libdrm to cover
634 * usage inside of a batchbuffer.
635 */
636 brw_emit_mi_flush(brw);
637 }
638
639 void
640 intelInitBufferObjectFuncs(struct dd_function_table *functions)
641 {
642 functions->NewBufferObject = brw_new_buffer_object;
643 functions->DeleteBuffer = brw_delete_buffer;
644 functions->BufferData = brw_buffer_data;
645 functions->BufferSubData = brw_buffer_subdata;
646 functions->GetBufferSubData = brw_get_buffer_subdata;
647 functions->MapBufferRange = brw_map_buffer_range;
648 functions->FlushMappedBufferRange = brw_flush_mapped_buffer_range;
649 functions->UnmapBuffer = brw_unmap_buffer;
650 functions->CopyBufferSubData = brw_copy_buffer_subdata;
651 }