~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/gallium/drivers/nouveau/nvc0/nvc0_miptree.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
 
 * Copyright 2008 Ben Skeggs
3
 
 *
4
 
 * Permission is hereby granted, free of charge, to any person obtaining a
5
 
 * copy of this software and associated documentation files (the "Software"),
6
 
 * to deal in the Software without restriction, including without limitation
7
 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
 
 * and/or sell copies of the Software, and to permit persons to whom the
9
 
 * Software is furnished to do so, subject to the following conditions:
10
 
 *
11
 
 * The above copyright notice and this permission notice shall be included in
12
 
 * all copies or substantial portions of the Software.
13
 
 *
14
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17
 
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18
 
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19
 
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
 
 * OTHER DEALINGS IN THE SOFTWARE.
21
 
 */
22
 
 
23
 
#include "drm-uapi/drm_fourcc.h"
24
 
 
25
 
#include "pipe/p_state.h"
26
 
#include "pipe/p_defines.h"
27
 
#include "frontend/drm_driver.h"
28
 
#include "util/u_inlines.h"
29
 
#include "util/format/u_format.h"
30
 
 
31
 
#include "nvc0/nvc0_context.h"
32
 
#include "nvc0/nvc0_resource.h"
33
 
 
34
 
static uint32_t
35
 
nvc0_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz, bool is_3d)
36
 
{
37
 
   return nv50_tex_choose_tile_dims_helper(nx, ny, nz, is_3d);
38
 
}
39
 
 
40
 
static uint32_t
41
 
tu102_choose_tiled_storage_type(enum pipe_format format,
42
 
                                unsigned ms,
43
 
                                bool compressed)
44
 
 
45
 
{
46
 
   uint32_t kind;
47
 
 
48
 
   switch (format) {
49
 
   case PIPE_FORMAT_Z16_UNORM:
50
 
      if (compressed)
51
 
         kind = 0x0b; // NV_MMU_PTE_KIND_Z16_COMPRESSIBLE_DISABLE_PLC
52
 
      else
53
 
         kind = 0x01; // NV_MMU_PTE_KIND_Z16
54
 
      break;
55
 
   case PIPE_FORMAT_X8Z24_UNORM:
56
 
   case PIPE_FORMAT_S8X24_UINT:
57
 
   case PIPE_FORMAT_S8_UINT_Z24_UNORM:
58
 
      if (compressed)
59
 
         kind = 0x0e; // NV_MMU_PTE_KIND_Z24S8_COMPRESSIBLE_DISABLE_PLC
60
 
      else
61
 
         kind = 0x05; // NV_MMU_PTE_KIND_Z24S8
62
 
      break;
63
 
   case PIPE_FORMAT_X24S8_UINT:
64
 
   case PIPE_FORMAT_Z24X8_UNORM:
65
 
   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
66
 
      if (compressed)
67
 
         kind = 0x0c; // NV_MMU_PTE_KIND_S8Z24_COMPRESSIBLE_DISABLE_PLC
68
 
      else
69
 
         kind = 0x03; // NV_MMU_PTE_KIND_S8Z24
70
 
      break;
71
 
   case PIPE_FORMAT_X32_S8X24_UINT:
72
 
   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
73
 
      if (compressed)
74
 
         kind = 0x0d; // NV_MMU_PTE_KIND_ZF32_X24S8_COMPRESSIBLE_DISABLE_PLC
75
 
      else
76
 
         kind = 0x04; // NV_MMU_PTE_KIND_ZF32_X24S8
77
 
      break;
78
 
   case PIPE_FORMAT_Z32_FLOAT:
79
 
   default:
80
 
      kind = 0x06;
81
 
      break;
82
 
   }
83
 
 
84
 
   return kind;
85
 
}
86
 
 
87
 
uint32_t
88
 
nvc0_choose_tiled_storage_type(struct pipe_screen *pscreen,
89
 
                               enum pipe_format format,
90
 
                               unsigned ms,
91
 
                               bool compressed)
92
 
{
93
 
   uint32_t tile_flags;
94
 
 
95
 
   if (nouveau_screen(pscreen)->device->chipset >= 0x160)
96
 
      return tu102_choose_tiled_storage_type(format, ms, compressed);
97
 
 
98
 
   switch (format) {
99
 
   case PIPE_FORMAT_Z16_UNORM:
100
 
      if (compressed)
101
 
         tile_flags = 0x02 + ms;
102
 
      else
103
 
         tile_flags = 0x01;
104
 
      break;
105
 
   case PIPE_FORMAT_X8Z24_UNORM:
106
 
   case PIPE_FORMAT_S8X24_UINT:
107
 
   case PIPE_FORMAT_S8_UINT_Z24_UNORM:
108
 
      if (compressed)
109
 
         tile_flags = 0x51 + ms;
110
 
      else
111
 
         tile_flags = 0x46;
112
 
      break;
113
 
   case PIPE_FORMAT_X24S8_UINT:
114
 
   case PIPE_FORMAT_Z24X8_UNORM:
115
 
   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
116
 
      if (compressed)
117
 
         tile_flags = 0x17 + ms;
118
 
      else
119
 
         tile_flags = 0x11;
120
 
      break;
121
 
   case PIPE_FORMAT_Z32_FLOAT:
122
 
      if (compressed)
123
 
         tile_flags = 0x86 + ms;
124
 
      else
125
 
         tile_flags = 0x7b;
126
 
      break;
127
 
   case PIPE_FORMAT_X32_S8X24_UINT:
128
 
   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
129
 
      if (compressed)
130
 
         tile_flags = 0xce + ms;
131
 
      else
132
 
         tile_flags = 0xc3;
133
 
      break;
134
 
   default:
135
 
      switch (util_format_get_blocksizebits(format)) {
136
 
      case 128:
137
 
         if (compressed)
138
 
            tile_flags = 0xf4 + ms * 2;
139
 
         else
140
 
            tile_flags = 0xfe;
141
 
         break;
142
 
      case 64:
143
 
         if (compressed) {
144
 
            switch (ms) {
145
 
            case 0: tile_flags = 0xe6; break;
146
 
            case 1: tile_flags = 0xeb; break;
147
 
            case 2: tile_flags = 0xed; break;
148
 
            case 3: tile_flags = 0xf2; break;
149
 
            default:
150
 
               return 0;
151
 
            }
152
 
         } else {
153
 
            tile_flags = 0xfe;
154
 
         }
155
 
         break;
156
 
      case 32:
157
 
         if (compressed && ms) {
158
 
            switch (ms) {
159
 
               /* This one makes things blurry:
160
 
            case 0: tile_flags = 0xdb; break;
161
 
               */
162
 
            case 1: tile_flags = 0xdd; break;
163
 
            case 2: tile_flags = 0xdf; break;
164
 
            case 3: tile_flags = 0xe4; break;
165
 
            default:
166
 
               return 0;
167
 
            }
168
 
         } else {
169
 
            tile_flags = 0xfe;
170
 
         }
171
 
         break;
172
 
      case 16:
173
 
      case 8:
174
 
         tile_flags = 0xfe;
175
 
         break;
176
 
      default:
177
 
         return 0;
178
 
      }
179
 
      break;
180
 
   }
181
 
 
182
 
   return tile_flags;
183
 
}
184
 
 
185
 
static uint32_t
186
 
nvc0_mt_choose_storage_type(struct pipe_screen *pscreen,
187
 
                            const struct nv50_miptree *mt,
188
 
                            bool compressed)
189
 
{
190
 
   const unsigned ms = util_logbase2(mt->base.base.nr_samples);
191
 
 
192
 
   if (unlikely(mt->base.base.bind & PIPE_BIND_CURSOR))
193
 
      return 0;
194
 
   if (unlikely(mt->base.base.flags & NOUVEAU_RESOURCE_FLAG_LINEAR))
195
 
      return 0;
196
 
 
197
 
   return nvc0_choose_tiled_storage_type(pscreen, mt->base.base.format, ms, compressed);
198
 
}
199
 
 
200
 
static inline bool
201
 
nvc0_miptree_init_ms_mode(struct nv50_miptree *mt)
202
 
{
203
 
   switch (mt->base.base.nr_samples) {
204
 
   case 8:
205
 
      mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS8;
206
 
      mt->ms_x = 2;
207
 
      mt->ms_y = 1;
208
 
      break;
209
 
   case 4:
210
 
      mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS4;
211
 
      mt->ms_x = 1;
212
 
      mt->ms_y = 1;
213
 
      break;
214
 
   case 2:
215
 
      mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS2;
216
 
      mt->ms_x = 1;
217
 
      break;
218
 
   case 1:
219
 
   case 0:
220
 
      mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS1;
221
 
      break;
222
 
   default:
223
 
      NOUVEAU_ERR("invalid nr_samples: %u\n", mt->base.base.nr_samples);
224
 
      return false;
225
 
   }
226
 
   return true;
227
 
}
228
 
 
229
 
static void
230
 
nvc0_miptree_init_layout_video(struct nv50_miptree *mt)
231
 
{
232
 
   const struct pipe_resource *pt = &mt->base.base;
233
 
   const unsigned blocksize = util_format_get_blocksize(pt->format);
234
 
 
235
 
   assert(pt->last_level == 0);
236
 
   assert(mt->ms_x == 0 && mt->ms_y == 0);
237
 
   assert(!util_format_is_compressed(pt->format));
238
 
 
239
 
   mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
240
 
 
241
 
   mt->level[0].tile_mode = 0x10;
242
 
   mt->level[0].pitch = align(pt->width0 * blocksize, 64);
243
 
   mt->total_size = align(pt->height0, 16) * mt->level[0].pitch * (mt->layout_3d ? pt->depth0 : 1);
244
 
 
245
 
   if (pt->array_size > 1) {
246
 
      mt->layer_stride = align(mt->total_size, NVC0_TILE_SIZE(0x10));
247
 
      mt->total_size = mt->layer_stride * pt->array_size;
248
 
   }
249
 
}
250
 
 
251
 
static void
252
 
nvc0_miptree_init_layout_tiled(struct nv50_miptree *mt, uint64_t modifier)
253
 
{
254
 
   struct pipe_resource *pt = &mt->base.base;
255
 
   unsigned w, h, d, l;
256
 
   const unsigned blocksize = util_format_get_blocksize(pt->format);
257
 
 
258
 
   mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
259
 
 
260
 
   w = pt->width0 << mt->ms_x;
261
 
   h = pt->height0 << mt->ms_y;
262
 
 
263
 
   /* For 3D textures, a mipmap is spanned by all the layers, for array
264
 
    * textures and cube maps, each layer contains its own mipmaps.
265
 
    */
266
 
   d = mt->layout_3d ? pt->depth0 : 1;
267
 
 
268
 
   assert(!mt->ms_mode || !pt->last_level);
269
 
   assert(modifier == DRM_FORMAT_MOD_INVALID ||
270
 
          (!pt->last_level && !mt->layout_3d));
271
 
   assert(modifier != DRM_FORMAT_MOD_LINEAR);
272
 
 
273
 
   for (l = 0; l <= pt->last_level; ++l) {
274
 
      struct nv50_miptree_level *lvl = &mt->level[l];
275
 
      unsigned tsx, tsy, tsz;
276
 
      unsigned nbx = util_format_get_nblocksx(pt->format, w);
277
 
      unsigned nby = util_format_get_nblocksy(pt->format, h);
278
 
 
279
 
      lvl->offset = mt->total_size;
280
 
 
281
 
      if (modifier != DRM_FORMAT_MOD_INVALID)
282
 
         /* Extract the log2(block height) field from the modifier and pack it
283
 
          * into tile_mode's y field. Other tile dimensions are always 1
284
 
          * (represented using 0 here) for 2D surfaces, and non-2D surfaces are
285
 
          * not supported by the current modifiers (asserted above). Note the
286
 
          * modifier must be validated prior to calling this function.
287
 
          */
288
 
         lvl->tile_mode = ((uint32_t)modifier & 0xf) << 4;
289
 
      else
290
 
         lvl->tile_mode = nvc0_tex_choose_tile_dims(nbx, nby, d, mt->layout_3d);
291
 
 
292
 
      tsx = NVC0_TILE_SIZE_X(lvl->tile_mode); /* x is tile row pitch in bytes */
293
 
      tsy = NVC0_TILE_SIZE_Y(lvl->tile_mode);
294
 
      tsz = NVC0_TILE_SIZE_Z(lvl->tile_mode);
295
 
 
296
 
      lvl->pitch = align(nbx * blocksize, tsx);
297
 
 
298
 
      mt->total_size += lvl->pitch * align(nby, tsy) * align(d, tsz);
299
 
 
300
 
      w = u_minify(w, 1);
301
 
      h = u_minify(h, 1);
302
 
      d = u_minify(d, 1);
303
 
   }
304
 
 
305
 
   if (pt->array_size > 1) {
306
 
      mt->layer_stride = align(mt->total_size,
307
 
                               NVC0_TILE_SIZE(mt->level[0].tile_mode));
308
 
      mt->total_size = mt->layer_stride * pt->array_size;
309
 
   }
310
 
}
311
 
 
312
 
static uint64_t
313
 
nvc0_miptree_get_modifier(struct pipe_screen *pscreen, struct nv50_miptree *mt)
314
 
{
315
 
   const union nouveau_bo_config *config = &mt->base.bo->config;
316
 
   const uint32_t uc_kind =
317
 
      nvc0_choose_tiled_storage_type(pscreen,
318
 
                                     mt->base.base.format,
319
 
                                     mt->base.base.nr_samples,
320
 
                                     false);
321
 
   const uint32_t kind_gen = nvc0_get_kind_generation(pscreen);
322
 
 
323
 
   if (mt->layout_3d)
324
 
      return DRM_FORMAT_MOD_INVALID;
325
 
   if (mt->base.base.nr_samples > 1)
326
 
      return DRM_FORMAT_MOD_INVALID;
327
 
   if (config->nvc0.memtype == 0x00)
328
 
      return DRM_FORMAT_MOD_LINEAR;
329
 
   if (NVC0_TILE_MODE_Y(config->nvc0.tile_mode) > 5)
330
 
      return DRM_FORMAT_MOD_INVALID;
331
 
   if (config->nvc0.memtype != uc_kind)
332
 
      return DRM_FORMAT_MOD_INVALID;
333
 
 
334
 
   return DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(
335
 
             0,
336
 
             nouveau_screen(pscreen)->tegra_sector_layout ? 0 : 1,
337
 
             kind_gen,
338
 
             config->nvc0.memtype,
339
 
             NVC0_TILE_MODE_Y(config->nvc0.tile_mode));
340
 
}
341
 
 
342
 
bool
343
 
nvc0_miptree_get_handle(struct pipe_screen *pscreen,
344
 
                        struct pipe_context *context,
345
 
                        struct pipe_resource *pt,
346
 
                        struct winsys_handle *whandle,
347
 
                        unsigned usage)
348
 
{
349
 
   struct nv50_miptree *mt = nv50_miptree(pt);
350
 
   bool ret;
351
 
 
352
 
   ret = nv50_miptree_get_handle(pscreen, context, pt, whandle, usage);
353
 
   if (!ret)
354
 
      return ret;
355
 
 
356
 
   whandle->modifier = nvc0_miptree_get_modifier(pscreen, mt);
357
 
 
358
 
   return true;
359
 
}
360
 
 
361
 
static uint64_t
362
 
nvc0_miptree_select_best_modifier(struct pipe_screen *pscreen,
363
 
                                  const struct nv50_miptree *mt,
364
 
                                  const uint64_t *modifiers,
365
 
                                  unsigned int count)
366
 
{
367
 
   /*
368
 
    * Supported block heights are 1,2,4,8,16,32, stored as log2() their
369
 
    * value. Reserve one slot for each, as well as the linear modifier.
370
 
    */
371
 
   uint64_t prio_supported_mods[] = {
372
 
      DRM_FORMAT_MOD_INVALID,
373
 
      DRM_FORMAT_MOD_INVALID,
374
 
      DRM_FORMAT_MOD_INVALID,
375
 
      DRM_FORMAT_MOD_INVALID,
376
 
      DRM_FORMAT_MOD_INVALID,
377
 
      DRM_FORMAT_MOD_INVALID,
378
 
      DRM_FORMAT_MOD_LINEAR,
379
 
   };
380
 
   const uint32_t uc_kind = nvc0_mt_choose_storage_type(pscreen, mt, false);
381
 
   int top_mod_slot = ARRAY_SIZE(prio_supported_mods);
382
 
   const uint32_t kind_gen = nvc0_get_kind_generation(pscreen);
383
 
   unsigned int i;
384
 
   int p;
385
 
 
386
 
   if (uc_kind != 0u) {
387
 
      const struct pipe_resource *pt = &mt->base.base;
388
 
      const unsigned nbx = util_format_get_nblocksx(pt->format, pt->width0);
389
 
      const unsigned nby = util_format_get_nblocksy(pt->format, pt->height0);
390
 
      const uint32_t lbh_preferred =
391
 
         NVC0_TILE_MODE_Y(nvc0_tex_choose_tile_dims(nbx, nby, 1u, false));
392
 
      uint32_t lbh = lbh_preferred;
393
 
      bool dec_lbh = true;
394
 
      const uint8_t s = nouveau_screen(pscreen)->tegra_sector_layout ? 0 : 1;
395
 
 
396
 
      for (i = 0; i < ARRAY_SIZE(prio_supported_mods) - 1; i++) {
397
 
         assert(lbh <= 5u);
398
 
         prio_supported_mods[i] =
399
 
            DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, s, kind_gen, uc_kind, lbh);
400
 
 
401
 
         /*
402
 
          * The preferred block height is the largest block size that doesn't
403
 
          * waste excessive space with unused padding bytes relative to the
404
 
          * height of the image.  Construct the priority array such that
405
 
          * the preferred block height is highest priority, followed by
406
 
          * progressively smaller block sizes down to a block height of one,
407
 
          * followed by progressively larger (more wasteful) block sizes up
408
 
          * to 5.
409
 
          */
410
 
         if (lbh == 0u) {
411
 
            lbh = lbh_preferred + 1u;
412
 
            dec_lbh = false;
413
 
         } else if (dec_lbh) {
414
 
            lbh--;
415
 
         } else {
416
 
            lbh++;
417
 
         }
418
 
      }
419
 
   }
420
 
 
421
 
   assert(prio_supported_mods[ARRAY_SIZE(prio_supported_mods) - 1] ==
422
 
          DRM_FORMAT_MOD_LINEAR);
423
 
 
424
 
   for (i = 0u; i < count; i++) {
425
 
      for (p = 0; p < ARRAY_SIZE(prio_supported_mods); p++) {
426
 
         if (prio_supported_mods[p] == modifiers[i]) {
427
 
            if (top_mod_slot > p) top_mod_slot = p;
428
 
            break;
429
 
         }
430
 
      }
431
 
   }
432
 
 
433
 
   if (top_mod_slot >= ARRAY_SIZE(prio_supported_mods))
434
 
       return DRM_FORMAT_MOD_INVALID;
435
 
 
436
 
   return prio_supported_mods[top_mod_slot];
437
 
}
438
 
 
439
 
struct pipe_resource *
440
 
nvc0_miptree_create(struct pipe_screen *pscreen,
441
 
                    const struct pipe_resource *templ,
442
 
                    const uint64_t *modifiers, unsigned int count)
443
 
{
444
 
   struct nouveau_device *dev = nouveau_screen(pscreen)->device;
445
 
   struct nouveau_drm *drm = nouveau_screen(pscreen)->drm;
446
 
   struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree);
447
 
   struct pipe_resource *pt = &mt->base.base;
448
 
   bool compressed = drm->version >= 0x01000101;
449
 
   int ret;
450
 
   union nouveau_bo_config bo_config;
451
 
   uint32_t bo_flags;
452
 
   unsigned pitch_align;
453
 
   uint64_t modifier = DRM_FORMAT_MOD_INVALID;
454
 
 
455
 
   if (!mt)
456
 
      return NULL;
457
 
 
458
 
   *pt = *templ;
459
 
   pipe_reference_init(&pt->reference, 1);
460
 
   pt->screen = pscreen;
461
 
 
462
 
   if (pt->usage == PIPE_USAGE_STAGING) {
463
 
      /* PIPE_USAGE_STAGING, and usage in general, should not be specified when
464
 
       * modifiers are used. */
465
 
      assert(count == 0);
466
 
      switch (pt->target) {
467
 
      case PIPE_TEXTURE_2D:
468
 
      case PIPE_TEXTURE_RECT:
469
 
         if (pt->last_level == 0 &&
470
 
             !util_format_is_depth_or_stencil(pt->format) &&
471
 
             pt->nr_samples <= 1)
472
 
            pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
473
 
         break;
474
 
      default:
475
 
         break;
476
 
      }
477
 
   }
478
 
 
479
 
   if (pt->bind & PIPE_BIND_LINEAR)
480
 
      pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
481
 
 
482
 
   if (count > 0) {
483
 
      modifier = nvc0_miptree_select_best_modifier(pscreen, mt,
484
 
                                                   modifiers, count);
485
 
 
486
 
      if (modifier == DRM_FORMAT_MOD_INVALID) {
487
 
         FREE(mt);
488
 
         return NULL;
489
 
      }
490
 
 
491
 
      if (modifier == DRM_FORMAT_MOD_LINEAR) {
492
 
         pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
493
 
         bo_config.nvc0.memtype = 0;
494
 
      } else {
495
 
         bo_config.nvc0.memtype = (modifier >> 12) & 0xff;
496
 
      }
497
 
   } else {
498
 
      bo_config.nvc0.memtype = nvc0_mt_choose_storage_type(pscreen, mt, compressed);
499
 
   }
500
 
 
501
 
   if (!nvc0_miptree_init_ms_mode(mt)) {
502
 
      FREE(mt);
503
 
      return NULL;
504
 
   }
505
 
 
506
 
   if (unlikely(pt->flags & NVC0_RESOURCE_FLAG_VIDEO)) {
507
 
      assert(modifier == DRM_FORMAT_MOD_INVALID);
508
 
      nvc0_miptree_init_layout_video(mt);
509
 
   } else
510
 
   if (likely(bo_config.nvc0.memtype)) {
511
 
      nvc0_miptree_init_layout_tiled(mt, modifier);
512
 
   } else {
513
 
      /* When modifiers are supplied, usage is zero. TODO: detect the
514
 
       * modifiers+cursor case. */
515
 
      if (pt->usage & PIPE_BIND_CURSOR)
516
 
         pitch_align = 1;
517
 
      else if ((pt->usage & PIPE_BIND_SCANOUT) || count > 0)
518
 
         pitch_align = 256;
519
 
      else
520
 
         pitch_align = 128;
521
 
      if (!nv50_miptree_init_layout_linear(mt, pitch_align)) {
522
 
         FREE(mt);
523
 
         return NULL;
524
 
      }
525
 
   }
526
 
   bo_config.nvc0.tile_mode = mt->level[0].tile_mode;
527
 
 
528
 
   if (!bo_config.nvc0.memtype && (pt->usage == PIPE_USAGE_STAGING || pt->bind & PIPE_BIND_SHARED))
529
 
      mt->base.domain = NOUVEAU_BO_GART;
530
 
   else
531
 
      mt->base.domain = NV_VRAM_DOMAIN(nouveau_screen(pscreen));
532
 
 
533
 
   bo_flags = mt->base.domain | NOUVEAU_BO_NOSNOOP;
534
 
 
535
 
   if (mt->base.base.bind & (PIPE_BIND_CURSOR | PIPE_BIND_DISPLAY_TARGET))
536
 
      bo_flags |= NOUVEAU_BO_CONTIG;
537
 
 
538
 
   ret = nouveau_bo_new(dev, bo_flags, 4096, mt->total_size, &bo_config,
539
 
                        &mt->base.bo);
540
 
   if (ret) {
541
 
      FREE(mt);
542
 
      return NULL;
543
 
   }
544
 
   mt->base.address = mt->base.bo->offset;
545
 
 
546
 
   NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_count, 1);
547
 
   NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_bytes,
548
 
                    mt->total_size);
549
 
 
550
 
   return pt;
551
 
}
552
 
 
553
 
/* Offset of zslice @z from start of level @l. */
554
 
inline unsigned
555
 
nvc0_mt_zslice_offset(const struct nv50_miptree *mt, unsigned l, unsigned z)
556
 
{
557
 
   const struct pipe_resource *pt = &mt->base.base;
558
 
 
559
 
   unsigned tds = NVC0_TILE_SHIFT_Z(mt->level[l].tile_mode);
560
 
   unsigned ths = NVC0_TILE_SHIFT_Y(mt->level[l].tile_mode);
561
 
 
562
 
   unsigned nby = util_format_get_nblocksy(pt->format,
563
 
                                           u_minify(pt->height0, l));
564
 
 
565
 
   /* to next 2D tile slice within a 3D tile */
566
 
   unsigned stride_2d = NVC0_TILE_SIZE_2D(mt->level[l].tile_mode);
567
 
 
568
 
   /* to slice in the next (in z direction) 3D tile */
569
 
   unsigned stride_3d = (align(nby, (1 << ths)) * mt->level[l].pitch) << tds;
570
 
 
571
 
   return (z & (1 << (tds - 1))) * stride_2d + (z >> tds) * stride_3d;
572
 
}
573
 
 
574
 
/* Surface functions.
575
 
 */
576
 
 
577
 
struct pipe_surface *
578
 
nvc0_miptree_surface_new(struct pipe_context *pipe,
579
 
                         struct pipe_resource *pt,
580
 
                         const struct pipe_surface *templ)
581
 
{
582
 
   struct nv50_surface *ns = nv50_surface_from_miptree(nv50_miptree(pt), templ);
583
 
   if (!ns)
584
 
      return NULL;
585
 
   ns->base.context = pipe;
586
 
   return &ns->base;
587
 
}