Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 1
/*
2
 * Copyright 2006 VMware, Inc.
3
 * Copyright © 2006 Intel Corporation
4
 *
5
 * Permission is hereby granted, free of charge, to any person obtaining
6
 * a copy of this software and associated documentation files (the
7
 * "Software"), to deal in the Software without restriction, including
8
 * without limitation the rights to use, copy, modify, merge, publish,
9
 * distribute, sublicense, and/or sell copies of the Software, and to
10
 * permit persons to whom the Software is furnished to do so, subject to
11
 * the following conditions:
12
 *
13
 * The above copyright notice and this permission notice (including the
14
 * next paragraph) shall be included in all copies or substantial
15
 * portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20
 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
 
26
/**
27
 * \file brw_tex_layout.cpp
28
 *
29
 * Code to lay out images in a mipmap tree.
30
 *
31
 * \author Keith Whitwell 
32
 * \author Michel Dänzer 
33
 */
34
 
35
#include "intel_mipmap_tree.h"
36
#include "brw_context.h"
37
#include "main/macros.h"
38
#include "main/glformats.h"
39
 
40
#define FILE_DEBUG_FLAG DEBUG_MIPTREE
41
 
42
static unsigned int
43
intel_horizontal_texture_alignment_unit(struct brw_context *brw,
44
                                        struct intel_mipmap_tree *mt)
45
{
46
   /**
47
    * From the "Alignment Unit Size" section of various specs, namely:
48
    * - Gen3 Spec: "Memory Data Formats" Volume,         Section 1.20.1.4
49
    * - i965 and G45 PRMs:             Volume 1,         Section 6.17.3.4.
50
    * - Ironlake and Sandybridge PRMs: Volume 1, Part 1, Section 7.18.3.4
51
    * - BSpec (for Ivybridge and slight variations in separate stencil)
52
    *
53
    * +----------------------------------------------------------------------+
54
    * |                                        | alignment unit width  ("i") |
55
    * | Surface Property                       |-----------------------------|
56
    * |                                        | 915 | 965 | ILK | SNB | IVB |
57
    * +----------------------------------------------------------------------+
58
    * | YUV 4:2:2 format                       |  8  |  4  |  4  |  4  |  4  |
59
    * | BC1-5 compressed format (DXTn/S3TC)    |  4  |  4  |  4  |  4  |  4  |
60
    * | FXT1  compressed format                |  8  |  8  |  8  |  8  |  8  |
61
    * | Depth Buffer (16-bit)                  |  4  |  4  |  4  |  4  |  8  |
62
    * | Depth Buffer (other)                   |  4  |  4  |  4  |  4  |  4  |
63
    * | Separate Stencil Buffer                | N/A | N/A |  8  |  8  |  8  |
64
    * | All Others                             |  4  |  4  |  4  |  4  |  4  |
65
    * +----------------------------------------------------------------------+
66
    *
67
    * On IVB+, non-special cases can be overridden by setting the SURFACE_STATE
68
    * "Surface Horizontal Alignment" field to HALIGN_4 or HALIGN_8.
69
    */
70
    if (_mesa_is_format_compressed(mt->format)) {
71
       /* The hardware alignment requirements for compressed textures
72
        * happen to match the block boundaries.
73
        */
74
      unsigned int i, j;
75
      _mesa_get_format_block_size(mt->format, &i, &j);
76
 
77
      /* On Gen9+ we can pick our own alignment for compressed textures but it
78
       * has to be a multiple of the block size. The minimum alignment we can
79
       * pick is 4 so we effectively have to align to 4 times the block
80
       * size
81
       */
82
      if (brw->gen >= 9)
83
         return i * 4;
84
      else
85
         return i;
86
    }
87
 
88
   if (mt->format == MESA_FORMAT_S_UINT8)
89
      return 8;
90
 
91
   if (brw->gen >= 7 && mt->format == MESA_FORMAT_Z_UNORM16)
92
      return 8;
93
 
94
   if (brw->gen == 8 && mt->mcs_mt && mt->num_samples <= 1)
95
      return 16;
96
 
97
   return 4;
98
}
99
 
100
static unsigned int
101
intel_vertical_texture_alignment_unit(struct brw_context *brw,
102
                                      mesa_format format, bool multisampled)
103
{
104
   /**
105
    * From the "Alignment Unit Size" section of various specs, namely:
106
    * - Gen3 Spec: "Memory Data Formats" Volume,         Section 1.20.1.4
107
    * - i965 and G45 PRMs:             Volume 1,         Section 6.17.3.4.
108
    * - Ironlake and Sandybridge PRMs: Volume 1, Part 1, Section 7.18.3.4
109
    * - BSpec (for Ivybridge and slight variations in separate stencil)
110
    *
111
    * +----------------------------------------------------------------------+
112
    * |                                        | alignment unit height ("j") |
113
    * | Surface Property                       |-----------------------------|
114
    * |                                        | 915 | 965 | ILK | SNB | IVB |
115
    * +----------------------------------------------------------------------+
116
    * | BC1-5 compressed format (DXTn/S3TC)    |  4  |  4  |  4  |  4  |  4  |
117
    * | FXT1  compressed format                |  4  |  4  |  4  |  4  |  4  |
118
    * | Depth Buffer                           |  2  |  2  |  2  |  4  |  4  |
119
    * | Separate Stencil Buffer                | N/A | N/A | N/A |  4  |  8  |
120
    * | Multisampled (4x or 8x) render target  | N/A | N/A | N/A |  4  |  4  |
121
    * | All Others                             |  2  |  2  |  2  |  *  |  *  |
122
    * +----------------------------------------------------------------------+
123
    *
124
    * Where "*" means either VALIGN_2 or VALIGN_4 depending on the setting of
125
    * the SURFACE_STATE "Surface Vertical Alignment" field.
126
    */
127
   if (_mesa_is_format_compressed(format))
128
      /* See comment above for the horizontal alignment */
129
      return brw->gen >= 9 ? 16 : 4;
130
 
131
   if (format == MESA_FORMAT_S_UINT8)
132
      return brw->gen >= 7 ? 8 : 4;
133
 
134
   /* Broadwell only supports VALIGN of 4, 8, and 16.  The BSpec says 4
135
    * should always be used, except for stencil buffers, which should be 8.
136
    */
137
   if (brw->gen >= 8)
138
      return 4;
139
 
140
   if (multisampled)
141
      return 4;
142
 
143
   GLenum base_format = _mesa_get_format_base_format(format);
144
 
145
   if (brw->gen >= 6 &&
146
       (base_format == GL_DEPTH_COMPONENT ||
147
	base_format == GL_DEPTH_STENCIL)) {
148
      return 4;
149
   }
150
 
151
   if (brw->gen == 7) {
152
      /* On Gen7, we prefer a vertical alignment of 4 when possible, because
153
       * that allows Y tiled render targets.
154
       *
155
       * From the Ivy Bridge PRM, Vol4 Part1 2.12.2.1 (SURFACE_STATE for most
156
       * messages), on p64, under the heading "Surface Vertical Alignment":
157
       *
158
       *     Value of 1 [VALIGN_4] is not supported for format YCRCB_NORMAL
159
       *     (0x182), YCRCB_SWAPUVY (0x183), YCRCB_SWAPUV (0x18f), YCRCB_SWAPY
160
       *     (0x190)
161
       *
162
       *     VALIGN_4 is not supported for surface format R32G32B32_FLOAT.
163
       */
164
      if (base_format == GL_YCBCR_MESA || format == MESA_FORMAT_RGB_FLOAT32)
165
         return 2;
166
 
167
      return 4;
168
   }
169
 
170
   return 2;
171
}
172
 
173
static void
174
gen9_miptree_layout_1d(struct intel_mipmap_tree *mt)
175
{
176
   unsigned x = 0;
177
   unsigned width = mt->physical_width0;
178
   unsigned depth = mt->physical_depth0; /* number of array layers. */
179
 
180
   /* When this layout is used the horizontal alignment is fixed at 64 and the
181
    * hardware ignores the value given in the surface state
182
    */
183
   const unsigned int align_w = 64;
184
 
185
   mt->total_height = mt->physical_height0;
186
   mt->total_width = 0;
187
 
188
   for (unsigned level = mt->first_level; level <= mt->last_level; level++) {
189
      unsigned img_width;
190
 
191
      intel_miptree_set_level_info(mt, level, x, 0, depth);
192
 
193
      img_width = ALIGN(width, align_w);
194
 
195
      mt->total_width = MAX2(mt->total_width, x + img_width);
196
 
197
      x += img_width;
198
 
199
      width = minify(width, 1);
200
   }
201
}
202
 
203
static void
204
brw_miptree_layout_2d(struct intel_mipmap_tree *mt)
205
{
206
   unsigned x = 0;
207
   unsigned y = 0;
208
   unsigned width = mt->physical_width0;
209
   unsigned height = mt->physical_height0;
210
   unsigned depth = mt->physical_depth0; /* number of array layers. */
211
   unsigned int bw, bh;
212
 
213
   _mesa_get_format_block_size(mt->format, &bw, &bh);
214
 
215
   mt->total_width = mt->physical_width0;
216
 
217
   if (mt->compressed) {
218
       mt->total_width = ALIGN(mt->physical_width0, mt->align_w);
219
   }
220
 
221
   /* May need to adjust width to accommodate the placement of
222
    * the 2nd mipmap.  This occurs when the alignment
223
    * constraints of mipmap placement push the right edge of the
224
    * 2nd mipmap out past the width of its parent.
225
    */
226
   if (mt->first_level != mt->last_level) {
227
       unsigned mip1_width;
228
 
229
       if (mt->compressed) {
230
          mip1_width = ALIGN(minify(mt->physical_width0, 1), mt->align_w) +
231
             ALIGN(minify(mt->physical_width0, 2), bw);
232
       } else {
233
          mip1_width = ALIGN(minify(mt->physical_width0, 1), mt->align_w) +
234
             minify(mt->physical_width0, 2);
235
       }
236
 
237
       if (mip1_width > mt->total_width) {
238
           mt->total_width = mip1_width;
239
       }
240
   }
241
 
242
   mt->total_height = 0;
243
 
244
   for (unsigned level = mt->first_level; level <= mt->last_level; level++) {
245
      unsigned img_height;
246
 
247
      intel_miptree_set_level_info(mt, level, x, y, depth);
248
 
249
      img_height = ALIGN(height, mt->align_h);
250
      if (mt->compressed)
251
	 img_height /= bh;
252
 
253
      if (mt->array_layout == ALL_SLICES_AT_EACH_LOD) {
254
         /* Compact arrays with separated miplevels */
255
         img_height *= depth;
256
      }
257
 
258
      /* Because the images are packed better, the final offset
259
       * might not be the maximal one:
260
       */
261
      mt->total_height = MAX2(mt->total_height, y + img_height);
262
 
263
      /* Layout_below: step right after second mipmap.
264
       */
265
      if (level == mt->first_level + 1) {
266
	 x += ALIGN(width, mt->align_w);
267
      } else {
268
	 y += img_height;
269
      }
270
 
271
      width  = minify(width, 1);
272
      height = minify(height, 1);
273
 
274
      if (mt->target == GL_TEXTURE_3D)
275
         depth = minify(depth, 1);
276
   }
277
}
278
 
279
unsigned
280
brw_miptree_get_horizontal_slice_pitch(const struct brw_context *brw,
281
                                       const struct intel_mipmap_tree *mt,
282
                                       unsigned level)
283
{
284
   assert(brw->gen < 9);
285
 
286
   if (mt->target == GL_TEXTURE_3D ||
287
       (brw->gen == 4 && mt->target == GL_TEXTURE_CUBE_MAP)) {
288
      return ALIGN(minify(mt->physical_width0, level), mt->align_w);
289
   } else {
290
      return 0;
291
   }
292
}
293
 
294
unsigned
295
brw_miptree_get_vertical_slice_pitch(const struct brw_context *brw,
296
                                     const struct intel_mipmap_tree *mt,
297
                                     unsigned level)
298
{
299
   if (brw->gen >= 9) {
300
      /* ALL_SLICES_AT_EACH_LOD isn't supported on Gen8+ but this code will
301
       * effectively end up with a packed qpitch anyway whenever
302
       * mt->first_level == mt->last_level.
303
       */
304
      assert(mt->array_layout != ALL_SLICES_AT_EACH_LOD);
305
 
306
      /* On Gen9 we can pick whatever qpitch we like as long as it's aligned
307
       * to the vertical alignment so we don't need to add any extra rows.
308
       */
309
      unsigned qpitch = mt->total_height;
310
 
311
      /* If the surface might be used as a stencil buffer or HiZ buffer then
312
       * it needs to be a multiple of 8.
313
       */
314
      const GLenum base_format = _mesa_get_format_base_format(mt->format);
315
      if (_mesa_is_depth_or_stencil_format(base_format))
316
         qpitch = ALIGN(qpitch, 8);
317
 
318
      /* 3D textures need to be aligned to the tile height. At this point we
319
       * don't know which tiling will be used so let's just align it to 32
320
       */
321
      if (mt->target == GL_TEXTURE_3D)
322
         qpitch = ALIGN(qpitch, 32);
323
 
324
      return qpitch;
325
 
326
   } else if (mt->target == GL_TEXTURE_3D ||
327
              (brw->gen == 4 && mt->target == GL_TEXTURE_CUBE_MAP) ||
328
              mt->array_layout == ALL_SLICES_AT_EACH_LOD) {
329
      return ALIGN(minify(mt->physical_height0, level), mt->align_h);
330
 
331
   } else {
332
      const unsigned h0 = ALIGN(mt->physical_height0, mt->align_h);
333
      const unsigned h1 = ALIGN(minify(mt->physical_height0, 1), mt->align_h);
334
 
335
      return h0 + h1 + (brw->gen >= 7 ? 12 : 11) * mt->align_h;
336
   }
337
}
338
 
339
static void
340
align_cube(struct intel_mipmap_tree *mt)
341
{
342
   /* The 965's sampler lays cachelines out according to how accesses
343
    * in the texture surfaces run, so they may be "vertical" through
344
    * memory.  As a result, the docs say in Surface Padding Requirements:
345
    * Sampling Engine Surfaces that two extra rows of padding are required.
346
    */
347
   if (mt->target == GL_TEXTURE_CUBE_MAP)
348
      mt->total_height += 2;
349
}
350
 
351
static bool
352
use_linear_1d_layout(struct brw_context *brw,
353
                     struct intel_mipmap_tree *mt)
354
{
355
   /* On Gen9+ the mipmap levels of a 1D surface are all laid out in a
356
    * horizontal line. This isn't done for depth/stencil buffers however
357
    * because those will be using a tiled layout
358
    */
359
   if (brw->gen >= 9 &&
360
       (mt->target == GL_TEXTURE_1D ||
361
        mt->target == GL_TEXTURE_1D_ARRAY)) {
362
      GLenum base_format = _mesa_get_format_base_format(mt->format);
363
 
364
      if (base_format != GL_DEPTH_COMPONENT &&
365
          base_format != GL_DEPTH_STENCIL &&
366
          base_format != GL_STENCIL_INDEX)
367
         return true;
368
   }
369
 
370
   return false;
371
}
372
 
373
static void
374
brw_miptree_layout_texture_array(struct brw_context *brw,
375
				 struct intel_mipmap_tree *mt)
376
{
377
   unsigned height = mt->physical_height0;
378
   bool layout_1d = use_linear_1d_layout(brw, mt);
379
   int physical_qpitch;
380
 
381
   if (layout_1d)
382
      gen9_miptree_layout_1d(mt);
383
   else
384
      brw_miptree_layout_2d(mt);
385
 
386
   if (layout_1d) {
387
      physical_qpitch = 1;
388
      /* When using the horizontal layout the qpitch specifies the distance in
389
       * pixels between array slices. The total_width is forced to be a
390
       * multiple of the horizontal alignment in brw_miptree_layout_1d (in
391
       * this case it's always 64). The vertical alignment is ignored.
392
       */
393
      mt->qpitch = mt->total_width;
394
   } else {
395
      mt->qpitch = brw_miptree_get_vertical_slice_pitch(brw, mt, 0);
396
      /* Unlike previous generations the qpitch is a multiple of the
397
       * compressed block size on Gen9 so physical_qpitch matches mt->qpitch.
398
       */
399
      physical_qpitch = (mt->compressed && brw->gen < 9 ? mt->qpitch / 4 :
400
                         mt->qpitch);
401
   }
402
 
403
   for (unsigned level = mt->first_level; level <= mt->last_level; level++) {
404
      unsigned img_height;
405
      img_height = ALIGN(height, mt->align_h);
406
      if (mt->compressed)
407
         img_height /= mt->align_h;
408
 
409
      for (int q = 0; q < mt->level[level].depth; q++) {
410
         if (mt->array_layout == ALL_SLICES_AT_EACH_LOD) {
411
            intel_miptree_set_image_offset(mt, level, q, 0, q * img_height);
412
         } else {
413
            intel_miptree_set_image_offset(mt, level, q, 0, q * physical_qpitch);
414
         }
415
      }
416
      height = minify(height, 1);
417
   }
418
   if (mt->array_layout == ALL_LOD_IN_EACH_SLICE)
419
      mt->total_height = physical_qpitch * mt->physical_depth0;
420
 
421
   align_cube(mt);
422
}
423
 
424
static void
425
brw_miptree_layout_texture_3d(struct brw_context *brw,
426
                              struct intel_mipmap_tree *mt)
427
{
428
   unsigned yscale = mt->compressed ? 4 : 1;
429
 
430
   mt->total_width = 0;
431
   mt->total_height = 0;
432
 
433
   unsigned ysum = 0;
434
   for (unsigned level = mt->first_level; level <= mt->last_level; level++) {
435
      unsigned WL = MAX2(mt->physical_width0 >> level, 1);
436
      unsigned HL = MAX2(mt->physical_height0 >> level, 1);
437
      unsigned DL = MAX2(mt->physical_depth0 >> level, 1);
438
      unsigned wL = ALIGN(WL, mt->align_w);
439
      unsigned hL = ALIGN(HL, mt->align_h);
440
 
441
      if (mt->target == GL_TEXTURE_CUBE_MAP)
442
         DL = 6;
443
 
444
      intel_miptree_set_level_info(mt, level, 0, 0, DL);
445
 
446
      for (unsigned q = 0; q < DL; q++) {
447
         unsigned x = (q % (1 << level)) * wL;
448
         unsigned y = ysum + (q >> level) * hL;
449
 
450
         intel_miptree_set_image_offset(mt, level, q, x, y / yscale);
451
         mt->total_width = MAX2(mt->total_width, x + wL);
452
         mt->total_height = MAX2(mt->total_height, (y + hL) / yscale);
453
      }
454
 
455
      ysum += ALIGN(DL, 1 << level) / (1 << level) * hL;
456
   }
457
 
458
   align_cube(mt);
459
}
460
 
461
void
462
brw_miptree_layout(struct brw_context *brw, struct intel_mipmap_tree *mt)
463
{
464
   bool multisampled = mt->num_samples > 1;
465
   bool gen6_hiz_or_stencil = false;
466
 
467
   if (brw->gen == 6 && mt->array_layout == ALL_SLICES_AT_EACH_LOD) {
468
      const GLenum base_format = _mesa_get_format_base_format(mt->format);
469
      gen6_hiz_or_stencil = _mesa_is_depth_or_stencil_format(base_format);
470
   }
471
 
472
   if (gen6_hiz_or_stencil) {
473
      /* On gen6, we use ALL_SLICES_AT_EACH_LOD for stencil/hiz because the
474
       * hardware doesn't support multiple mip levels on stencil/hiz.
475
       *
476
       * PRM Vol 2, Part 1, 7.5.3 Hierarchical Depth Buffer:
477
       * "The hierarchical depth buffer does not support the LOD field"
478
       *
479
       * PRM Vol 2, Part 1, 7.5.4.1 Separate Stencil Buffer:
480
       * "The stencil depth buffer does not support the LOD field"
481
       */
482
      if (mt->format == MESA_FORMAT_S_UINT8) {
483
         /* Stencil uses W tiling, so we force W tiling alignment for the
484
          * ALL_SLICES_AT_EACH_LOD miptree layout.
485
          */
486
         mt->align_w = 64;
487
         mt->align_h = 64;
488
      } else {
489
         /* Depth uses Y tiling, so we force need Y tiling alignment for the
490
          * ALL_SLICES_AT_EACH_LOD miptree layout.
491
          */
492
         mt->align_w = 128 / mt->cpp;
493
         mt->align_h = 32;
494
      }
495
   } else {
496
      mt->align_w = intel_horizontal_texture_alignment_unit(brw, mt);
497
      mt->align_h =
498
         intel_vertical_texture_alignment_unit(brw, mt->format, multisampled);
499
   }
500
 
501
   switch (mt->target) {
502
   case GL_TEXTURE_CUBE_MAP:
503
      if (brw->gen == 4) {
504
         /* Gen4 stores cube maps as 3D textures. */
505
         assert(mt->physical_depth0 == 6);
506
         brw_miptree_layout_texture_3d(brw, mt);
507
      } else {
508
         /* All other hardware stores cube maps as 2D arrays. */
509
	 brw_miptree_layout_texture_array(brw, mt);
510
      }
511
      break;
512
 
513
   case GL_TEXTURE_3D:
514
      if (brw->gen >= 9)
515
         brw_miptree_layout_texture_array(brw, mt);
516
      else
517
         brw_miptree_layout_texture_3d(brw, mt);
518
      break;
519
 
520
   case GL_TEXTURE_1D_ARRAY:
521
   case GL_TEXTURE_2D_ARRAY:
522
   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
523
   case GL_TEXTURE_CUBE_MAP_ARRAY:
524
      brw_miptree_layout_texture_array(brw, mt);
525
      break;
526
 
527
   default:
528
      switch (mt->msaa_layout) {
529
      case INTEL_MSAA_LAYOUT_UMS:
530
      case INTEL_MSAA_LAYOUT_CMS:
531
         brw_miptree_layout_texture_array(brw, mt);
532
         break;
533
      case INTEL_MSAA_LAYOUT_NONE:
534
      case INTEL_MSAA_LAYOUT_IMS:
535
         if (use_linear_1d_layout(brw, mt))
536
            gen9_miptree_layout_1d(mt);
537
         else
538
            brw_miptree_layout_2d(mt);
539
         break;
540
      }
541
      break;
542
   }
543
   DBG("%s: %dx%dx%d\n", __func__,
544
       mt->total_width, mt->total_height, mt->cpp);
545
 
546
   /* On Gen9+ the alignment values are expressed in multiples of the block
547
    * size
548
    */
549
   if (brw->gen >= 9) {
550
      unsigned int i, j;
551
      _mesa_get_format_block_size(mt->format, &i, &j);
552
      mt->align_w /= i;
553
      mt->align_h /= j;
554
   }
555
}
556