Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nvc0/nvc0_miptree.c
4574 views
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
}
588
589