~gma500/+junk/gma500-natty

« back to all changes in this revision

Viewing changes to xpsb-glx/mesa/src/mesa/drivers/dri/intel/intel_regions.c

  • Committer: Luca Forina
  • Date: 2011-02-14 10:01:54 UTC
  • Revision ID: luca.forina@gmail.com-20110214100154-ai9gynuqb1dna2ea
new commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**************************************************************************
 
2
 * 
 
3
 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
 
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 TUNGSTEN GRAPHICS 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
/* Provide additional functionality on top of bufmgr buffers:
 
29
 *   - 2d semantics and blit operations
 
30
 *   - refcounting of buffers for multiple images in a buffer.
 
31
 *   - refcounting of buffer mappings.
 
32
 *   - some logic for moving the buffers to the best memory pools for
 
33
 *     given operations.
 
34
 *
 
35
 * Most of this is to make it easier to implement the fixed-layout
 
36
 * mipmap tree required by intel hardware in the face of GL's
 
37
 * programming interface where each image can be specifed in random
 
38
 * order and it isn't clear what layout the tree should have until the
 
39
 * last moment.
 
40
 */
 
41
 
 
42
#include <sys/ioctl.h>
 
43
#include <errno.h>
 
44
 
 
45
#include "intel_context.h"
 
46
#include "intel_regions.h"
 
47
#include "intel_blit.h"
 
48
#include "intel_buffer_objects.h"
 
49
#include "intel_bufmgr.h"
 
50
#include "intel_batchbuffer.h"
 
51
#include "intel_chipset.h"
 
52
 
 
53
#define FILE_DEBUG_FLAG DEBUG_REGION
 
54
 
 
55
/* XXX: Thread safety?
 
56
 */
 
57
GLubyte *
 
58
intel_region_map(struct intel_context *intel, struct intel_region *region)
 
59
{
 
60
   DBG("%s\n", __FUNCTION__);
 
61
   if (!region->map_refcount++) {
 
62
      if (region->pbo)
 
63
         intel_region_cow(intel, region);
 
64
 
 
65
      dri_bo_map(region->buffer, GL_TRUE);
 
66
      region->map = region->buffer->virtual;
 
67
   }
 
68
 
 
69
   return region->map;
 
70
}
 
71
 
 
72
void
 
73
intel_region_unmap(struct intel_context *intel, struct intel_region *region)
 
74
{
 
75
   DBG("%s\n", __FUNCTION__);
 
76
   if (!--region->map_refcount) {
 
77
      dri_bo_unmap(region->buffer);
 
78
      region->map = NULL;
 
79
   }
 
80
}
 
81
 
 
82
static struct intel_region *
 
83
intel_region_alloc_internal(struct intel_context *intel,
 
84
                            GLuint cpp,
 
85
                            GLuint width, GLuint height, GLuint pitch,
 
86
                            dri_bo *buffer)
 
87
{
 
88
   struct intel_region *region;
 
89
 
 
90
   DBG("%s\n", __FUNCTION__);
 
91
 
 
92
   if (buffer == NULL)
 
93
      return NULL;
 
94
 
 
95
   region = calloc(sizeof(*region), 1);
 
96
   region->cpp = cpp;
 
97
   region->width = width;
 
98
   region->height = height;
 
99
   region->pitch = pitch;
 
100
   region->refcount = 1;
 
101
   region->buffer = buffer;
 
102
 
 
103
   /* Default to no tiling */
 
104
   region->tiling = I915_TILING_NONE;
 
105
   region->bit_6_swizzle = I915_BIT_6_SWIZZLE_NONE;
 
106
 
 
107
   return region;
 
108
}
 
109
 
 
110
struct intel_region *
 
111
intel_region_alloc(struct intel_context *intel,
 
112
                   GLuint cpp, GLuint width, GLuint height, GLuint pitch,
 
113
                   GLboolean expect_accelerated_upload)
 
114
{
 
115
   dri_bo *buffer;
 
116
 
 
117
   if (expect_accelerated_upload) {
 
118
      buffer = drm_intel_bo_alloc_for_render(intel->bufmgr, "region",
 
119
                                             pitch * cpp * height, 64);
 
120
   } else {
 
121
      buffer = drm_intel_bo_alloc(intel->bufmgr, "region",
 
122
                                  pitch * cpp * height, 64);
 
123
   }
 
124
 
 
125
   return intel_region_alloc_internal(intel, cpp, width, height, pitch, buffer);
 
126
}
 
127
 
 
128
struct intel_region *
 
129
intel_region_alloc_for_handle(struct intel_context *intel,
 
130
                              GLuint cpp,
 
131
                              GLuint width, GLuint height, GLuint pitch,
 
132
                              GLuint handle, const char *name)
 
133
{
 
134
   struct intel_region *region;
 
135
   dri_bo *buffer;
 
136
   int ret;
 
137
 
 
138
   buffer = intel_bo_gem_create_from_name(intel->bufmgr, name, handle);
 
139
 
 
140
   region = intel_region_alloc_internal(intel, cpp,
 
141
                                        width, height, pitch, buffer);
 
142
   if (region == NULL)
 
143
      return region;
 
144
 
 
145
   ret = dri_bo_get_tiling(region->buffer, &region->tiling,
 
146
                           &region->bit_6_swizzle);
 
147
   if (ret != 0) {
 
148
      fprintf(stderr, "Couldn't get tiling of buffer %d (%s): %s\n",
 
149
              handle, name, strerror(-ret));
 
150
      intel_region_release(&region);
 
151
      return NULL;
 
152
   }
 
153
 
 
154
   return region;
 
155
}
 
156
 
 
157
void
 
158
intel_region_reference(struct intel_region **dst, struct intel_region *src)
 
159
{
 
160
   if (src)
 
161
      DBG("%s %d\n", __FUNCTION__, src->refcount);
 
162
 
 
163
   assert(*dst == NULL);
 
164
   if (src) {
 
165
      src->refcount++;
 
166
      *dst = src;
 
167
   }
 
168
}
 
169
 
 
170
void
 
171
intel_region_release(struct intel_region **region_handle)
 
172
{
 
173
   struct intel_region *region = *region_handle;
 
174
 
 
175
   if (region == NULL)
 
176
      return;
 
177
 
 
178
   DBG("%s %d\n", __FUNCTION__, region->refcount - 1);
 
179
 
 
180
   ASSERT(region->refcount > 0);
 
181
   region->refcount--;
 
182
 
 
183
   if (region->refcount == 0) {
 
184
      assert(region->map_refcount == 0);
 
185
 
 
186
      if (region->pbo)
 
187
         region->pbo->region = NULL;
 
188
      region->pbo = NULL;
 
189
      dri_bo_unreference(region->buffer);
 
190
 
 
191
      if (region->classic_map != NULL) {
 
192
         drmUnmap(region->classic_map,
 
193
                        region->pitch * region->cpp * region->height);
 
194
      }
 
195
 
 
196
      free(region);
 
197
   }
 
198
   *region_handle = NULL;
 
199
}
 
200
 
 
201
/*
 
202
 * XXX Move this into core Mesa?
 
203
 */
 
204
void
 
205
_mesa_copy_rect(GLubyte * dst,
 
206
                GLuint cpp,
 
207
                GLuint dst_pitch,
 
208
                GLuint dst_x,
 
209
                GLuint dst_y,
 
210
                GLuint width,
 
211
                GLuint height,
 
212
                const GLubyte * src,
 
213
                GLuint src_pitch, GLuint src_x, GLuint src_y)
 
214
{
 
215
   GLuint i;
 
216
 
 
217
   dst_pitch *= cpp;
 
218
   src_pitch *= cpp;
 
219
   dst += dst_x * cpp;
 
220
   src += src_x * cpp;
 
221
   dst += dst_y * dst_pitch;
 
222
   src += src_y * dst_pitch;
 
223
   width *= cpp;
 
224
 
 
225
   if (width == dst_pitch && width == src_pitch)
 
226
      memcpy(dst, src, height * width);
 
227
   else {
 
228
      for (i = 0; i < height; i++) {
 
229
         memcpy(dst, src, width);
 
230
         dst += dst_pitch;
 
231
         src += src_pitch;
 
232
      }
 
233
   }
 
234
}
 
235
 
 
236
 
 
237
/* Upload data to a rectangular sub-region.  Lots of choices how to do this:
 
238
 *
 
239
 * - memcpy by span to current destination
 
240
 * - upload data as new buffer and blit
 
241
 *
 
242
 * Currently always memcpy.
 
243
 */
 
244
void
 
245
intel_region_data(struct intel_context *intel,
 
246
                  struct intel_region *dst,
 
247
                  GLuint dst_offset,
 
248
                  GLuint dstx, GLuint dsty,
 
249
                  const void *src, GLuint src_pitch,
 
250
                  GLuint srcx, GLuint srcy, GLuint width, GLuint height)
 
251
{
 
252
   GLboolean locked = GL_FALSE;
 
253
 
 
254
   DBG("%s\n", __FUNCTION__);
 
255
 
 
256
   if (intel == NULL)
 
257
      return;
 
258
 
 
259
   if (dst->pbo) {
 
260
      if (dstx == 0 &&
 
261
          dsty == 0 && width == dst->pitch && height == dst->height)
 
262
         intel_region_release_pbo(intel, dst);
 
263
      else
 
264
         intel_region_cow(intel, dst);
 
265
   }
 
266
 
 
267
   if (!intel->locked) {
 
268
      LOCK_HARDWARE(intel);
 
269
      locked = GL_TRUE;
 
270
   }
 
271
 
 
272
   _mesa_copy_rect(intel_region_map(intel, dst) + dst_offset,
 
273
                   dst->cpp,
 
274
                   dst->pitch,
 
275
                   dstx, dsty, width, height, src, src_pitch, srcx, srcy);
 
276
 
 
277
   intel_region_unmap(intel, dst);
 
278
 
 
279
   if (locked)
 
280
      UNLOCK_HARDWARE(intel);
 
281
 
 
282
}
 
283
 
 
284
/* Copy rectangular sub-regions. Need better logic about when to
 
285
 * push buffers into AGP - will currently do so whenever possible.
 
286
 */
 
287
void
 
288
intel_region_copy(struct intel_context *intel,
 
289
                  struct intel_region *dst,
 
290
                  GLuint dst_offset,
 
291
                  GLuint dstx, GLuint dsty,
 
292
                  struct intel_region *src,
 
293
                  GLuint src_offset,
 
294
                  GLuint srcx, GLuint srcy, GLuint width, GLuint height)
 
295
{
 
296
   DBG("%s\n", __FUNCTION__);
 
297
 
 
298
   if (intel == NULL)
 
299
      return;
 
300
 
 
301
   if (dst->pbo) {
 
302
      if (dstx == 0 &&
 
303
          dsty == 0 && width == dst->pitch && height == dst->height)
 
304
         intel_region_release_pbo(intel, dst);
 
305
      else
 
306
         intel_region_cow(intel, dst);
 
307
   }
 
308
 
 
309
   assert(src->cpp == dst->cpp);
 
310
 
 
311
   intelEmitCopyBlit(intel,
 
312
                     dst->cpp,
 
313
                     src->pitch, src->buffer, src_offset, src->tiling,
 
314
                     dst->pitch, dst->buffer, dst_offset, dst->tiling,
 
315
                     srcx, srcy, dstx, dsty, width, height,
 
316
                     GL_COPY);
 
317
}
 
318
 
 
319
/* Fill a rectangular sub-region.  Need better logic about when to
 
320
 * push buffers into AGP - will currently do so whenever possible.
 
321
 */
 
322
void
 
323
intel_region_fill(struct intel_context *intel,
 
324
                  struct intel_region *dst,
 
325
                  GLuint dst_offset,
 
326
                  GLuint dstx, GLuint dsty,
 
327
                  GLuint width, GLuint height, GLuint color)
 
328
{
 
329
   DBG("%s\n", __FUNCTION__);
 
330
 
 
331
   if (intel == NULL)
 
332
      return;   
 
333
 
 
334
   if (dst->pbo) {
 
335
      if (dstx == 0 &&
 
336
          dsty == 0 && width == dst->pitch && height == dst->height)
 
337
         intel_region_release_pbo(intel, dst);
 
338
      else
 
339
         intel_region_cow(intel, dst);
 
340
   }
 
341
 
 
342
   intelEmitFillBlit(intel,
 
343
                     dst->cpp,
 
344
                     dst->pitch, dst->buffer, dst_offset, dst->tiling,
 
345
                     dstx, dsty, width, height, color);
 
346
}
 
347
 
 
348
/* Attach to a pbo, discarding our data.  Effectively zero-copy upload
 
349
 * the pbo's data.
 
350
 */
 
351
void
 
352
intel_region_attach_pbo(struct intel_context *intel,
 
353
                        struct intel_region *region,
 
354
                        struct intel_buffer_object *pbo)
 
355
{
 
356
   if (region->pbo == pbo)
 
357
      return;
 
358
 
 
359
   /* If there is already a pbo attached, break the cow tie now.
 
360
    * Don't call intel_region_release_pbo() as that would
 
361
    * unnecessarily allocate a new buffer we would have to immediately
 
362
    * discard.
 
363
    */
 
364
   if (region->pbo) {
 
365
      region->pbo->region = NULL;
 
366
      region->pbo = NULL;
 
367
   }
 
368
 
 
369
   if (region->buffer) {
 
370
      dri_bo_unreference(region->buffer);
 
371
      region->buffer = NULL;
 
372
   }
 
373
 
 
374
   region->pbo = pbo;
 
375
   region->pbo->region = region;
 
376
   dri_bo_reference(pbo->buffer);
 
377
   region->buffer = pbo->buffer;
 
378
}
 
379
 
 
380
 
 
381
/* Break the COW tie to the pbo and allocate a new buffer.
 
382
 * The pbo gets to keep the data.
 
383
 */
 
384
void
 
385
intel_region_release_pbo(struct intel_context *intel,
 
386
                         struct intel_region *region)
 
387
{
 
388
   assert(region->buffer == region->pbo->buffer);
 
389
   region->pbo->region = NULL;
 
390
   region->pbo = NULL;
 
391
   dri_bo_unreference(region->buffer);
 
392
   region->buffer = NULL;
 
393
 
 
394
   region->buffer = dri_bo_alloc(intel->bufmgr, "region",
 
395
                                 region->pitch * region->cpp * region->height,
 
396
                                 64);
 
397
}
 
398
 
 
399
/* Break the COW tie to the pbo.  Both the pbo and the region end up
 
400
 * with a copy of the data.
 
401
 */
 
402
void
 
403
intel_region_cow(struct intel_context *intel, struct intel_region *region)
 
404
{
 
405
   struct intel_buffer_object *pbo = region->pbo;
 
406
   GLboolean was_locked = intel->locked;
 
407
 
 
408
   if (intel == NULL)
 
409
      return;
 
410
 
 
411
   intel_region_release_pbo(intel, region);
 
412
 
 
413
   assert(region->cpp * region->pitch * region->height == pbo->Base.Size);
 
414
 
 
415
   DBG("%s (%d bytes)\n", __FUNCTION__, pbo->Base.Size);
 
416
 
 
417
   /* Now blit from the texture buffer to the new buffer: 
 
418
    */
 
419
 
 
420
   was_locked = intel->locked;
 
421
   if (!was_locked)
 
422
      LOCK_HARDWARE(intel);
 
423
 
 
424
   intelEmitCopyBlit(intel,
 
425
                     region->cpp,
 
426
                     region->pitch, region->buffer, 0, region->tiling,
 
427
                     region->pitch, pbo->buffer, 0, region->tiling,
 
428
                     0, 0, 0, 0,
 
429
                     region->pitch, region->height,
 
430
                     GL_COPY);
 
431
 
 
432
   if (!was_locked)
 
433
      UNLOCK_HARDWARE(intel);
 
434
}
 
435
 
 
436
dri_bo *
 
437
intel_region_buffer(struct intel_context *intel,
 
438
                    struct intel_region *region, GLuint flag)
 
439
{
 
440
   if (region->pbo) {
 
441
      if (flag == INTEL_WRITE_PART)
 
442
         intel_region_cow(intel, region);
 
443
      else if (flag == INTEL_WRITE_FULL)
 
444
         intel_region_release_pbo(intel, region);
 
445
   }
 
446
 
 
447
   return region->buffer;
 
448
}
 
449
 
 
450
static struct intel_region *
 
451
intel_recreate_static(struct intel_context *intel,
 
452
                      const char *name,
 
453
                      struct intel_region *region,
 
454
                      intelRegion *region_desc)
 
455
{
 
456
   intelScreenPrivate *intelScreen = intel->intelScreen;
 
457
   int ret;
 
458
 
 
459
   if (region == NULL) {
 
460
      region = calloc(sizeof(*region), 1);
 
461
      region->refcount = 1;
 
462
   }
 
463
 
 
464
   if (intel->ctx.Visual.rgbBits == 24)
 
465
      region->cpp = 4;
 
466
   else
 
467
      region->cpp = intel->ctx.Visual.rgbBits / 8;
 
468
   region->pitch = intelScreen->pitch;
 
469
   region->height = intelScreen->height;     /* needed? */
 
470
 
 
471
   if (region->buffer != NULL) {
 
472
      dri_bo_unreference(region->buffer);
 
473
      region->buffer = NULL;
 
474
   }
 
475
 
 
476
   if (intel->ttm) {
 
477
      assert(region_desc->bo_handle != -1);
 
478
      region->buffer = intel_bo_gem_create_from_name(intel->bufmgr,
 
479
                                                     name,
 
480
                                                     region_desc->bo_handle);
 
481
 
 
482
      ret = dri_bo_get_tiling(region->buffer, &region->tiling,
 
483
                              &region->bit_6_swizzle);
 
484
      if (ret != 0) {
 
485
         fprintf(stderr, "Couldn't get tiling of buffer %d (%s): %s\n",
 
486
                 region_desc->bo_handle, name, strerror(-ret));
 
487
         intel_region_release(&region);
 
488
         return NULL;
 
489
      }
 
490
   } else {
 
491
      if (region->classic_map != NULL) {
 
492
         drmUnmap(region->classic_map,
 
493
                  region->pitch * region->cpp * region->height);
 
494
         region->classic_map = NULL;
 
495
      }
 
496
      ret = drmMap(intel->driFd, region_desc->handle,
 
497
                   region->pitch * region->cpp * region->height,
 
498
                   &region->classic_map);
 
499
      if (ret != 0) {
 
500
         fprintf(stderr, "Failed to drmMap %s buffer\n", name);
 
501
         free(region);
 
502
         return NULL;
 
503
      }
 
504
 
 
505
      region->buffer = intel_bo_fake_alloc_static(intel->bufmgr,
 
506
                                                  name,
 
507
                                                  region_desc->offset,
 
508
                                                  region->pitch * region->cpp *
 
509
                                                  region->height,
 
510
                                                  region->classic_map);
 
511
 
 
512
      /* The sarea just gives us a boolean for whether it's tiled or not,
 
513
       * instead of which tiling mode it is.  Guess.
 
514
       */
 
515
      if (region_desc->tiled) {
 
516
         if (IS_965(intel->intelScreen->deviceID) &&
 
517
             region_desc == &intelScreen->depth)
 
518
            region->tiling = I915_TILING_Y;
 
519
         else
 
520
            region->tiling = I915_TILING_X;
 
521
      } else {
 
522
         region->tiling = I915_TILING_NONE;
 
523
      }
 
524
 
 
525
      region->bit_6_swizzle = I915_BIT_6_SWIZZLE_NONE;
 
526
   }
 
527
 
 
528
   assert(region->buffer != NULL);
 
529
 
 
530
   return region;
 
531
}
 
532
 
 
533
/**
 
534
 * Create intel_region structs to describe the static front, back, and depth
 
535
 * buffers created by the xserver.
 
536
 *
 
537
 * Although FBO's mean we now no longer use these as render targets in
 
538
 * all circumstances, they won't go away until the back and depth
 
539
 * buffers become private, and the front buffer will remain even then.
 
540
 *
 
541
 * Note that these don't allocate video memory, just describe
 
542
 * allocations alread made by the X server.
 
543
 */
 
544
void
 
545
intel_recreate_static_regions(struct intel_context *intel)
 
546
{
 
547
   intelScreenPrivate *intelScreen = intel->intelScreen;
 
548
 
 
549
   intel->front_region =
 
550
      intel_recreate_static(intel, "front",
 
551
                            intel->front_region,
 
552
                            &intelScreen->front);
 
553
 
 
554
   intel->back_region =
 
555
      intel_recreate_static(intel, "back",
 
556
                            intel->back_region,
 
557
                            &intelScreen->back);
 
558
 
 
559
   /* Still assumes front.cpp == depth.cpp.  We can kill this when we move to
 
560
    * private buffers.
 
561
    */
 
562
   intel->depth_region =
 
563
      intel_recreate_static(intel, "depth",
 
564
                            intel->depth_region,
 
565
                            &intelScreen->depth);
 
566
}