~ubuntu-branches/ubuntu/quantal/mesa/quantal

« back to all changes in this revision

Viewing changes to src/mesa/drivers/dri/i915tex/intel_regions.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-02-21 12:44:07 UTC
  • mfrom: (1.2.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 22.
  • Revision ID: james.westby@ubuntu.com-20070221124407-rgcacs32mycrtadl
ImportĀ upstreamĀ versionĀ 6.5.2

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 "intel_context.h"
 
43
#include "intel_regions.h"
 
44
#include "intel_blit.h"
 
45
#include "intel_buffer_objects.h"
 
46
#include "dri_bufmgr.h"
 
47
#include "intel_batchbuffer.h"
 
48
 
 
49
#define FILE_DEBUG_FLAG DEBUG_REGION
 
50
 
 
51
void
 
52
intel_region_idle(intelScreenPrivate *intelScreen, struct intel_region *region)
 
53
{
 
54
   DBG("%s\n", __FUNCTION__);
 
55
   if (region && region->buffer)
 
56
      driBOWaitIdle(region->buffer, GL_FALSE);
 
57
}
 
58
 
 
59
/* XXX: Thread safety?
 
60
 */
 
61
GLubyte *
 
62
intel_region_map(intelScreenPrivate *intelScreen, struct intel_region *region)
 
63
{
 
64
   DBG("%s\n", __FUNCTION__);
 
65
   if (!region->map_refcount++) {
 
66
      if (region->pbo)
 
67
         intel_region_cow(intelScreen, region);
 
68
 
 
69
      region->map = driBOMap(region->buffer,
 
70
                             DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0);
 
71
   }
 
72
 
 
73
   return region->map;
 
74
}
 
75
 
 
76
void
 
77
intel_region_unmap(intelScreenPrivate *intelScreen, struct intel_region *region)
 
78
{
 
79
   DBG("%s\n", __FUNCTION__);
 
80
   if (!--region->map_refcount) {
 
81
      driBOUnmap(region->buffer);
 
82
      region->map = NULL;
 
83
   }
 
84
}
 
85
 
 
86
#undef TEST_CACHED_TEXTURES
 
87
 
 
88
struct intel_region *
 
89
intel_region_alloc(intelScreenPrivate *intelScreen,
 
90
                   GLuint cpp, GLuint pitch, GLuint height)
 
91
{
 
92
   struct intel_region *region = calloc(sizeof(*region), 1);
 
93
 
 
94
   DBG("%s\n", __FUNCTION__);
 
95
 
 
96
   region->cpp = cpp;
 
97
   region->pitch = pitch;
 
98
   region->height = height;     /* needed? */
 
99
   region->refcount = 1;
 
100
 
 
101
   driGenBuffers(intelScreen->regionPool,
 
102
                 "region", 1, &region->buffer, 64,
 
103
#ifdef TEST_CACHED_TEXTURES              
 
104
                 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_BIND_CACHED |
 
105
                 DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 
 
106
#else
 
107
                 0,
 
108
#endif
 
109
                 0);
 
110
   driBOData(region->buffer, pitch * cpp * height, NULL, 0);
 
111
   return region;
 
112
}
 
113
 
 
114
void
 
115
intel_region_reference(struct intel_region **dst, struct intel_region *src)
 
116
{
 
117
   assert(*dst == NULL);
 
118
   if (src) {
 
119
      src->refcount++;
 
120
      *dst = src;
 
121
   }
 
122
}
 
123
 
 
124
void
 
125
intel_region_release(struct intel_region **region)
 
126
{
 
127
   if (!*region)
 
128
      return;
 
129
 
 
130
   DBG("%s %d\n", __FUNCTION__, (*region)->refcount - 1);
 
131
 
 
132
   ASSERT((*region)->refcount > 0);
 
133
   (*region)->refcount--;
 
134
 
 
135
   if ((*region)->refcount == 0) {
 
136
      assert((*region)->map_refcount == 0);
 
137
 
 
138
      if ((*region)->pbo)
 
139
         (*region)->pbo->region = NULL;
 
140
      (*region)->pbo = NULL;
 
141
      driBOUnReference((*region)->buffer);
 
142
      free(*region);
 
143
   }
 
144
   *region = NULL;
 
145
}
 
146
 
 
147
 
 
148
struct intel_region *
 
149
intel_region_create_static(intelScreenPrivate *intelScreen,
 
150
                           GLuint mem_type,
 
151
                           GLuint offset,
 
152
                           void *virtual,
 
153
                           GLuint cpp, GLuint pitch, GLuint height)
 
154
{
 
155
   struct intel_region *region = calloc(sizeof(*region), 1);
 
156
   DBG("%s\n", __FUNCTION__);
 
157
 
 
158
   region->cpp = cpp;
 
159
   region->pitch = pitch;
 
160
   region->height = height;     /* needed? */
 
161
   region->refcount = 1;
 
162
 
 
163
   /*
 
164
    * We use a "shared" buffer type to indicate buffers created and
 
165
    * shared by others.
 
166
    */
 
167
 
 
168
   driGenBuffers(intelScreen->staticPool, "static region", 1,
 
169
                 &region->buffer, 64,
 
170
                 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_NO_MOVE |
 
171
                 DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0);
 
172
   driBOSetStatic(region->buffer, offset, pitch * cpp * height, virtual, 0);
 
173
 
 
174
   return region;
 
175
}
 
176
 
 
177
 
 
178
 
 
179
void
 
180
intel_region_update_static(intelScreenPrivate *intelScreen,
 
181
                           struct intel_region *region,
 
182
                           GLuint mem_type,
 
183
                           GLuint offset,
 
184
                           void *virtual,
 
185
                           GLuint cpp, GLuint pitch, GLuint height)
 
186
{
 
187
   DBG("%s\n", __FUNCTION__);
 
188
 
 
189
   region->cpp = cpp;
 
190
   region->pitch = pitch;
 
191
   region->height = height;     /* needed? */
 
192
 
 
193
   /*
 
194
    * We use a "shared" buffer type to indicate buffers created and
 
195
    * shared by others.
 
196
    */
 
197
 
 
198
   driDeleteBuffers(1, &region->buffer);
 
199
   driGenBuffers(intelScreen->staticPool, "static region", 1,
 
200
                 &region->buffer, 64,
 
201
                 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_NO_MOVE |
 
202
                 DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0);
 
203
   driBOSetStatic(region->buffer, offset, pitch * cpp * height, virtual, 0);
 
204
 
 
205
}
 
206
 
 
207
 
 
208
 
 
209
/*
 
210
 * XXX Move this into core Mesa?
 
211
 */
 
212
static void
 
213
_mesa_copy_rect(GLubyte * dst,
 
214
                GLuint cpp,
 
215
                GLuint dst_pitch,
 
216
                GLuint dst_x,
 
217
                GLuint dst_y,
 
218
                GLuint width,
 
219
                GLuint height,
 
220
                GLubyte * src, GLuint src_pitch, GLuint src_x, GLuint src_y)
 
221
{
 
222
   GLuint i;
 
223
 
 
224
   dst_pitch *= cpp;
 
225
   src_pitch *= cpp;
 
226
   dst += dst_x * cpp;
 
227
   src += src_x * cpp;
 
228
   dst += dst_y * dst_pitch;
 
229
   src += src_y * dst_pitch;
 
230
   width *= cpp;
 
231
 
 
232
   if (width == dst_pitch && width == src_pitch)
 
233
      memcpy(dst, src, height * width);
 
234
   else {
 
235
      for (i = 0; i < height; i++) {
 
236
         memcpy(dst, src, width);
 
237
         dst += dst_pitch;
 
238
         src += src_pitch;
 
239
      }
 
240
   }
 
241
}
 
242
 
 
243
 
 
244
/* Upload data to a rectangular sub-region.  Lots of choices how to do this:
 
245
 *
 
246
 * - memcpy by span to current destination
 
247
 * - upload data as new buffer and blit
 
248
 *
 
249
 * Currently always memcpy.
 
250
 */
 
251
void
 
252
intel_region_data(intelScreenPrivate *intelScreen,
 
253
                  struct intel_region *dst,
 
254
                  GLuint dst_offset,
 
255
                  GLuint dstx, GLuint dsty,
 
256
                  void *src, GLuint src_pitch,
 
257
                  GLuint srcx, GLuint srcy, GLuint width, GLuint height)
 
258
{
 
259
   struct intel_context *intel = intelScreenContext(intelScreen);
 
260
 
 
261
   DBG("%s\n", __FUNCTION__);
 
262
 
 
263
   if (intel == NULL)
 
264
      return;
 
265
 
 
266
   if (dst->pbo) {
 
267
      if (dstx == 0 &&
 
268
          dsty == 0 && width == dst->pitch && height == dst->height)
 
269
         intel_region_release_pbo(intelScreen, dst);
 
270
      else
 
271
         intel_region_cow(intelScreen, dst);
 
272
   }
 
273
 
 
274
 
 
275
   LOCK_HARDWARE(intel);
 
276
 
 
277
   _mesa_copy_rect(intel_region_map(intelScreen, dst) + dst_offset,
 
278
                   dst->cpp,
 
279
                   dst->pitch,
 
280
                   dstx, dsty, width, height, src, src_pitch, srcx, srcy);
 
281
 
 
282
   intel_region_unmap(intelScreen, dst);
 
283
 
 
284
   UNLOCK_HARDWARE(intel);
 
285
 
 
286
}
 
287
 
 
288
/* Copy rectangular sub-regions. Need better logic about when to
 
289
 * push buffers into AGP - will currently do so whenever possible.
 
290
 */
 
291
void
 
292
intel_region_copy(intelScreenPrivate *intelScreen,
 
293
                  struct intel_region *dst,
 
294
                  GLuint dst_offset,
 
295
                  GLuint dstx, GLuint dsty,
 
296
                  struct intel_region *src,
 
297
                  GLuint src_offset,
 
298
                  GLuint srcx, GLuint srcy, GLuint width, GLuint height)
 
299
{
 
300
   struct intel_context *intel = intelScreenContext(intelScreen);
 
301
 
 
302
   DBG("%s\n", __FUNCTION__);
 
303
 
 
304
   if (intel == NULL)
 
305
      return;
 
306
 
 
307
   if (dst->pbo) {
 
308
      if (dstx == 0 &&
 
309
          dsty == 0 && width == dst->pitch && height == dst->height)
 
310
         intel_region_release_pbo(intelScreen, dst);
 
311
      else
 
312
         intel_region_cow(intelScreen, dst);
 
313
   }
 
314
 
 
315
   assert(src->cpp == dst->cpp);
 
316
 
 
317
   intelEmitCopyBlit(intel,
 
318
                     dst->cpp,
 
319
                     src->pitch, src->buffer, src_offset,
 
320
                     dst->pitch, dst->buffer, dst_offset,
 
321
                     srcx, srcy, dstx, dsty, width, height,
 
322
                     GL_COPY);
 
323
}
 
324
 
 
325
/* Fill a rectangular sub-region.  Need better logic about when to
 
326
 * push buffers into AGP - will currently do so whenever possible.
 
327
 */
 
328
void
 
329
intel_region_fill(intelScreenPrivate *intelScreen,
 
330
                  struct intel_region *dst,
 
331
                  GLuint dst_offset,
 
332
                  GLuint dstx, GLuint dsty,
 
333
                  GLuint width, GLuint height, GLuint color)
 
334
{
 
335
   struct intel_context *intel = intelScreenContext(intelScreen);
 
336
 
 
337
   DBG("%s\n", __FUNCTION__);
 
338
 
 
339
   if (intel == NULL)
 
340
      return;   
 
341
 
 
342
   if (dst->pbo) {
 
343
      if (dstx == 0 &&
 
344
          dsty == 0 && width == dst->pitch && height == dst->height)
 
345
         intel_region_release_pbo(intelScreen, dst);
 
346
      else
 
347
         intel_region_cow(intelScreen, dst);
 
348
   }
 
349
 
 
350
   intelEmitFillBlit(intel,
 
351
                     dst->cpp,
 
352
                     dst->pitch, dst->buffer, dst_offset,
 
353
                     dstx, dsty, width, height, color);
 
354
}
 
355
 
 
356
/* Attach to a pbo, discarding our data.  Effectively zero-copy upload
 
357
 * the pbo's data.
 
358
 */
 
359
void
 
360
intel_region_attach_pbo(intelScreenPrivate *intelScreen,
 
361
                        struct intel_region *region,
 
362
                        struct intel_buffer_object *pbo)
 
363
{
 
364
   if (region->pbo == pbo)
 
365
      return;
 
366
 
 
367
   /* If there is already a pbo attached, break the cow tie now.
 
368
    * Don't call intel_region_release_pbo() as that would
 
369
    * unnecessarily allocate a new buffer we would have to immediately
 
370
    * discard.
 
371
    */
 
372
   if (region->pbo) {
 
373
      region->pbo->region = NULL;
 
374
      region->pbo = NULL;
 
375
   }
 
376
 
 
377
   if (region->buffer) {
 
378
      driDeleteBuffers(1, &region->buffer);
 
379
      region->buffer = NULL;
 
380
   }
 
381
 
 
382
   region->pbo = pbo;
 
383
   region->pbo->region = region;
 
384
   region->buffer = driBOReference(pbo->buffer);
 
385
}
 
386
 
 
387
 
 
388
/* Break the COW tie to the pbo.  The pbo gets to keep the data.
 
389
 */
 
390
void
 
391
intel_region_release_pbo(intelScreenPrivate *intelScreen,
 
392
                         struct intel_region *region)
 
393
{
 
394
   assert(region->buffer == region->pbo->buffer);
 
395
   region->pbo->region = NULL;
 
396
   region->pbo = NULL;
 
397
   driBOUnReference(region->buffer);
 
398
   region->buffer = NULL;
 
399
 
 
400
   driGenBuffers(intelScreen->regionPool,
 
401
                 "region", 1, &region->buffer, 64, 0, 0);
 
402
   driBOData(region->buffer,
 
403
             region->cpp * region->pitch * region->height, NULL, 0);
 
404
}
 
405
 
 
406
/* Break the COW tie to the pbo.  Both the pbo and the region end up
 
407
 * with a copy of the data.
 
408
 */
 
409
void
 
410
intel_region_cow(intelScreenPrivate *intelScreen, struct intel_region *region)
 
411
{
 
412
   struct intel_context *intel = intelScreenContext(intelScreen);
 
413
   struct intel_buffer_object *pbo = region->pbo;
 
414
 
 
415
   if (intel == NULL)
 
416
      return;
 
417
 
 
418
   intel_region_release_pbo(intelScreen, region);
 
419
 
 
420
   assert(region->cpp * region->pitch * region->height == pbo->Base.Size);
 
421
 
 
422
   DBG("%s (%d bytes)\n", __FUNCTION__, pbo->Base.Size);
 
423
 
 
424
   /* Now blit from the texture buffer to the new buffer: 
 
425
    */
 
426
 
 
427
   intel_batchbuffer_flush(intel->batch);
 
428
 
 
429
   if (!intel->locked) {
 
430
      LOCK_HARDWARE(intel);
 
431
      intelEmitCopyBlit(intel,
 
432
                        region->cpp,
 
433
                        region->pitch,
 
434
                        region->buffer, 0,
 
435
                        region->pitch,
 
436
                        pbo->buffer, 0,
 
437
                        0, 0, 0, 0, 
 
438
                        region->pitch, region->height,
 
439
                        GL_COPY);
 
440
      
 
441
      intel_batchbuffer_flush(intel->batch);
 
442
      UNLOCK_HARDWARE(intel);
 
443
   }
 
444
   else {
 
445
      intelEmitCopyBlit(intel,
 
446
                        region->cpp,
 
447
                        region->pitch,
 
448
                        region->buffer, 0,
 
449
                        region->pitch,
 
450
                        pbo->buffer, 0,
 
451
                        0, 0, 0, 0, 
 
452
                        region->pitch, region->height,
 
453
                        GL_COPY);
 
454
      
 
455
      intel_batchbuffer_flush(intel->batch);
 
456
   }
 
457
}
 
458
 
 
459
struct _DriBufferObject *
 
460
intel_region_buffer(intelScreenPrivate *intelScreen,
 
461
                    struct intel_region *region, GLuint flag)
 
462
{
 
463
   if (region->pbo) {
 
464
      if (flag == INTEL_WRITE_PART)
 
465
         intel_region_cow(intelScreen, region);
 
466
      else if (flag == INTEL_WRITE_FULL)
 
467
         intel_region_release_pbo(intelScreen, region);
 
468
   }
 
469
 
 
470
   return region->buffer;
 
471
}