Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 1
/**************************************************************************
2
 *
3
 * Copyright 2006 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
  * Authors:
29
  *   Keith Whitwell 
30
  *   Michel Dänzer 
31
  */
32
 
33
#include "pipe/p_state.h"
34
#include "pipe/p_context.h"
35
#include "pipe/p_defines.h"
36
#include "util/u_inlines.h"
37
#include "util/u_format.h"
38
#include "util/u_math.h"
39
#include "util/u_memory.h"
40
#include "util/u_rect.h"
41
 
42
#include "i915_context.h"
43
#include "i915_resource.h"
44
#include "i915_screen.h"
45
#include "i915_winsys.h"
46
#include "i915_debug.h"
47
 
48
 
49
#define DEBUG_TEXTURES 0
50
 
51
/*
52
 * Helper function and arrays
53
 */
54
 
55
 
56
/**
57
 * Initial offset for Cube map.
58
 */
59
static const int initial_offsets[6][2] = {
60
   [PIPE_TEX_FACE_POS_X] = {0, 0},
61
   [PIPE_TEX_FACE_POS_Y] = {1, 0},
62
   [PIPE_TEX_FACE_POS_Z] = {1, 1},
63
   [PIPE_TEX_FACE_NEG_X] = {0, 2},
64
   [PIPE_TEX_FACE_NEG_Y] = {1, 2},
65
   [PIPE_TEX_FACE_NEG_Z] = {1, 3},
66
};
67
 
68
/**
69
 * Step offsets for Cube map.
70
 */
71
static const int step_offsets[6][2] = {
72
   [PIPE_TEX_FACE_POS_X] = { 0, 2},
73
   [PIPE_TEX_FACE_POS_Y] = {-1, 2},
74
   [PIPE_TEX_FACE_POS_Z] = {-1, 1},
75
   [PIPE_TEX_FACE_NEG_X] = { 0, 2},
76
   [PIPE_TEX_FACE_NEG_Y] = {-1, 2},
77
   [PIPE_TEX_FACE_NEG_Z] = {-1, 1},
78
};
79
 
80
/**
81
 * For compressed level 2
82
 */
83
static const int bottom_offsets[6] = {
84
   [PIPE_TEX_FACE_POS_X] = 16 + 0 * 8,
85
   [PIPE_TEX_FACE_POS_Y] = 16 + 1 * 8,
86
   [PIPE_TEX_FACE_POS_Z] = 16 + 2 * 8,
87
   [PIPE_TEX_FACE_NEG_X] = 16 + 3 * 8,
88
   [PIPE_TEX_FACE_NEG_Y] = 16 + 4 * 8,
89
   [PIPE_TEX_FACE_NEG_Z] = 16 + 5 * 8,
90
};
91
 
92
static INLINE unsigned
93
align_nblocksx(enum pipe_format format, unsigned width, unsigned align_to)
94
{
95
   return align(util_format_get_nblocksx(format, width), align_to);
96
}
97
 
98
static INLINE unsigned
99
align_nblocksy(enum pipe_format format, unsigned width, unsigned align_to)
100
{
101
   return align(util_format_get_nblocksy(format, width), align_to);
102
}
103
 
104
static INLINE unsigned
105
get_pot_stride(enum pipe_format format, unsigned width)
106
{
107
   return util_next_power_of_two(util_format_get_stride(format, width));
108
}
109
 
110
static INLINE const char*
111
get_tiling_string(enum i915_winsys_buffer_tile tile)
112
{
113
   switch(tile) {
114
   case I915_TILE_NONE:
115
      return "none";
116
   case I915_TILE_X:
117
      return "x";
118
   case I915_TILE_Y:
119
      return "y";
120
   default:
121
      assert(FALSE);
122
      return "?";
123
   }
124
}
125
 
126
 
127
/*
128
 * More advanced helper funcs
129
 */
130
 
131
 
132
static void
133
i915_texture_set_level_info(struct i915_texture *tex,
134
                            unsigned level, unsigned nr_images)
135
{
136
   assert(level < Elements(tex->nr_images));
137
   assert(nr_images);
138
   assert(!tex->image_offset[level]);
139
 
140
   tex->nr_images[level] = nr_images;
141
   tex->image_offset[level] = MALLOC(nr_images * sizeof(struct offset_pair));
142
   tex->image_offset[level][0].nblocksx = 0;
143
   tex->image_offset[level][0].nblocksy = 0;
144
}
145
 
146
unsigned i915_texture_offset(const struct i915_texture *tex,
147
                                    unsigned level, unsigned layer)
148
{
149
   unsigned x, y;
150
   x = tex->image_offset[level][layer].nblocksx
151
      * util_format_get_blocksize(tex->b.b.format);
152
   y = tex->image_offset[level][layer].nblocksy;
153
 
154
   return y * tex->stride + x;
155
}
156
 
157
static void
158
i915_texture_set_image_offset(struct i915_texture *tex,
159
                              unsigned level, unsigned img,
160
                              unsigned nblocksx, unsigned nblocksy)
161
{
162
   /* for the first image and level make sure offset is zero */
163
   assert(!(img == 0 && level == 0) || (nblocksx == 0 && nblocksy == 0));
164
   assert(img < tex->nr_images[level]);
165
 
166
   tex->image_offset[level][img].nblocksx = nblocksx;
167
   tex->image_offset[level][img].nblocksy = nblocksy;
168
 
169
#if DEBUG_TEXTURES
170
   debug_printf("%s: %p level %u, img %u (%u, %u)\n", __FUNCTION__,
171
                tex, level, img, x, y);
172
#endif
173
}
174
 
175
static enum i915_winsys_buffer_tile
176
i915_texture_tiling(struct i915_screen *is, struct i915_texture *tex)
177
{
178
   if (!is->debug.tiling)
179
      return I915_TILE_NONE;
180
 
181
   if (tex->b.b.target == PIPE_TEXTURE_1D)
182
      return I915_TILE_NONE;
183
 
184
   if (util_format_is_s3tc(tex->b.b.format))
185
      return I915_TILE_X;
186
 
187
   if (is->debug.use_blitter)
188
      return I915_TILE_X;
189
   else
190
      return I915_TILE_Y;
191
}
192
 
193
 
194
/*
195
 * Shared layout functions
196
 */
197
 
198
 
199
/**
200
 * Special case to deal with scanout textures.
201
 */
202
static boolean
203
i9x5_scanout_layout(struct i915_texture *tex)
204
{
205
   struct pipe_resource *pt = &tex->b.b;
206
 
207
   if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4)
208
      return FALSE;
209
 
210
   i915_texture_set_level_info(tex, 0, 1);
211
   i915_texture_set_image_offset(tex, 0, 0, 0, 0);
212
 
213
   if (pt->width0 >= 240) {
214
      tex->stride = align(util_format_get_stride(pt->format, pt->width0), 64);
215
      tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8);
216
      tex->tiling = I915_TILE_X;
217
   /* special case for cursors */
218
   } else if (pt->width0 == 64 && pt->height0 == 64) {
219
      tex->stride = get_pot_stride(pt->format, pt->width0);
220
      tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8);
221
   } else {
222
      return FALSE;
223
   }
224
 
225
#if DEBUG_TEXTURE
226
   debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
227
      pt->width0, pt->height0, util_format_get_blocksize(pt->format),
228
      tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);
229
#endif
230
 
231
   return TRUE;
232
}
233
 
234
/**
235
 * Special case to deal with shared textures.
236
 */
237
static boolean
238
i9x5_display_target_layout(struct i915_texture *tex)
239
{
240
   struct pipe_resource *pt = &tex->b.b;
241
 
242
   if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4)
243
      return FALSE;
244
 
245
   /* fallback to normal textures for small textures */
246
   if (pt->width0 < 240)
247
      return FALSE;
248
 
249
   i915_texture_set_level_info(tex, 0, 1);
250
   i915_texture_set_image_offset(tex, 0, 0, 0, 0);
251
 
252
   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 64);
253
   tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8);
254
   tex->tiling = I915_TILE_X;
255
 
256
#if DEBUG_TEXTURE
257
   debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
258
      pt->width0, pt->height0, util_format_get_blocksize(pt->format),
259
      tex->stride, tex->total_nblocksy, tex->stride * tex->total_nblocksy);
260
#endif
261
 
262
   return TRUE;
263
}
264
 
265
/**
266
 * Helper function for special layouts
267
 */
268
static boolean
269
i9x5_special_layout(struct i915_texture *tex)
270
{
271
   struct pipe_resource *pt = &tex->b.b;
272
 
273
   /* Scanouts needs special care */
274
   if (pt->bind & PIPE_BIND_SCANOUT)
275
      if (i9x5_scanout_layout(tex))
276
         return TRUE;
277
 
278
   /* Shared buffers needs to be compatible with X servers
279
    *
280
    * XXX: need a better name than shared for this if it is to be part
281
    * of core gallium, and probably move the flag to resource.flags,
282
    * rather than bindings.
283
    */
284
   if (pt->bind & (PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET))
285
      if (i9x5_display_target_layout(tex))
286
         return TRUE;
287
 
288
   return FALSE;
289
}
290
 
291
/**
292
 * Cube layout used on i915 and for non-compressed textures on i945.
293
 */
294
static void
295
i9x5_texture_layout_cube(struct i915_texture *tex)
296
{
297
   struct pipe_resource *pt = &tex->b.b;
298
   unsigned width = util_next_power_of_two(pt->width0);
299
   const unsigned nblocks = util_format_get_nblocksx(pt->format, width);
300
   unsigned level;
301
   unsigned face;
302
 
303
   assert(pt->width0 == pt->height0); /* cubemap images are square */
304
 
305
   /* double pitch for cube layouts */
306
   tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4);
307
   tex->total_nblocksy = nblocks * 4;
308
 
309
   for (level = 0; level <= pt->last_level; level++)
310
      i915_texture_set_level_info(tex, level, 6);
311
 
312
   for (face = 0; face < 6; face++) {
313
      unsigned x = initial_offsets[face][0] * nblocks;
314
      unsigned y = initial_offsets[face][1] * nblocks;
315
      unsigned d = nblocks;
316
 
317
      for (level = 0; level <= pt->last_level; level++) {
318
         i915_texture_set_image_offset(tex, level, face, x, y);
319
         d >>= 1;
320
         x += step_offsets[face][0] * d;
321
         y += step_offsets[face][1] * d;
322
      }
323
   }
324
}
325
 
326
 
327
/*
328
 * i915 layout functions
329
 */
330
 
331
 
332
static void
333
i915_texture_layout_2d(struct i915_texture *tex)
334
{
335
   struct pipe_resource *pt = &tex->b.b;
336
   unsigned level;
337
   unsigned width = util_next_power_of_two(pt->width0);
338
   unsigned height = util_next_power_of_two(pt->height0);
339
   unsigned nblocksy = util_format_get_nblocksy(pt->format, width);
340
   unsigned align_y = 2;
341
 
342
   if (util_format_is_s3tc(pt->format))
343
      align_y = 1;
344
 
345
   tex->stride = align(util_format_get_stride(pt->format, width), 4);
346
   tex->total_nblocksy = 0;
347
 
348
   for (level = 0; level <= pt->last_level; level++) {
349
      i915_texture_set_level_info(tex, level, 1);
350
      i915_texture_set_image_offset(tex, level, 0, 0, tex->total_nblocksy);
351
 
352
      tex->total_nblocksy += nblocksy;
353
 
354
      width = u_minify(width, 1);
355
      height = u_minify(height, 1);
356
      nblocksy = align_nblocksy(pt->format, height, align_y);
357
   }
358
}
359
 
360
static void
361
i915_texture_layout_3d(struct i915_texture *tex)
362
{
363
   struct pipe_resource *pt = &tex->b.b;
364
   unsigned level;
365
 
366
   unsigned width = util_next_power_of_two(pt->width0);
367
   unsigned height = util_next_power_of_two(pt->height0);
368
   unsigned depth = util_next_power_of_two(pt->depth0);
369
   unsigned nblocksy = util_format_get_nblocksy(pt->format, height);
370
   unsigned stack_nblocksy = 0;
371
 
372
   /* Calculate the size of a single slice.
373
    */
374
   tex->stride = align(util_format_get_stride(pt->format, width), 4);
375
 
376
   /* XXX: hardware expects/requires 9 levels at minimum.
377
    */
378
   for (level = 0; level <= MAX2(8, pt->last_level); level++) {
379
      i915_texture_set_level_info(tex, level, depth);
380
 
381
      stack_nblocksy += MAX2(2, nblocksy);
382
 
383
      width = u_minify(width, 1);
384
      height = u_minify(height, 1);
385
      nblocksy = util_format_get_nblocksy(pt->format, height);
386
   }
387
 
388
   /* Fixup depth image_offsets:
389
    */
390
   for (level = 0; level <= pt->last_level; level++) {
391
      unsigned i;
392
      for (i = 0; i < depth; i++)
393
         i915_texture_set_image_offset(tex, level, i, 0, i * stack_nblocksy);
394
 
395
      depth = u_minify(depth, 1);
396
   }
397
 
398
   /* Multiply slice size by texture depth for total size.  It's
399
    * remarkable how wasteful of memory the i915 texture layouts
400
    * are.  They are largely fixed in the i945.
401
    */
402
   tex->total_nblocksy = stack_nblocksy * util_next_power_of_two(pt->depth0);
403
}
404
 
405
static boolean
406
i915_texture_layout(struct i915_texture * tex)
407
{
408
   switch (tex->b.b.target) {
409
   case PIPE_TEXTURE_1D:
410
   case PIPE_TEXTURE_2D:
411
   case PIPE_TEXTURE_RECT:
412
      if (!i9x5_special_layout(tex))
413
         i915_texture_layout_2d(tex);
414
      break;
415
   case PIPE_TEXTURE_3D:
416
      i915_texture_layout_3d(tex);
417
      break;
418
   case PIPE_TEXTURE_CUBE:
419
      i9x5_texture_layout_cube(tex);
420
      break;
421
   default:
422
      assert(0);
423
      return FALSE;
424
   }
425
 
426
   return TRUE;
427
}
428
 
429
 
430
/*
431
 * i945 layout functions
432
 */
433
 
434
 
435
static void
436
i945_texture_layout_2d(struct i915_texture *tex)
437
{
438
   struct pipe_resource *pt = &tex->b.b;
439
   int align_x = 4, align_y = 2;
440
   unsigned level;
441
   unsigned x = 0;
442
   unsigned y = 0;
443
   unsigned width = util_next_power_of_two(pt->width0);
444
   unsigned height = util_next_power_of_two(pt->height0);
445
   unsigned nblocksx = util_format_get_nblocksx(pt->format, width);
446
   unsigned nblocksy = util_format_get_nblocksy(pt->format, height);
447
 
448
   if (util_format_is_s3tc(pt->format)) {
449
      align_x = 1;
450
      align_y = 1;
451
   }
452
 
453
   tex->stride = align(util_format_get_stride(pt->format, width), 4);
454
 
455
   /* May need to adjust pitch to accommodate the placement of
456
    * the 2nd mipmap level.  This occurs when the alignment
457
    * constraints of mipmap placement push the right edge of the
458
    * 2nd mipmap level out past the width of its parent.
459
    */
460
   if (pt->last_level > 0) {
461
      unsigned mip1_nblocksx =
462
         align_nblocksx(pt->format, u_minify(width, 1), align_x) +
463
         util_format_get_nblocksx(pt->format, u_minify(width, 2));
464
 
465
      if (mip1_nblocksx > nblocksx)
466
         tex->stride = mip1_nblocksx * util_format_get_blocksize(pt->format);
467
   }
468
 
469
   /* Pitch must be a whole number of dwords
470
    */
471
   tex->stride = align(tex->stride, 64);
472
   tex->total_nblocksy = 0;
473
 
474
   for (level = 0; level <= pt->last_level; level++) {
475
      i915_texture_set_level_info(tex, level, 1);
476
      i915_texture_set_image_offset(tex, level, 0, x, y);
477
 
478
      /* Because the images are packed better, the final offset
479
       * might not be the maximal one:
480
       */
481
      tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
482
 
483
      /* Layout_below: step right after second mipmap level.
484
       */
485
      if (level == 1) {
486
         x += nblocksx;
487
      } else {
488
         y += nblocksy;
489
      }
490
 
491
      width  = u_minify(width, 1);
492
      height = u_minify(height, 1);
493
      nblocksx = align_nblocksx(pt->format, width, align_x);
494
      nblocksy = align_nblocksy(pt->format, height, align_y);
495
   }
496
}
497
 
498
static void
499
i945_texture_layout_3d(struct i915_texture *tex)
500
{
501
   struct pipe_resource *pt = &tex->b.b;
502
   unsigned width = util_next_power_of_two(pt->width0);
503
   unsigned height = util_next_power_of_two(pt->height0);
504
   unsigned depth = util_next_power_of_two(pt->depth0);
505
   unsigned nblocksy = util_format_get_nblocksy(pt->format, width);
506
   unsigned pack_x_pitch, pack_x_nr;
507
   unsigned pack_y_pitch;
508
   unsigned level;
509
 
510
   tex->stride = align(util_format_get_stride(pt->format, width), 4);
511
   tex->total_nblocksy = 0;
512
 
513
   pack_y_pitch = MAX2(nblocksy, 2);
514
   pack_x_pitch = tex->stride / util_format_get_blocksize(pt->format);
515
   pack_x_nr = 1;
516
 
517
   for (level = 0; level <= pt->last_level; level++) {
518
      int x = 0;
519
      int y = 0;
520
      unsigned q, j;
521
 
522
      i915_texture_set_level_info(tex, level, depth);
523
 
524
      for (q = 0; q < depth;) {
525
         for (j = 0; j < pack_x_nr && q < depth; j++, q++) {
526
            i915_texture_set_image_offset(tex, level, q, x, y + tex->total_nblocksy);
527
            x += pack_x_pitch;
528
         }
529
 
530
         x = 0;
531
         y += pack_y_pitch;
532
      }
533
 
534
      tex->total_nblocksy += y;
535
 
536
      if (pack_x_pitch > 4) {
537
         pack_x_pitch >>= 1;
538
         pack_x_nr <<= 1;
539
         assert(pack_x_pitch * pack_x_nr * util_format_get_blocksize(pt->format) <= tex->stride);
540
      }
541
 
542
      if (pack_y_pitch > 2) {
543
         pack_y_pitch >>= 1;
544
      }
545
 
546
      width = u_minify(width, 1);
547
      height = u_minify(height, 1);
548
      depth = u_minify(depth, 1);
549
      nblocksy = util_format_get_nblocksy(pt->format, height);
550
   }
551
}
552
 
553
static void
554
i945_texture_layout_cube(struct i915_texture *tex)
555
{
556
   struct pipe_resource *pt = &tex->b.b;
557
   unsigned width = util_next_power_of_two(pt->width0);
558
   const unsigned nblocks = util_format_get_nblocksx(pt->format, width);
559
   const unsigned dim = width;
560
   unsigned level;
561
   unsigned face;
562
 
563
   assert(pt->width0 == pt->height0); /* cubemap images are square */
564
   assert(util_format_is_s3tc(pt->format)); /* compressed only */
565
 
566
   /*
567
    * Depending on the size of the largest images, pitch can be
568
    * determined either by the old-style packing of cubemap faces,
569
    * or the final row of 4x4, 2x2 and 1x1 faces below this.
570
    *
571
    * 64  * 2 / 4 = 32
572
    * 14 * 2 = 28
573
    */
574
   if (width >= 64)
575
      tex->stride = nblocks * 2 * util_format_get_blocksize(pt->format);
576
   else
577
      tex->stride = 14 * 2 * util_format_get_blocksize(pt->format);
578
 
579
   /*
580
    * Something similary apply for height as well.
581
    */
582
   if (width >= 4)
583
      tex->total_nblocksy = nblocks * 4 + 1;
584
   else
585
      tex->total_nblocksy = 1;
586
 
587
   /* Set all the levels to effectively occupy the whole rectangular region */
588
   for (level = 0; level <= pt->last_level; level++)
589
      i915_texture_set_level_info(tex, level, 6);
590
 
591
   for (face = 0; face < 6; face++) {
592
      /* all calculations in pixels */
593
      unsigned total_height = tex->total_nblocksy * 4;
594
      unsigned x = initial_offsets[face][0] * dim;
595
      unsigned y = initial_offsets[face][1] * dim;
596
      unsigned d = dim;
597
 
598
      if (dim == 4 && face >= 4) {
599
         x = (face - 4) * 8;
600
         y = tex->total_nblocksy * 4 - 4; /* 4 = 1 block */
601
      } else if (dim < 4 && (face > 0)) {
602
         x = face * 8;
603
         y = total_height - 4;
604
      }
605
 
606
      for (level = 0; level <= pt->last_level; level++) {
607
         i915_texture_set_image_offset(tex, level, face,
608
                                       util_format_get_nblocksx(pt->format, x),
609
                                       util_format_get_nblocksy(pt->format, y));
610
 
611
         d >>= 1;
612
 
613
         switch (d) {
614
         case 4:
615
            switch (face) {
616
            case PIPE_TEX_FACE_POS_X:
617
            case PIPE_TEX_FACE_NEG_X:
618
               x += step_offsets[face][0] * d;
619
               y += step_offsets[face][1] * d;
620
               break;
621
            case PIPE_TEX_FACE_POS_Y:
622
            case PIPE_TEX_FACE_NEG_Y:
623
               y += 12;
624
               x -= 8;
625
               break;
626
            case PIPE_TEX_FACE_POS_Z:
627
            case PIPE_TEX_FACE_NEG_Z:
628
               y = total_height - 4;
629
               x = (face - 4) * 8;
630
               break;
631
            }
632
            break;
633
         case 2:
634
            y = total_height - 4;
635
            x = bottom_offsets[face];
636
            break;
637
         case 1:
638
            x += 48;
639
            break;
640
         default:
641
            x += step_offsets[face][0] * d;
642
            y += step_offsets[face][1] * d;
643
            break;
644
         }
645
      }
646
   }
647
}
648
 
649
static boolean
650
i945_texture_layout(struct i915_texture * tex)
651
{
652
   switch (tex->b.b.target) {
653
   case PIPE_TEXTURE_1D:
654
   case PIPE_TEXTURE_2D:
655
   case PIPE_TEXTURE_RECT:
656
      if (!i9x5_special_layout(tex))
657
         i945_texture_layout_2d(tex);
658
      break;
659
   case PIPE_TEXTURE_3D:
660
      i945_texture_layout_3d(tex);
661
      break;
662
   case PIPE_TEXTURE_CUBE:
663
      if (!util_format_is_s3tc(tex->b.b.format))
664
         i9x5_texture_layout_cube(tex);
665
      else
666
         i945_texture_layout_cube(tex);
667
      break;
668
   default:
669
      assert(0);
670
      return FALSE;
671
   }
672
 
673
   return TRUE;
674
}
675
 
676
 
677
 
678
/*
679
 * Screen texture functions
680
 */
681
 
682
 
683
 
684
static boolean
685
i915_texture_get_handle(struct pipe_screen * screen,
686
                        struct pipe_resource *texture,
687
                        struct winsys_handle *whandle)
688
{
689
   struct i915_screen *is = i915_screen(screen);
690
   struct i915_texture *tex = i915_texture(texture);
691
   struct i915_winsys *iws = is->iws;
692
 
693
   return iws->buffer_get_handle(iws, tex->buffer, whandle, tex->stride);
694
}
695
 
696
 
697
static void
698
i915_texture_destroy(struct pipe_screen *screen,
699
                     struct pipe_resource *pt)
700
{
701
   struct i915_texture *tex = i915_texture(pt);
702
   struct i915_winsys *iws = i915_screen(screen)->iws;
703
   uint i;
704
 
705
   if (tex->buffer)
706
      iws->buffer_destroy(iws, tex->buffer);
707
 
708
   for (i = 0; i < Elements(tex->image_offset); i++)
709
      FREE(tex->image_offset[i]);
710
 
711
   FREE(tex);
712
}
713
 
714
static void *
715
i915_texture_transfer_map(struct pipe_context *pipe,
716
                          struct pipe_resource *resource,
717
                          unsigned level,
718
                          unsigned usage,
719
                          const struct pipe_box *box,
720
                          struct pipe_transfer **ptransfer)
721
{
722
   struct i915_context *i915 = i915_context(pipe);
723
   struct i915_texture *tex = i915_texture(resource);
724
   struct i915_transfer *transfer = util_slab_alloc(&i915->texture_transfer_pool);
725
   boolean use_staging_texture = FALSE;
726
   struct i915_winsys *iws = i915_screen(pipe->screen)->iws;
727
   enum pipe_format format = resource->format;
728
   unsigned offset;
729
   char *map;
730
 
731
   if (transfer == NULL)
732
      return NULL;
733
 
734
   transfer->b.resource = resource;
735
   transfer->b.level = level;
736
   transfer->b.usage = usage;
737
   transfer->b.box = *box;
738
   transfer->b.stride = tex->stride;
739
   transfer->staging_texture = NULL;
740
   /* XXX: handle depth textures everyhwere*/
741
   transfer->b.layer_stride = 0;
742
 
743
   /* if we use staging transfers, only support textures we can render to,
744
    * because we need that for u_blitter */
745
   if (i915->blitter &&
746
       util_blitter_is_copy_supported(i915->blitter, resource, resource) &&
747
       (usage & PIPE_TRANSFER_WRITE) &&
748
       !(usage & (PIPE_TRANSFER_READ | PIPE_TRANSFER_DONTBLOCK | PIPE_TRANSFER_UNSYNCHRONIZED)))
749
      use_staging_texture = TRUE;
750
 
751
   use_staging_texture = FALSE;
752
 
753
   if (use_staging_texture) {
754
      /*
755
       * Allocate the untiled staging texture.
756
       * If the alloc fails, transfer->staging_texture is NULL and we fallback to a map()
757
       */
758
      transfer->staging_texture = i915_texture_create(pipe->screen, resource, TRUE);
759
   }
760
 
761
   if (resource->target != PIPE_TEXTURE_3D &&
762
       resource->target != PIPE_TEXTURE_CUBE)
763
      assert(box->z == 0);
764
 
765
   if (transfer->staging_texture) {
766
      tex = i915_texture(transfer->staging_texture);
767
   } else {
768
      /* TODO this is a sledgehammer */
769
      tex = i915_texture(resource);
770
      pipe->flush(pipe, NULL, 0);
771
   }
772
 
773
   offset = i915_texture_offset(tex, transfer->b.level, box->z);
774
 
775
   map = iws->buffer_map(iws, tex->buffer,
776
                         (transfer->b.usage & PIPE_TRANSFER_WRITE) ? TRUE : FALSE);
777
   if (map == NULL) {
778
      pipe_resource_reference(&transfer->staging_texture, NULL);
779
      FREE(transfer);
780
      return NULL;
781
   }
782
 
783
   *ptransfer = &transfer->b;
784
 
785
   return map + offset +
786
      box->y / util_format_get_blockheight(format) * transfer->b.stride +
787
      box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
788
}
789
 
790
static void
791
i915_texture_transfer_unmap(struct pipe_context *pipe,
792
			    struct pipe_transfer *transfer)
793
{
794
   struct i915_context *i915 = i915_context(pipe);
795
   struct i915_transfer *itransfer = (struct i915_transfer*)transfer;
796
   struct i915_texture *tex = i915_texture(itransfer->b.resource);
797
   struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws;
798
 
799
   if (itransfer->staging_texture)
800
      tex = i915_texture(itransfer->staging_texture);
801
 
802
   iws->buffer_unmap(iws, tex->buffer);
803
 
804
   if ((itransfer->staging_texture) &&
805
       (transfer->usage & PIPE_TRANSFER_WRITE)) {
806
      struct pipe_box sbox;
807
 
808
      u_box_origin_2d(itransfer->b.box.width, itransfer->b.box.height, &sbox);
809
      pipe->resource_copy_region(pipe, itransfer->b.resource, itransfer->b.level,
810
                                   itransfer->b.box.x, itransfer->b.box.y, itransfer->b.box.z,
811
                                   itransfer->staging_texture,
812
                                   0, &sbox);
813
      pipe->flush(pipe, NULL, 0);
814
      pipe_resource_reference(&itransfer->staging_texture, NULL);
815
   }
816
 
817
   util_slab_free(&i915->texture_transfer_pool, itransfer);
818
}
819
 
820
#if 0
821
static void i915_transfer_inline_write( struct pipe_context *pipe,
822
                                 struct pipe_resource *resource,
823
                                 unsigned level,
824
                                 unsigned usage,
825
                                 const struct pipe_box *box,
826
                                 const void *data,
827
                                 unsigned stride,
828
                                 unsigned layer_stride)
829
{
830
   struct pipe_transfer *transfer = NULL;
831
   struct i915_transfer *itransfer = NULL;
832
   const uint8_t *src_data = data;
833
   unsigned i;
834
 
835
   transfer = pipe->transfer_get(pipe,
836
                                 resource,
837
                                 level,
838
                                 usage,
839
                                 box );
840
   if (transfer == NULL)
841
      goto out;
842
 
843
   itransfer = (struct i915_transfer*)transfer;
844
 
845
   if (itransfer->staging_texture) {
846
      struct i915_texture *tex = i915_texture(itransfer->staging_texture);
847
      enum pipe_format format = tex->b.b.format;
848
      struct i915_winsys *iws = i915_screen(tex->b.b.screen)->iws;
849
      size_t offset;
850
      size_t size;
851
 
852
      offset = i915_texture_offset(tex, transfer->level, transfer->box.z);
853
 
854
      for (i = 0; i < box->depth; i++) {
855
         if (!tex->b.b.last_level &&
856
                     tex->b.b.width0 == transfer->box.width) {
857
             unsigned nby = util_format_get_nblocksy(format, transfer->box.y);
858
             assert(!offset);
859
             assert(!transfer->box.x);
860
             assert(tex->stride == transfer->stride);
861
 
862
             offset += tex->stride * nby;
863
             size = util_format_get_2d_size(format, transfer->stride,
864
                             transfer->box.height);
865
             iws->buffer_write(iws, tex->buffer, offset, size, transfer->data);
866
 
867
         } else {
868
             unsigned nby = util_format_get_nblocksy(format, transfer->box.y);
869
             int i;
870
             offset += util_format_get_stride(format, transfer->box.x);
871
             size = transfer->stride;
872
 
873
             for (i = 0; i < nby; i++) {
874
                     iws->buffer_write(iws, tex->buffer, offset, size, transfer->data);
875
                     offset += tex->stride;
876
             }
877
         }
878
         offset += layer_stride;
879
      }
880
   } else {
881
      uint8_t *map = pipe_transfer_map(pipe, &itransfer->b);
882
      if (map == NULL)
883
         goto nomap;
884
 
885
      for (i = 0; i < box->depth; i++) {
886
         util_copy_rect(map,
887
                        resource->format,
888
                        itransfer->b.stride, /* bytes */
889
                        0, 0,
890
                        box->width,
891
                        box->height,
892
                        src_data,
893
                        stride,       /* bytes */
894
                        0, 0);
895
         map += itransfer->b.layer_stride;
896
         src_data += layer_stride;
897
      }
898
nomap:
899
      if (map)
900
         pipe_transfer_unmap(pipe, &itransfer->b);
901
   }
902
 
903
out:
904
   if (itransfer)
905
      pipe_transfer_destroy(pipe, &itransfer->b);
906
}
907
#endif
908
 
909
struct u_resource_vtbl i915_texture_vtbl =
910
{
911
   i915_texture_get_handle,	      /* get_handle */
912
   i915_texture_destroy,	      /* resource_destroy */
913
   i915_texture_transfer_map,	      /* transfer_map */
914
   u_default_transfer_flush_region,   /* transfer_flush_region */
915
   i915_texture_transfer_unmap,	      /* transfer_unmap */
916
   u_default_transfer_inline_write    /* transfer_inline_write */
917
};
918
 
919
 
920
struct pipe_resource *
921
i915_texture_create(struct pipe_screen *screen,
922
                    const struct pipe_resource *template,
923
                    boolean force_untiled)
924
{
925
   struct i915_screen *is = i915_screen(screen);
926
   struct i915_winsys *iws = is->iws;
927
   struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
928
   unsigned buf_usage = 0;
929
 
930
   if (!tex)
931
      return NULL;
932
 
933
   tex->b.b = *template;
934
   tex->b.vtbl = &i915_texture_vtbl;
935
   pipe_reference_init(&tex->b.b.reference, 1);
936
   tex->b.b.screen = screen;
937
 
938
   if ( (force_untiled) || (template->usage == PIPE_USAGE_STREAM) )
939
      tex->tiling = I915_TILE_NONE;
940
   else
941
      tex->tiling = i915_texture_tiling(is, tex);
942
 
943
   if (is->is_i945) {
944
      if (!i945_texture_layout(tex))
945
         goto fail;
946
   } else {
947
      if (!i915_texture_layout(tex))
948
         goto fail;
949
   }
950
 
951
   /* for scanouts and cursors, cursors arn't scanouts */
952
 
953
   /* XXX: use a custom flag for cursors, don't rely on magically
954
    * guessing that this is Xorg asking for a cursor
955
    */
956
   if ((template->bind & PIPE_BIND_SCANOUT) && template->width0 != 64)
957
      buf_usage = I915_NEW_SCANOUT;
958
   else
959
      buf_usage = I915_NEW_TEXTURE;
960
 
961
   tex->buffer = iws->buffer_create_tiled(iws, &tex->stride, tex->total_nblocksy,
962
                                             &tex->tiling, buf_usage);
963
   if (!tex->buffer)
964
      goto fail;
965
 
966
   I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__,
967
            tex, tex->stride,
968
            tex->stride / util_format_get_blocksize(tex->b.b.format),
969
            tex->total_nblocksy, get_tiling_string(tex->tiling));
970
 
971
   return &tex->b.b;
972
 
973
fail:
974
   FREE(tex);
975
   return NULL;
976
}
977
 
978
struct pipe_resource *
979
i915_texture_from_handle(struct pipe_screen * screen,
980
			  const struct pipe_resource *template,
981
			  struct winsys_handle *whandle)
982
{
983
   struct i915_screen *is = i915_screen(screen);
984
   struct i915_texture *tex;
985
   struct i915_winsys *iws = is->iws;
986
   struct i915_winsys_buffer *buffer;
987
   unsigned stride;
988
   enum i915_winsys_buffer_tile tiling;
989
 
990
   assert(screen);
991
 
992
   buffer = iws->buffer_from_handle(iws, whandle, template->height0, &tiling, &stride);
993
 
994
   /* Only supports one type */
995
   if ((template->target != PIPE_TEXTURE_2D &&
996
       template->target != PIPE_TEXTURE_RECT) ||
997
       template->last_level != 0 ||
998
       template->depth0 != 1) {
999
      return NULL;
1000
   }
1001
 
1002
   tex = CALLOC_STRUCT(i915_texture);
1003
   if (!tex)
1004
      return NULL;
1005
 
1006
   tex->b.b = *template;
1007
   tex->b.vtbl = &i915_texture_vtbl;
1008
   pipe_reference_init(&tex->b.b.reference, 1);
1009
   tex->b.b.screen = screen;
1010
 
1011
   tex->stride = stride;
1012
   tex->tiling = tiling;
1013
   tex->total_nblocksy = align_nblocksy(tex->b.b.format, tex->b.b.height0, 8);
1014
 
1015
   i915_texture_set_level_info(tex, 0, 1);
1016
   i915_texture_set_image_offset(tex, 0, 0, 0, 0);
1017
 
1018
   tex->buffer = buffer;
1019
 
1020
   I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n", __func__,
1021
            tex, tex->stride,
1022
            tex->stride / util_format_get_blocksize(tex->b.b.format),
1023
            tex->total_nblocksy, get_tiling_string(tex->tiling));
1024
 
1025
   return &tex->b.b;
1026
}
1027