Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 1
/**************************************************************************
2
 *
3
 * Copyright 2003 VMware, Inc.
4
 * All Rights Reserved.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sub license, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * The above copyright notice and this permission notice (including the
15
 * next paragraph) shall be included in all copies or substantial portions
16
 * of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21
 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 *
26
 **************************************************************************/
27
 
28
 
29
#include "main/imports.h"
30
#include "main/mtypes.h"
31
#include "main/macros.h"
32
#include "main/bufferobj.h"
33
 
34
#include "intel_blit.h"
35
#include "intel_buffer_objects.h"
36
#include "intel_batchbuffer.h"
37
#include "intel_context.h"
38
#include "intel_fbo.h"
39
#include "intel_mipmap_tree.h"
40
#include "intel_regions.h"
41
 
42
static GLboolean
43
intel_bufferobj_unmap(struct gl_context * ctx, struct gl_buffer_object *obj,
44
                      gl_map_buffer_index index);
45
 
46
/** Allocates a new drm_intel_bo to store the data for the buffer object. */
47
static void
48
intel_bufferobj_alloc_buffer(struct intel_context *intel,
49
			     struct intel_buffer_object *intel_obj)
50
{
51
   intel_obj->buffer = drm_intel_bo_alloc(intel->bufmgr, "bufferobj",
52
					  intel_obj->Base.Size, 64);
53
}
54
 
55
static void
56
release_buffer(struct intel_buffer_object *intel_obj)
57
{
58
   drm_intel_bo_unreference(intel_obj->buffer);
59
   intel_obj->buffer = NULL;
60
   intel_obj->offset = 0;
61
   intel_obj->source = 0;
62
}
63
 
64
/**
65
 * There is some duplication between mesa's bufferobjects and our
66
 * bufmgr buffers.  Both have an integer handle and a hashtable to
67
 * lookup an opaque structure.  It would be nice if the handles and
68
 * internal structure where somehow shared.
69
 */
70
static struct gl_buffer_object *
71
intel_bufferobj_alloc(struct gl_context * ctx, GLuint name)
72
{
73
   struct intel_buffer_object *obj = CALLOC_STRUCT(intel_buffer_object);
74
 
75
   _mesa_initialize_buffer_object(ctx, &obj->Base, name);
76
 
77
   obj->buffer = NULL;
78
 
79
   return &obj->Base;
80
}
81
 
82
/**
83
 * Deallocate/free a vertex/pixel buffer object.
84
 * Called via glDeleteBuffersARB().
85
 */
86
static void
87
intel_bufferobj_free(struct gl_context * ctx, struct gl_buffer_object *obj)
88
{
89
   struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
90
 
91
   assert(intel_obj);
92
 
93
   /* Buffer objects are automatically unmapped when deleting according
94
    * to the spec, but Mesa doesn't do UnmapBuffer for us at context destroy
95
    * (though it does if you call glDeleteBuffers)
96
    */
97
   _mesa_buffer_unmap_all_mappings(ctx, obj);
98
 
99
   _mesa_align_free(intel_obj->sys_buffer);
100
 
101
   drm_intel_bo_unreference(intel_obj->buffer);
102
   free(intel_obj);
103
}
104
 
105
 
106
 
107
/**
108
 * Allocate space for and store data in a buffer object.  Any data that was
109
 * previously stored in the buffer object is lost.  If data is NULL,
110
 * memory will be allocated, but no copy will occur.
111
 * Called via ctx->Driver.BufferData().
112
 * \return true for success, false if out of memory
113
 */
114
static GLboolean
115
intel_bufferobj_data(struct gl_context * ctx,
116
                     GLenum target,
117
                     GLsizeiptrARB size,
118
                     const GLvoid * data,
119
                     GLenum usage,
120
                     GLbitfield storageFlags,
121
                     struct gl_buffer_object *obj)
122
{
123
   struct intel_context *intel = intel_context(ctx);
124
   struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
125
 
126
   intel_obj->Base.Size = size;
127
   intel_obj->Base.Usage = usage;
128
   intel_obj->Base.StorageFlags = storageFlags;
129
 
130
   assert(!obj->Mappings[MAP_USER].Pointer); /* Mesa should have unmapped it */
131
   assert(!obj->Mappings[MAP_INTERNAL].Pointer);
132
 
133
   if (intel_obj->buffer != NULL)
134
      release_buffer(intel_obj);
135
 
136
   _mesa_align_free(intel_obj->sys_buffer);
137
   intel_obj->sys_buffer = NULL;
138
 
139
   if (size != 0) {
140
      /* Stick VBOs in system memory, as we're always doing swtnl with their
141
       * contents anyway.
142
       */
143
      if (target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER) {
144
	 intel_obj->sys_buffer =
145
            _mesa_align_malloc(size, ctx->Const.MinMapBufferAlignment);
146
	 if (intel_obj->sys_buffer != NULL) {
147
	    if (data != NULL)
148
	       memcpy(intel_obj->sys_buffer, data, size);
149
	    return true;
150
	 }
151
      }
152
 
153
      intel_bufferobj_alloc_buffer(intel, intel_obj);
154
      if (!intel_obj->buffer)
155
         return false;
156
 
157
      if (data != NULL)
158
	 drm_intel_bo_subdata(intel_obj->buffer, 0, size, data);
159
   }
160
 
161
   return true;
162
}
163
 
164
 
165
/**
166
 * Replace data in a subrange of buffer object.  If the data range
167
 * specified by size + offset extends beyond the end of the buffer or
168
 * if data is NULL, no copy is performed.
169
 * Called via glBufferSubDataARB().
170
 */
171
static void
172
intel_bufferobj_subdata(struct gl_context * ctx,
173
                        GLintptrARB offset,
174
                        GLsizeiptrARB size,
175
                        const GLvoid * data, struct gl_buffer_object *obj)
176
{
177
   struct intel_context *intel = intel_context(ctx);
178
   struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
179
   bool busy;
180
 
181
   if (size == 0)
182
      return;
183
 
184
   assert(intel_obj);
185
 
186
   /* If we have a single copy in system memory, update that */
187
   if (intel_obj->sys_buffer) {
188
      if (intel_obj->source)
189
	 release_buffer(intel_obj);
190
 
191
      if (intel_obj->buffer == NULL) {
192
	 memcpy((char *)intel_obj->sys_buffer + offset, data, size);
193
	 return;
194
      }
195
 
196
      _mesa_align_free(intel_obj->sys_buffer);
197
      intel_obj->sys_buffer = NULL;
198
   }
199
 
200
   /* Otherwise we need to update the copy in video memory. */
201
   busy =
202
      drm_intel_bo_busy(intel_obj->buffer) ||
203
      drm_intel_bo_references(intel->batch.bo, intel_obj->buffer);
204
 
205
   if (busy) {
206
      if (size == intel_obj->Base.Size) {
207
	 /* Replace the current busy bo with fresh data. */
208
	 drm_intel_bo_unreference(intel_obj->buffer);
209
	 intel_bufferobj_alloc_buffer(intel, intel_obj);
210
	 drm_intel_bo_subdata(intel_obj->buffer, 0, size, data);
211
      } else {
212
         perf_debug("Using a blit copy to avoid stalling on %ldb "
213
                    "glBufferSubData() to a busy buffer object.\n",
214
                    (long)size);
215
	 drm_intel_bo *temp_bo =
216
	    drm_intel_bo_alloc(intel->bufmgr, "subdata temp", size, 64);
217
 
218
	 drm_intel_bo_subdata(temp_bo, 0, size, data);
219
 
220
	 intel_emit_linear_blit(intel,
221
				intel_obj->buffer, offset,
222
				temp_bo, 0,
223
				size);
224
 
225
	 drm_intel_bo_unreference(temp_bo);
226
      }
227
   } else {
228
      drm_intel_bo_subdata(intel_obj->buffer, offset, size, data);
229
   }
230
}
231
 
232
 
233
/**
234
 * Called via glGetBufferSubDataARB().
235
 */
236
static void
237
intel_bufferobj_get_subdata(struct gl_context * ctx,
238
                            GLintptrARB offset,
239
                            GLsizeiptrARB size,
240
                            GLvoid * data, struct gl_buffer_object *obj)
241
{
242
   struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
243
   struct intel_context *intel = intel_context(ctx);
244
 
245
   assert(intel_obj);
246
   if (intel_obj->sys_buffer)
247
      memcpy(data, (char *)intel_obj->sys_buffer + offset, size);
248
   else {
249
      if (drm_intel_bo_references(intel->batch.bo, intel_obj->buffer)) {
250
	 intel_batchbuffer_flush(intel);
251
      }
252
      drm_intel_bo_get_subdata(intel_obj->buffer, offset, size, data);
253
   }
254
}
255
 
256
 
257
 
258
/**
259
 * Called via glMapBufferRange and glMapBuffer
260
 *
261
 * The goal of this extension is to allow apps to accumulate their rendering
262
 * at the same time as they accumulate their buffer object.  Without it,
263
 * you'd end up blocking on execution of rendering every time you mapped
264
 * the buffer to put new data in.
265
 *
266
 * We support it in 3 ways: If unsynchronized, then don't bother
267
 * flushing the batchbuffer before mapping the buffer, which can save blocking
268
 * in many cases.  If we would still block, and they allow the whole buffer
269
 * to be invalidated, then just allocate a new buffer to replace the old one.
270
 * If not, and we'd block, and they allow the subrange of the buffer to be
271
 * invalidated, then we can make a new little BO, let them write into that,
272
 * and blit it into the real BO at unmap time.
273
 */
274
static void *
275
intel_bufferobj_map_range(struct gl_context * ctx,
276
			  GLintptr offset, GLsizeiptr length,
277
			  GLbitfield access, struct gl_buffer_object *obj,
278
                          gl_map_buffer_index index)
279
{
280
   struct intel_context *intel = intel_context(ctx);
281
   struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
282
 
283
   assert(intel_obj);
284
 
285
   /* _mesa_MapBufferRange (GL entrypoint) sets these, but the vbo module also
286
    * internally uses our functions directly.
287
    */
288
   obj->Mappings[index].Offset = offset;
289
   obj->Mappings[index].Length = length;
290
   obj->Mappings[index].AccessFlags = access;
291
 
292
   if (intel_obj->sys_buffer) {
293
      const bool read_only =
294
	 (access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == GL_MAP_READ_BIT;
295
 
296
      if (!read_only && intel_obj->source)
297
	 release_buffer(intel_obj);
298
 
299
      if (!intel_obj->buffer || intel_obj->source) {
300
	 obj->Mappings[index].Pointer = intel_obj->sys_buffer + offset;
301
	 return obj->Mappings[index].Pointer;
302
      }
303
 
304
      _mesa_align_free(intel_obj->sys_buffer);
305
      intel_obj->sys_buffer = NULL;
306
   }
307
 
308
   if (intel_obj->buffer == NULL) {
309
      obj->Mappings[index].Pointer = NULL;
310
      return NULL;
311
   }
312
 
313
   /* If the access is synchronized (like a normal buffer mapping), then get
314
    * things flushed out so the later mapping syncs appropriately through GEM.
315
    * If the user doesn't care about existing buffer contents and mapping would
316
    * cause us to block, then throw out the old buffer.
317
    *
318
    * If they set INVALIDATE_BUFFER, we can pitch the current contents to
319
    * achieve the required synchronization.
320
    */
321
   if (!(access & GL_MAP_UNSYNCHRONIZED_BIT)) {
322
      if (drm_intel_bo_references(intel->batch.bo, intel_obj->buffer)) {
323
	 if (access & GL_MAP_INVALIDATE_BUFFER_BIT) {
324
	    drm_intel_bo_unreference(intel_obj->buffer);
325
	    intel_bufferobj_alloc_buffer(intel, intel_obj);
326
	 } else {
327
            perf_debug("Stalling on the GPU for mapping a busy buffer "
328
                       "object\n");
329
	    intel_flush(ctx);
330
	 }
331
      } else if (drm_intel_bo_busy(intel_obj->buffer) &&
332
		 (access & GL_MAP_INVALIDATE_BUFFER_BIT)) {
333
	 drm_intel_bo_unreference(intel_obj->buffer);
334
	 intel_bufferobj_alloc_buffer(intel, intel_obj);
335
      }
336
   }
337
 
338
   /* If the user is mapping a range of an active buffer object but
339
    * doesn't require the current contents of that range, make a new
340
    * BO, and we'll copy what they put in there out at unmap or
341
    * FlushRange time.
342
    */
343
   if ((access & GL_MAP_INVALIDATE_RANGE_BIT) &&
344
       drm_intel_bo_busy(intel_obj->buffer)) {
345
      /* Ensure that the base alignment of the allocation meets the alignment
346
       * guarantees the driver has advertised to the application.
347
       */
348
      const unsigned alignment = ctx->Const.MinMapBufferAlignment;
349
      const unsigned extra = (uintptr_t) offset % alignment;
350
 
351
      if (access & GL_MAP_FLUSH_EXPLICIT_BIT) {
352
         intel_obj->range_map_buffer[index] =
353
            _mesa_align_malloc(length + extra, alignment);
354
         obj->Mappings[index].Pointer =
355
            intel_obj->range_map_buffer[index] + extra;
356
      } else {
357
	 intel_obj->range_map_bo[index] = drm_intel_bo_alloc(intel->bufmgr,
358
                                                             "range map",
359
                                                             length + extra,
360
                                                             alignment);
361
	 if (!(access & GL_MAP_READ_BIT)) {
362
	    drm_intel_gem_bo_map_gtt(intel_obj->range_map_bo[index]);
363
	 } else {
364
	    drm_intel_bo_map(intel_obj->range_map_bo[index],
365
			     (access & GL_MAP_WRITE_BIT) != 0);
366
	 }
367
	 obj->Mappings[index].Pointer =
368
            intel_obj->range_map_bo[index]->virtual + extra;
369
      }
370
      return obj->Mappings[index].Pointer;
371
   }
372
 
373
   if (access & GL_MAP_UNSYNCHRONIZED_BIT)
374
      drm_intel_gem_bo_map_unsynchronized(intel_obj->buffer);
375
   else if (!(access & GL_MAP_READ_BIT)) {
376
      drm_intel_gem_bo_map_gtt(intel_obj->buffer);
377
   } else {
378
      drm_intel_bo_map(intel_obj->buffer, (access & GL_MAP_WRITE_BIT) != 0);
379
   }
380
 
381
   obj->Mappings[index].Pointer = intel_obj->buffer->virtual + offset;
382
   return obj->Mappings[index].Pointer;
383
}
384
 
385
/* Ideally we'd use a BO to avoid taking up cache space for the temporary
386
 * data, but FlushMappedBufferRange may be followed by further writes to
387
 * the pointer, so we would have to re-map after emitting our blit, which
388
 * would defeat the point.
389
 */
390
static void
391
intel_bufferobj_flush_mapped_range(struct gl_context *ctx,
392
				   GLintptr offset, GLsizeiptr length,
393
                                   struct gl_buffer_object *obj,
394
                                   gl_map_buffer_index index)
395
{
396
   struct intel_context *intel = intel_context(ctx);
397
   struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
398
   drm_intel_bo *temp_bo;
399
 
400
   /* Unless we're in the range map using a temporary system buffer,
401
    * there's no work to do.
402
    */
403
   if (intel_obj->range_map_buffer[index] == NULL)
404
      return;
405
 
406
   if (length == 0)
407
      return;
408
 
409
   temp_bo = drm_intel_bo_alloc(intel->bufmgr, "range map flush", length, 64);
410
 
411
   /* Use obj->Pointer instead of intel_obj->range_map_buffer because the
412
    * former points to the actual mapping while the latter may be offset to
413
    * meet alignment guarantees.
414
    */
415
   drm_intel_bo_subdata(temp_bo, 0, length, obj->Mappings[index].Pointer);
416
 
417
   intel_emit_linear_blit(intel,
418
			  intel_obj->buffer,
419
                          obj->Mappings[index].Offset + offset,
420
			  temp_bo, 0,
421
			  length);
422
 
423
   drm_intel_bo_unreference(temp_bo);
424
}
425
 
426
 
427
/**
428
 * Called via glUnmapBuffer().
429
 */
430
static GLboolean
431
intel_bufferobj_unmap(struct gl_context * ctx, struct gl_buffer_object *obj,
432
                      gl_map_buffer_index index)
433
{
434
   struct intel_context *intel = intel_context(ctx);
435
   struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
436
 
437
   assert(intel_obj);
438
   assert(obj->Mappings[index].Pointer);
439
   if (intel_obj->sys_buffer != NULL) {
440
      /* always keep the mapping around. */
441
   } else if (intel_obj->range_map_buffer[index] != NULL) {
442
      /* Since we've emitted some blits to buffers that will (likely) be used
443
       * in rendering operations in other cache domains in this batch, emit a
444
       * flush.  Once again, we wish for a domain tracker in libdrm to cover
445
       * usage inside of a batchbuffer.
446
       */
447
      intel_batchbuffer_emit_mi_flush(intel);
448
      _mesa_align_free(intel_obj->range_map_buffer[index]);
449
      intel_obj->range_map_buffer[index] = NULL;
450
   } else if (intel_obj->range_map_bo[index] != NULL) {
451
      const unsigned extra = obj->Mappings[index].Pointer -
452
                             intel_obj->range_map_bo[index]->virtual;
453
 
454
      drm_intel_bo_unmap(intel_obj->range_map_bo[index]);
455
 
456
      intel_emit_linear_blit(intel,
457
			     intel_obj->buffer, obj->Mappings[index].Offset,
458
			     intel_obj->range_map_bo[index], extra,
459
			     obj->Mappings[index].Length);
460
 
461
      /* Since we've emitted some blits to buffers that will (likely) be used
462
       * in rendering operations in other cache domains in this batch, emit a
463
       * flush.  Once again, we wish for a domain tracker in libdrm to cover
464
       * usage inside of a batchbuffer.
465
       */
466
      intel_batchbuffer_emit_mi_flush(intel);
467
 
468
      drm_intel_bo_unreference(intel_obj->range_map_bo[index]);
469
      intel_obj->range_map_bo[index] = NULL;
470
   } else if (intel_obj->buffer != NULL) {
471
      drm_intel_bo_unmap(intel_obj->buffer);
472
   }
473
   obj->Mappings[index].Pointer = NULL;
474
   obj->Mappings[index].Offset = 0;
475
   obj->Mappings[index].Length = 0;
476
 
477
   return true;
478
}
479
 
480
drm_intel_bo *
481
intel_bufferobj_buffer(struct intel_context *intel,
482
                       struct intel_buffer_object *intel_obj)
483
{
484
   if (intel_obj->source)
485
      release_buffer(intel_obj);
486
 
487
   if (intel_obj->buffer == NULL) {
488
      intel_bufferobj_alloc_buffer(intel, intel_obj);
489
      drm_intel_bo_subdata(intel_obj->buffer,
490
			   0, intel_obj->Base.Size,
491
			   intel_obj->sys_buffer);
492
 
493
      _mesa_align_free(intel_obj->sys_buffer);
494
      intel_obj->sys_buffer = NULL;
495
      intel_obj->offset = 0;
496
   }
497
 
498
   return intel_obj->buffer;
499
}
500
 
501
#define INTEL_UPLOAD_SIZE (64*1024)
502
 
503
void
504
intel_upload_finish(struct intel_context *intel)
505
{
506
   if (!intel->upload.bo)
507
	   return;
508
 
509
   if (intel->upload.buffer_len) {
510
	   drm_intel_bo_subdata(intel->upload.bo,
511
				intel->upload.buffer_offset,
512
				intel->upload.buffer_len,
513
				intel->upload.buffer);
514
	   intel->upload.buffer_len = 0;
515
   }
516
 
517
   drm_intel_bo_unreference(intel->upload.bo);
518
   intel->upload.bo = NULL;
519
}
520
 
521
static void wrap_buffers(struct intel_context *intel, GLuint size)
522
{
523
   intel_upload_finish(intel);
524
 
525
   if (size < INTEL_UPLOAD_SIZE)
526
      size = INTEL_UPLOAD_SIZE;
527
 
528
   intel->upload.bo = drm_intel_bo_alloc(intel->bufmgr, "upload", size, 0);
529
   intel->upload.offset = 0;
530
}
531
 
532
void intel_upload_data(struct intel_context *intel,
533
		       const void *ptr, GLuint size, GLuint align,
534
		       drm_intel_bo **return_bo,
535
		       GLuint *return_offset)
536
{
537
   GLuint base, delta;
538
 
539
   base = (intel->upload.offset + align - 1) / align * align;
540
   if (intel->upload.bo == NULL || base + size > intel->upload.bo->size) {
541
      wrap_buffers(intel, size);
542
      base = 0;
543
   }
544
 
545
   drm_intel_bo_reference(intel->upload.bo);
546
   *return_bo = intel->upload.bo;
547
   *return_offset = base;
548
 
549
   delta = base - intel->upload.offset;
550
   if (intel->upload.buffer_len &&
551
       intel->upload.buffer_len + delta + size > sizeof(intel->upload.buffer))
552
   {
553
      drm_intel_bo_subdata(intel->upload.bo,
554
			   intel->upload.buffer_offset,
555
			   intel->upload.buffer_len,
556
			   intel->upload.buffer);
557
      intel->upload.buffer_len = 0;
558
   }
559
 
560
   if (size < sizeof(intel->upload.buffer))
561
   {
562
      if (intel->upload.buffer_len == 0)
563
	 intel->upload.buffer_offset = base;
564
      else
565
	 intel->upload.buffer_len += delta;
566
 
567
      memcpy(intel->upload.buffer + intel->upload.buffer_len, ptr, size);
568
      intel->upload.buffer_len += size;
569
   }
570
   else
571
   {
572
      drm_intel_bo_subdata(intel->upload.bo, base, size, ptr);
573
   }
574
 
575
   intel->upload.offset = base + size;
576
}
577
 
578
drm_intel_bo *
579
intel_bufferobj_source(struct intel_context *intel,
580
                       struct intel_buffer_object *intel_obj,
581
		       GLuint align, GLuint *offset)
582
{
583
   if (intel_obj->buffer == NULL) {
584
      intel_upload_data(intel,
585
			intel_obj->sys_buffer, intel_obj->Base.Size, align,
586
			&intel_obj->buffer, &intel_obj->offset);
587
      intel_obj->source = 1;
588
   }
589
 
590
   *offset = intel_obj->offset;
591
   return intel_obj->buffer;
592
}
593
 
594
static void
595
intel_bufferobj_copy_subdata(struct gl_context *ctx,
596
			     struct gl_buffer_object *src,
597
			     struct gl_buffer_object *dst,
598
			     GLintptr read_offset, GLintptr write_offset,
599
			     GLsizeiptr size)
600
{
601
   struct intel_context *intel = intel_context(ctx);
602
   struct intel_buffer_object *intel_src = intel_buffer_object(src);
603
   struct intel_buffer_object *intel_dst = intel_buffer_object(dst);
604
   drm_intel_bo *src_bo, *dst_bo;
605
   GLuint src_offset;
606
 
607
   if (size == 0)
608
      return;
609
 
610
   /* If we're in system memory, just map and memcpy. */
611
   if (intel_src->sys_buffer || intel_dst->sys_buffer) {
612
      /* The same buffer may be used, but note that regions copied may
613
       * not overlap.
614
       */
615
      if (src == dst) {
616
	 char *ptr = intel_bufferobj_map_range(ctx, 0, dst->Size,
617
					       GL_MAP_READ_BIT |
618
					       GL_MAP_WRITE_BIT,
619
					       dst, MAP_INTERNAL);
620
	 memmove(ptr + write_offset, ptr + read_offset, size);
621
	 intel_bufferobj_unmap(ctx, dst, MAP_INTERNAL);
622
      } else {
623
	 const char *src_ptr;
624
	 char *dst_ptr;
625
 
626
	 src_ptr =  intel_bufferobj_map_range(ctx, 0, src->Size,
627
					      GL_MAP_READ_BIT, src,
628
                                              MAP_INTERNAL);
629
	 dst_ptr =  intel_bufferobj_map_range(ctx, 0, dst->Size,
630
					      GL_MAP_WRITE_BIT, dst,
631
                                              MAP_INTERNAL);
632
 
633
	 memcpy(dst_ptr + write_offset, src_ptr + read_offset, size);
634
 
635
	 intel_bufferobj_unmap(ctx, src, MAP_INTERNAL);
636
	 intel_bufferobj_unmap(ctx, dst, MAP_INTERNAL);
637
      }
638
      return;
639
   }
640
 
641
   /* Otherwise, we have real BOs, so blit them. */
642
 
643
   dst_bo = intel_bufferobj_buffer(intel, intel_dst);
644
   src_bo = intel_bufferobj_source(intel, intel_src, 64, &src_offset);
645
 
646
   intel_emit_linear_blit(intel,
647
			  dst_bo, write_offset,
648
			  src_bo, read_offset + src_offset, size);
649
 
650
   /* Since we've emitted some blits to buffers that will (likely) be used
651
    * in rendering operations in other cache domains in this batch, emit a
652
    * flush.  Once again, we wish for a domain tracker in libdrm to cover
653
    * usage inside of a batchbuffer.
654
    */
655
   intel_batchbuffer_emit_mi_flush(intel);
656
}
657
 
658
static GLenum
659
intel_buffer_purgeable(drm_intel_bo *buffer)
660
{
661
   int retained = 0;
662
 
663
   if (buffer != NULL)
664
      retained = drm_intel_bo_madvise (buffer, I915_MADV_DONTNEED);
665
 
666
   return retained ? GL_VOLATILE_APPLE : GL_RELEASED_APPLE;
667
}
668
 
669
static GLenum
670
intel_buffer_object_purgeable(struct gl_context * ctx,
671
                              struct gl_buffer_object *obj,
672
                              GLenum option)
673
{
674
   struct intel_buffer_object *intel_obj = intel_buffer_object (obj);
675
 
676
   if (intel_obj->buffer != NULL)
677
      return intel_buffer_purgeable(intel_obj->buffer);
678
 
679
   if (option == GL_RELEASED_APPLE) {
680
      _mesa_align_free(intel_obj->sys_buffer);
681
      intel_obj->sys_buffer = NULL;
682
 
683
      return GL_RELEASED_APPLE;
684
   } else {
685
      /* XXX Create the buffer and madvise(MADV_DONTNEED)? */
686
      struct intel_context *intel = intel_context(ctx);
687
      drm_intel_bo *bo = intel_bufferobj_buffer(intel, intel_obj);
688
 
689
      return intel_buffer_purgeable(bo);
690
   }
691
}
692
 
693
static GLenum
694
intel_texture_object_purgeable(struct gl_context * ctx,
695
                               struct gl_texture_object *obj,
696
                               GLenum option)
697
{
698
   struct intel_texture_object *intel;
699
 
700
   (void) ctx;
701
   (void) option;
702
 
703
   intel = intel_texture_object(obj);
704
   if (intel->mt == NULL || intel->mt->region == NULL)
705
      return GL_RELEASED_APPLE;
706
 
707
   return intel_buffer_purgeable(intel->mt->region->bo);
708
}
709
 
710
static GLenum
711
intel_render_object_purgeable(struct gl_context * ctx,
712
                              struct gl_renderbuffer *obj,
713
                              GLenum option)
714
{
715
   struct intel_renderbuffer *intel;
716
 
717
   (void) ctx;
718
   (void) option;
719
 
720
   intel = intel_renderbuffer(obj);
721
   if (intel->mt == NULL)
722
      return GL_RELEASED_APPLE;
723
 
724
   return intel_buffer_purgeable(intel->mt->region->bo);
725
}
726
 
727
static GLenum
728
intel_buffer_unpurgeable(drm_intel_bo *buffer)
729
{
730
   int retained;
731
 
732
   retained = 0;
733
   if (buffer != NULL)
734
      retained = drm_intel_bo_madvise (buffer, I915_MADV_WILLNEED);
735
 
736
   return retained ? GL_RETAINED_APPLE : GL_UNDEFINED_APPLE;
737
}
738
 
739
static GLenum
740
intel_buffer_object_unpurgeable(struct gl_context * ctx,
741
                                struct gl_buffer_object *obj,
742
                                GLenum option)
743
{
744
   (void) ctx;
745
   (void) option;
746
 
747
   return intel_buffer_unpurgeable(intel_buffer_object (obj)->buffer);
748
}
749
 
750
static GLenum
751
intel_texture_object_unpurgeable(struct gl_context * ctx,
752
                                 struct gl_texture_object *obj,
753
                                 GLenum option)
754
{
755
   struct intel_texture_object *intel;
756
 
757
   (void) ctx;
758
   (void) option;
759
 
760
   intel = intel_texture_object(obj);
761
   if (intel->mt == NULL || intel->mt->region == NULL)
762
      return GL_UNDEFINED_APPLE;
763
 
764
   return intel_buffer_unpurgeable(intel->mt->region->bo);
765
}
766
 
767
static GLenum
768
intel_render_object_unpurgeable(struct gl_context * ctx,
769
                                struct gl_renderbuffer *obj,
770
                                GLenum option)
771
{
772
   struct intel_renderbuffer *intel;
773
 
774
   (void) ctx;
775
   (void) option;
776
 
777
   intel = intel_renderbuffer(obj);
778
   if (intel->mt == NULL)
779
      return GL_UNDEFINED_APPLE;
780
 
781
   return intel_buffer_unpurgeable(intel->mt->region->bo);
782
}
783
 
784
void
785
intelInitBufferObjectFuncs(struct dd_function_table *functions)
786
{
787
   functions->NewBufferObject = intel_bufferobj_alloc;
788
   functions->DeleteBuffer = intel_bufferobj_free;
789
   functions->BufferData = intel_bufferobj_data;
790
   functions->BufferSubData = intel_bufferobj_subdata;
791
   functions->GetBufferSubData = intel_bufferobj_get_subdata;
792
   functions->MapBufferRange = intel_bufferobj_map_range;
793
   functions->FlushMappedBufferRange = intel_bufferobj_flush_mapped_range;
794
   functions->UnmapBuffer = intel_bufferobj_unmap;
795
   functions->CopyBufferSubData = intel_bufferobj_copy_subdata;
796
 
797
   functions->BufferObjectPurgeable = intel_buffer_object_purgeable;
798
   functions->TextureObjectPurgeable = intel_texture_object_purgeable;
799
   functions->RenderObjectPurgeable = intel_render_object_purgeable;
800
 
801
   functions->BufferObjectUnpurgeable = intel_buffer_object_unpurgeable;
802
   functions->TextureObjectUnpurgeable = intel_texture_object_unpurgeable;
803
   functions->RenderObjectUnpurgeable = intel_render_object_unpurgeable;
804
}