~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/gallium/drivers/i915/i915_resource_texture.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

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