2
* Copyright 2008 Ben Skeggs
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:
11
* The above copyright notice and this permission notice shall be included in
12
* all copies or substantial portions of the Software.
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.
23
#include "drm-uapi/drm_fourcc.h"
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"
31
#include "nvc0/nvc0_context.h"
32
#include "nvc0/nvc0_resource.h"
35
nvc0_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz, bool is_3d)
37
return nv50_tex_choose_tile_dims_helper(nx, ny, nz, is_3d);
41
tu102_choose_tiled_storage_type(enum pipe_format format,
49
case PIPE_FORMAT_Z16_UNORM:
51
kind = 0x0b; // NV_MMU_PTE_KIND_Z16_COMPRESSIBLE_DISABLE_PLC
53
kind = 0x01; // NV_MMU_PTE_KIND_Z16
55
case PIPE_FORMAT_X8Z24_UNORM:
56
case PIPE_FORMAT_S8X24_UINT:
57
case PIPE_FORMAT_S8_UINT_Z24_UNORM:
59
kind = 0x0e; // NV_MMU_PTE_KIND_Z24S8_COMPRESSIBLE_DISABLE_PLC
61
kind = 0x05; // NV_MMU_PTE_KIND_Z24S8
63
case PIPE_FORMAT_X24S8_UINT:
64
case PIPE_FORMAT_Z24X8_UNORM:
65
case PIPE_FORMAT_Z24_UNORM_S8_UINT:
67
kind = 0x0c; // NV_MMU_PTE_KIND_S8Z24_COMPRESSIBLE_DISABLE_PLC
69
kind = 0x03; // NV_MMU_PTE_KIND_S8Z24
71
case PIPE_FORMAT_X32_S8X24_UINT:
72
case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
74
kind = 0x0d; // NV_MMU_PTE_KIND_ZF32_X24S8_COMPRESSIBLE_DISABLE_PLC
76
kind = 0x04; // NV_MMU_PTE_KIND_ZF32_X24S8
78
case PIPE_FORMAT_Z32_FLOAT:
88
nvc0_choose_tiled_storage_type(struct pipe_screen *pscreen,
89
enum pipe_format format,
95
if (nouveau_screen(pscreen)->device->chipset >= 0x160)
96
return tu102_choose_tiled_storage_type(format, ms, compressed);
99
case PIPE_FORMAT_Z16_UNORM:
101
tile_flags = 0x02 + ms;
105
case PIPE_FORMAT_X8Z24_UNORM:
106
case PIPE_FORMAT_S8X24_UINT:
107
case PIPE_FORMAT_S8_UINT_Z24_UNORM:
109
tile_flags = 0x51 + ms;
113
case PIPE_FORMAT_X24S8_UINT:
114
case PIPE_FORMAT_Z24X8_UNORM:
115
case PIPE_FORMAT_Z24_UNORM_S8_UINT:
117
tile_flags = 0x17 + ms;
121
case PIPE_FORMAT_Z32_FLOAT:
123
tile_flags = 0x86 + ms;
127
case PIPE_FORMAT_X32_S8X24_UINT:
128
case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
130
tile_flags = 0xce + ms;
135
switch (util_format_get_blocksizebits(format)) {
138
tile_flags = 0xf4 + ms * 2;
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;
157
if (compressed && ms) {
159
/* This one makes things blurry:
160
case 0: tile_flags = 0xdb; break;
162
case 1: tile_flags = 0xdd; break;
163
case 2: tile_flags = 0xdf; break;
164
case 3: tile_flags = 0xe4; break;
186
nvc0_mt_choose_storage_type(struct pipe_screen *pscreen,
187
const struct nv50_miptree *mt,
190
const unsigned ms = util_logbase2(mt->base.base.nr_samples);
192
if (unlikely(mt->base.base.bind & PIPE_BIND_CURSOR))
194
if (unlikely(mt->base.base.flags & NOUVEAU_RESOURCE_FLAG_LINEAR))
197
return nvc0_choose_tiled_storage_type(pscreen, mt->base.base.format, ms, compressed);
201
nvc0_miptree_init_ms_mode(struct nv50_miptree *mt)
203
switch (mt->base.base.nr_samples) {
205
mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS8;
210
mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS4;
215
mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS2;
220
mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS1;
223
NOUVEAU_ERR("invalid nr_samples: %u\n", mt->base.base.nr_samples);
230
nvc0_miptree_init_layout_video(struct nv50_miptree *mt)
232
const struct pipe_resource *pt = &mt->base.base;
233
const unsigned blocksize = util_format_get_blocksize(pt->format);
235
assert(pt->last_level == 0);
236
assert(mt->ms_x == 0 && mt->ms_y == 0);
237
assert(!util_format_is_compressed(pt->format));
239
mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
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);
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;
252
nvc0_miptree_init_layout_tiled(struct nv50_miptree *mt, uint64_t modifier)
254
struct pipe_resource *pt = &mt->base.base;
256
const unsigned blocksize = util_format_get_blocksize(pt->format);
258
mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
260
w = pt->width0 << mt->ms_x;
261
h = pt->height0 << mt->ms_y;
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.
266
d = mt->layout_3d ? pt->depth0 : 1;
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);
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);
279
lvl->offset = mt->total_size;
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.
288
lvl->tile_mode = ((uint32_t)modifier & 0xf) << 4;
290
lvl->tile_mode = nvc0_tex_choose_tile_dims(nbx, nby, d, mt->layout_3d);
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);
296
lvl->pitch = align(nbx * blocksize, tsx);
298
mt->total_size += lvl->pitch * align(nby, tsy) * align(d, tsz);
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;
313
nvc0_miptree_get_modifier(struct pipe_screen *pscreen, struct nv50_miptree *mt)
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,
321
const uint32_t kind_gen = nvc0_get_kind_generation(pscreen);
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;
334
return DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(
336
nouveau_screen(pscreen)->tegra_sector_layout ? 0 : 1,
338
config->nvc0.memtype,
339
NVC0_TILE_MODE_Y(config->nvc0.tile_mode));
343
nvc0_miptree_get_handle(struct pipe_screen *pscreen,
344
struct pipe_context *context,
345
struct pipe_resource *pt,
346
struct winsys_handle *whandle,
349
struct nv50_miptree *mt = nv50_miptree(pt);
352
ret = nv50_miptree_get_handle(pscreen, context, pt, whandle, usage);
356
whandle->modifier = nvc0_miptree_get_modifier(pscreen, mt);
362
nvc0_miptree_select_best_modifier(struct pipe_screen *pscreen,
363
const struct nv50_miptree *mt,
364
const uint64_t *modifiers,
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.
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,
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);
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;
394
const uint8_t s = nouveau_screen(pscreen)->tegra_sector_layout ? 0 : 1;
396
for (i = 0; i < ARRAY_SIZE(prio_supported_mods) - 1; i++) {
398
prio_supported_mods[i] =
399
DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, s, kind_gen, uc_kind, lbh);
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
411
lbh = lbh_preferred + 1u;
413
} else if (dec_lbh) {
421
assert(prio_supported_mods[ARRAY_SIZE(prio_supported_mods) - 1] ==
422
DRM_FORMAT_MOD_LINEAR);
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;
433
if (top_mod_slot >= ARRAY_SIZE(prio_supported_mods))
434
return DRM_FORMAT_MOD_INVALID;
436
return prio_supported_mods[top_mod_slot];
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)
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;
450
union nouveau_bo_config bo_config;
452
unsigned pitch_align;
453
uint64_t modifier = DRM_FORMAT_MOD_INVALID;
459
pipe_reference_init(&pt->reference, 1);
460
pt->screen = pscreen;
462
if (pt->usage == PIPE_USAGE_STAGING) {
463
/* PIPE_USAGE_STAGING, and usage in general, should not be specified when
464
* modifiers are used. */
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) &&
472
pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
479
if (pt->bind & PIPE_BIND_LINEAR)
480
pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
483
modifier = nvc0_miptree_select_best_modifier(pscreen, mt,
486
if (modifier == DRM_FORMAT_MOD_INVALID) {
491
if (modifier == DRM_FORMAT_MOD_LINEAR) {
492
pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
493
bo_config.nvc0.memtype = 0;
495
bo_config.nvc0.memtype = (modifier >> 12) & 0xff;
498
bo_config.nvc0.memtype = nvc0_mt_choose_storage_type(pscreen, mt, compressed);
501
if (!nvc0_miptree_init_ms_mode(mt)) {
506
if (unlikely(pt->flags & NVC0_RESOURCE_FLAG_VIDEO)) {
507
assert(modifier == DRM_FORMAT_MOD_INVALID);
508
nvc0_miptree_init_layout_video(mt);
510
if (likely(bo_config.nvc0.memtype)) {
511
nvc0_miptree_init_layout_tiled(mt, modifier);
513
/* When modifiers are supplied, usage is zero. TODO: detect the
514
* modifiers+cursor case. */
515
if (pt->usage & PIPE_BIND_CURSOR)
517
else if ((pt->usage & PIPE_BIND_SCANOUT) || count > 0)
521
if (!nv50_miptree_init_layout_linear(mt, pitch_align)) {
526
bo_config.nvc0.tile_mode = mt->level[0].tile_mode;
528
if (!bo_config.nvc0.memtype && (pt->usage == PIPE_USAGE_STAGING || pt->bind & PIPE_BIND_SHARED))
529
mt->base.domain = NOUVEAU_BO_GART;
531
mt->base.domain = NV_VRAM_DOMAIN(nouveau_screen(pscreen));
533
bo_flags = mt->base.domain | NOUVEAU_BO_NOSNOOP;
535
if (mt->base.base.bind & (PIPE_BIND_CURSOR | PIPE_BIND_DISPLAY_TARGET))
536
bo_flags |= NOUVEAU_BO_CONTIG;
538
ret = nouveau_bo_new(dev, bo_flags, 4096, mt->total_size, &bo_config,
544
mt->base.address = mt->base.bo->offset;
546
NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_count, 1);
547
NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_bytes,
553
/* Offset of zslice @z from start of level @l. */
555
nvc0_mt_zslice_offset(const struct nv50_miptree *mt, unsigned l, unsigned z)
557
const struct pipe_resource *pt = &mt->base.base;
559
unsigned tds = NVC0_TILE_SHIFT_Z(mt->level[l].tile_mode);
560
unsigned ths = NVC0_TILE_SHIFT_Y(mt->level[l].tile_mode);
562
unsigned nby = util_format_get_nblocksy(pt->format,
563
u_minify(pt->height0, l));
565
/* to next 2D tile slice within a 3D tile */
566
unsigned stride_2d = NVC0_TILE_SIZE_2D(mt->level[l].tile_mode);
568
/* to slice in the next (in z direction) 3D tile */
569
unsigned stride_3d = (align(nby, (1 << ths)) * mt->level[l].pitch) << tds;
571
return (z & (1 << (tds - 1))) * stride_2d + (z >> tds) * stride_3d;
574
/* Surface functions.
577
struct pipe_surface *
578
nvc0_miptree_surface_new(struct pipe_context *pipe,
579
struct pipe_resource *pt,
580
const struct pipe_surface *templ)
582
struct nv50_surface *ns = nv50_surface_from_miptree(nv50_miptree(pt), templ);
585
ns->base.context = pipe;