Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nv30/nv30_miptree.c
4574 views
1
/*
2
* Copyright 2012 Red Hat Inc.
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
* Authors: Ben Skeggs
23
*
24
*/
25
26
#include "util/format/u_format.h"
27
#include "util/u_inlines.h"
28
#include "util/u_surface.h"
29
30
#include "nv_m2mf.xml.h"
31
#include "nv_object.xml.h"
32
#include "nv30/nv30_screen.h"
33
#include "nv30/nv30_context.h"
34
#include "nv30/nv30_resource.h"
35
#include "nv30/nv30_transfer.h"
36
37
static inline unsigned
38
layer_offset(struct pipe_resource *pt, unsigned level, unsigned layer)
39
{
40
struct nv30_miptree *mt = nv30_miptree(pt);
41
struct nv30_miptree_level *lvl = &mt->level[level];
42
43
if (pt->target == PIPE_TEXTURE_CUBE)
44
return (layer * mt->layer_size) + lvl->offset;
45
46
return lvl->offset + (layer * lvl->zslice_size);
47
}
48
49
bool
50
nv30_miptree_get_handle(struct pipe_screen *pscreen,
51
struct pipe_context *context,
52
struct pipe_resource *pt,
53
struct winsys_handle *handle,
54
unsigned usage)
55
{
56
if (pt->target == PIPE_BUFFER)
57
return false;
58
59
struct nv30_miptree *mt = nv30_miptree(pt);
60
unsigned stride;
61
62
if (!mt || !mt->base.bo)
63
return false;
64
65
stride = mt->level[0].pitch;
66
67
return nouveau_screen_bo_get_handle(pscreen, mt->base.bo, stride, handle);
68
}
69
70
void
71
nv30_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt)
72
{
73
struct nv30_miptree *mt = nv30_miptree(pt);
74
75
nouveau_bo_ref(NULL, &mt->base.bo);
76
FREE(mt);
77
}
78
79
struct nv30_transfer {
80
struct pipe_transfer base;
81
struct nv30_rect img;
82
struct nv30_rect tmp;
83
unsigned nblocksx;
84
unsigned nblocksy;
85
};
86
87
static inline struct nv30_transfer *
88
nv30_transfer(struct pipe_transfer *ptx)
89
{
90
return (struct nv30_transfer *)ptx;
91
}
92
93
static inline void
94
define_rect(struct pipe_resource *pt, unsigned level, unsigned z,
95
unsigned x, unsigned y, unsigned w, unsigned h,
96
struct nv30_rect *rect)
97
{
98
struct nv30_miptree *mt = nv30_miptree(pt);
99
struct nv30_miptree_level *lvl = &mt->level[level];
100
101
rect->w = u_minify(pt->width0, level) << mt->ms_x;
102
rect->w = util_format_get_nblocksx(pt->format, rect->w);
103
rect->h = u_minify(pt->height0, level) << mt->ms_y;
104
rect->h = util_format_get_nblocksy(pt->format, rect->h);
105
rect->d = 1;
106
rect->z = 0;
107
if (mt->swizzled) {
108
if (pt->target == PIPE_TEXTURE_3D) {
109
rect->d = u_minify(pt->depth0, level);
110
rect->z = z; z = 0;
111
}
112
rect->pitch = 0;
113
} else {
114
rect->pitch = lvl->pitch;
115
}
116
117
rect->bo = mt->base.bo;
118
rect->domain = NOUVEAU_BO_VRAM;
119
rect->offset = layer_offset(pt, level, z);
120
rect->cpp = util_format_get_blocksize(pt->format);
121
122
rect->x0 = util_format_get_nblocksx(pt->format, x) << mt->ms_x;
123
rect->y0 = util_format_get_nblocksy(pt->format, y) << mt->ms_y;
124
rect->x1 = rect->x0 + (util_format_get_nblocksx(pt->format, w) << mt->ms_x);
125
rect->y1 = rect->y0 + (util_format_get_nblocksy(pt->format, h) << mt->ms_y);
126
127
/* XXX There's some indication that swizzled formats > 4 bytes are treated
128
* differently. However that only applies to RGBA16_FLOAT, RGBA32_FLOAT,
129
* and the DXT* formats. The former aren't properly supported yet, and the
130
* latter avoid swizzled layouts.
131
132
if (mt->swizzled && rect->cpp > 4) {
133
unsigned scale = rect->cpp / 4;
134
rect->w *= scale;
135
rect->x0 *= scale;
136
rect->x1 *= scale;
137
rect->cpp = 4;
138
}
139
*/
140
}
141
142
void
143
nv30_resource_copy_region(struct pipe_context *pipe,
144
struct pipe_resource *dstres, unsigned dst_level,
145
unsigned dstx, unsigned dsty, unsigned dstz,
146
struct pipe_resource *srcres, unsigned src_level,
147
const struct pipe_box *src_box)
148
{
149
struct nv30_context *nv30 = nv30_context(pipe);
150
struct nv30_rect src, dst;
151
152
if (dstres->target == PIPE_BUFFER && srcres->target == PIPE_BUFFER) {
153
nouveau_copy_buffer(&nv30->base,
154
nv04_resource(dstres), dstx,
155
nv04_resource(srcres), src_box->x, src_box->width);
156
return;
157
}
158
159
define_rect(srcres, src_level, src_box->z, src_box->x, src_box->y,
160
src_box->width, src_box->height, &src);
161
define_rect(dstres, dst_level, dstz, dstx, dsty,
162
src_box->width, src_box->height, &dst);
163
164
nv30_transfer_rect(nv30, NEAREST, &src, &dst);
165
}
166
167
static void
168
nv30_resource_resolve(struct nv30_context *nv30,
169
const struct pipe_blit_info *info)
170
{
171
struct nv30_miptree *src_mt = nv30_miptree(info->src.resource);
172
struct nv30_rect src, dst;
173
unsigned x, x0, x1, y, y1, w, h;
174
175
define_rect(info->src.resource, 0, info->src.box.z, info->src.box.x,
176
info->src.box.y, info->src.box.width, info->src.box.height, &src);
177
define_rect(info->dst.resource, 0, info->dst.box.z, info->dst.box.x,
178
info->dst.box.y, info->dst.box.width, info->dst.box.height, &dst);
179
180
x0 = src.x0;
181
x1 = src.x1;
182
y1 = src.y1;
183
184
/* On nv3x we must use sifm which is restricted to 1024x1024 tiles */
185
for (y = src.y0; y < y1; y += h) {
186
h = y1 - y;
187
if (h > 1024)
188
h = 1024;
189
190
src.y0 = 0;
191
src.y1 = h;
192
src.h = h;
193
194
dst.y1 = dst.y0 + (h >> src_mt->ms_y);
195
dst.h = h >> src_mt->ms_y;
196
197
for (x = x0; x < x1; x += w) {
198
w = x1 - x;
199
if (w > 1024)
200
w = 1024;
201
202
src.offset = y * src.pitch + x * src.cpp;
203
src.x0 = 0;
204
src.x1 = w;
205
src.w = w;
206
207
dst.offset = (y >> src_mt->ms_y) * dst.pitch +
208
(x >> src_mt->ms_x) * dst.cpp;
209
dst.x1 = dst.x0 + (w >> src_mt->ms_x);
210
dst.w = w >> src_mt->ms_x;
211
212
nv30_transfer_rect(nv30, BILINEAR, &src, &dst);
213
}
214
}
215
}
216
217
void
218
nv30_blit(struct pipe_context *pipe,
219
const struct pipe_blit_info *blit_info)
220
{
221
struct nv30_context *nv30 = nv30_context(pipe);
222
struct pipe_blit_info info = *blit_info;
223
224
if (info.src.resource->nr_samples > 1 &&
225
info.dst.resource->nr_samples <= 1 &&
226
!util_format_is_depth_or_stencil(info.src.resource->format) &&
227
!util_format_is_pure_integer(info.src.resource->format)) {
228
nv30_resource_resolve(nv30, blit_info);
229
return;
230
}
231
232
if (util_try_blit_via_copy_region(pipe, &info)) {
233
return; /* done */
234
}
235
236
if (info.mask & PIPE_MASK_S) {
237
debug_printf("nv30: cannot blit stencil, skipping\n");
238
info.mask &= ~PIPE_MASK_S;
239
}
240
241
if (!util_blitter_is_blit_supported(nv30->blitter, &info)) {
242
debug_printf("nv30: blit unsupported %s -> %s\n",
243
util_format_short_name(info.src.resource->format),
244
util_format_short_name(info.dst.resource->format));
245
return;
246
}
247
248
/* XXX turn off occlusion queries */
249
250
util_blitter_save_vertex_buffer_slot(nv30->blitter, nv30->vtxbuf);
251
util_blitter_save_vertex_elements(nv30->blitter, nv30->vertex);
252
util_blitter_save_vertex_shader(nv30->blitter, nv30->vertprog.program);
253
util_blitter_save_rasterizer(nv30->blitter, nv30->rast);
254
util_blitter_save_viewport(nv30->blitter, &nv30->viewport);
255
util_blitter_save_scissor(nv30->blitter, &nv30->scissor);
256
util_blitter_save_fragment_shader(nv30->blitter, nv30->fragprog.program);
257
util_blitter_save_blend(nv30->blitter, nv30->blend);
258
util_blitter_save_depth_stencil_alpha(nv30->blitter,
259
nv30->zsa);
260
util_blitter_save_stencil_ref(nv30->blitter, &nv30->stencil_ref);
261
util_blitter_save_sample_mask(nv30->blitter, nv30->sample_mask);
262
util_blitter_save_framebuffer(nv30->blitter, &nv30->framebuffer);
263
util_blitter_save_fragment_sampler_states(nv30->blitter,
264
nv30->fragprog.num_samplers,
265
(void**)nv30->fragprog.samplers);
266
util_blitter_save_fragment_sampler_views(nv30->blitter,
267
nv30->fragprog.num_textures, nv30->fragprog.textures);
268
util_blitter_save_render_condition(nv30->blitter, nv30->render_cond_query,
269
nv30->render_cond_cond, nv30->render_cond_mode);
270
util_blitter_blit(nv30->blitter, &info);
271
}
272
273
void
274
nv30_flush_resource(struct pipe_context *pipe,
275
struct pipe_resource *resource)
276
{
277
}
278
279
void *
280
nv30_miptree_transfer_map(struct pipe_context *pipe, struct pipe_resource *pt,
281
unsigned level, unsigned usage,
282
const struct pipe_box *box,
283
struct pipe_transfer **ptransfer)
284
{
285
struct nv30_context *nv30 = nv30_context(pipe);
286
struct nouveau_device *dev = nv30->screen->base.device;
287
struct nv30_miptree *mt = nv30_miptree(pt);
288
struct nv30_transfer *tx;
289
unsigned access = 0;
290
int ret;
291
292
tx = CALLOC_STRUCT(nv30_transfer);
293
if (!tx)
294
return NULL;
295
pipe_resource_reference(&tx->base.resource, pt);
296
tx->base.level = level;
297
tx->base.usage = usage;
298
tx->base.box = *box;
299
tx->base.stride = align(util_format_get_nblocksx(pt->format, box->width) *
300
util_format_get_blocksize(pt->format), 64);
301
tx->base.layer_stride = util_format_get_nblocksy(pt->format, box->height) *
302
tx->base.stride;
303
304
tx->nblocksx = util_format_get_nblocksx(pt->format, box->width);
305
tx->nblocksy = util_format_get_nblocksy(pt->format, box->height);
306
307
define_rect(pt, level, box->z, box->x, box->y,
308
box->width, box->height, &tx->img);
309
310
ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
311
tx->base.layer_stride * tx->base.box.depth, NULL,
312
&tx->tmp.bo);
313
if (ret) {
314
pipe_resource_reference(&tx->base.resource, NULL);
315
FREE(tx);
316
return NULL;
317
}
318
319
tx->tmp.domain = NOUVEAU_BO_GART;
320
tx->tmp.offset = 0;
321
tx->tmp.pitch = tx->base.stride;
322
tx->tmp.cpp = tx->img.cpp;
323
tx->tmp.w = tx->nblocksx;
324
tx->tmp.h = tx->nblocksy;
325
tx->tmp.d = 1;
326
tx->tmp.x0 = 0;
327
tx->tmp.y0 = 0;
328
tx->tmp.x1 = tx->tmp.w;
329
tx->tmp.y1 = tx->tmp.h;
330
tx->tmp.z = 0;
331
332
if (usage & PIPE_MAP_READ) {
333
bool is_3d = mt->base.base.target == PIPE_TEXTURE_3D;
334
unsigned offset = tx->img.offset;
335
unsigned z = tx->img.z;
336
unsigned i;
337
for (i = 0; i < box->depth; ++i) {
338
nv30_transfer_rect(nv30, NEAREST, &tx->img, &tx->tmp);
339
if (is_3d && mt->swizzled)
340
tx->img.z++;
341
else if (is_3d)
342
tx->img.offset += mt->level[level].zslice_size;
343
else
344
tx->img.offset += mt->layer_size;
345
tx->tmp.offset += tx->base.layer_stride;
346
}
347
tx->img.z = z;
348
tx->img.offset = offset;
349
tx->tmp.offset = 0;
350
}
351
352
if (tx->tmp.bo->map) {
353
*ptransfer = &tx->base;
354
return tx->tmp.bo->map;
355
}
356
357
if (usage & PIPE_MAP_READ)
358
access |= NOUVEAU_BO_RD;
359
if (usage & PIPE_MAP_WRITE)
360
access |= NOUVEAU_BO_WR;
361
362
ret = nouveau_bo_map(tx->tmp.bo, access, nv30->base.client);
363
if (ret) {
364
pipe_resource_reference(&tx->base.resource, NULL);
365
FREE(tx);
366
return NULL;
367
}
368
369
*ptransfer = &tx->base;
370
return tx->tmp.bo->map;
371
}
372
373
void
374
nv30_miptree_transfer_unmap(struct pipe_context *pipe,
375
struct pipe_transfer *ptx)
376
{
377
struct nv30_context *nv30 = nv30_context(pipe);
378
struct nv30_transfer *tx = nv30_transfer(ptx);
379
struct nv30_miptree *mt = nv30_miptree(tx->base.resource);
380
unsigned i;
381
382
if (ptx->usage & PIPE_MAP_WRITE) {
383
bool is_3d = mt->base.base.target == PIPE_TEXTURE_3D;
384
for (i = 0; i < tx->base.box.depth; ++i) {
385
nv30_transfer_rect(nv30, NEAREST, &tx->tmp, &tx->img);
386
if (is_3d && mt->swizzled)
387
tx->img.z++;
388
else if (is_3d)
389
tx->img.offset += mt->level[tx->base.level].zslice_size;
390
else
391
tx->img.offset += mt->layer_size;
392
tx->tmp.offset += tx->base.layer_stride;
393
}
394
395
/* Allow the copies above to finish executing before freeing the source */
396
nouveau_fence_work(nv30->screen->base.fence.current,
397
nouveau_fence_unref_bo, tx->tmp.bo);
398
} else {
399
nouveau_bo_ref(NULL, &tx->tmp.bo);
400
}
401
pipe_resource_reference(&ptx->resource, NULL);
402
FREE(tx);
403
}
404
405
struct pipe_resource *
406
nv30_miptree_create(struct pipe_screen *pscreen,
407
const struct pipe_resource *tmpl)
408
{
409
struct nouveau_device *dev = nouveau_screen(pscreen)->device;
410
struct nv30_miptree *mt = CALLOC_STRUCT(nv30_miptree);
411
struct pipe_resource *pt = &mt->base.base;
412
unsigned blocksz, size;
413
unsigned w, h, d, l;
414
int ret;
415
416
switch (tmpl->nr_samples) {
417
case 4:
418
mt->ms_mode = 0x00004000;
419
mt->ms_x = 1;
420
mt->ms_y = 1;
421
break;
422
case 2:
423
mt->ms_mode = 0x00003000;
424
mt->ms_x = 1;
425
mt->ms_y = 0;
426
break;
427
default:
428
mt->ms_mode = 0x00000000;
429
mt->ms_x = 0;
430
mt->ms_y = 0;
431
break;
432
}
433
434
*pt = *tmpl;
435
pipe_reference_init(&pt->reference, 1);
436
pt->screen = pscreen;
437
438
w = pt->width0 << mt->ms_x;
439
h = pt->height0 << mt->ms_y;
440
d = (pt->target == PIPE_TEXTURE_3D) ? pt->depth0 : 1;
441
blocksz = util_format_get_blocksize(pt->format);
442
443
if ((pt->target == PIPE_TEXTURE_RECT) ||
444
(pt->bind & PIPE_BIND_SCANOUT) ||
445
!util_is_power_of_two_or_zero(pt->width0) ||
446
!util_is_power_of_two_or_zero(pt->height0) ||
447
!util_is_power_of_two_or_zero(pt->depth0) ||
448
mt->ms_mode) {
449
mt->uniform_pitch = util_format_get_nblocksx(pt->format, w) * blocksz;
450
mt->uniform_pitch = align(mt->uniform_pitch, 64);
451
if (pt->bind & PIPE_BIND_SCANOUT) {
452
struct nv30_screen *screen = nv30_screen(pscreen);
453
int pitch_align = MAX2(
454
screen->eng3d->oclass >= NV40_3D_CLASS ? 1024 : 256,
455
/* round_down_pow2(mt->uniform_pitch / 4) */
456
1 << (util_last_bit(mt->uniform_pitch / 4) - 1));
457
mt->uniform_pitch = align(mt->uniform_pitch, pitch_align);
458
}
459
}
460
461
if (util_format_is_compressed(pt->format)) {
462
// Compressed (DXT) formats are packed tightly. We don't mark them as
463
// swizzled, since their layout is largely linear. However we do end up
464
// omitting the LINEAR flag when texturing them, as the levels are not
465
// uniformly sized (for POT sizes).
466
} else if (!mt->uniform_pitch) {
467
mt->swizzled = true;
468
}
469
470
size = 0;
471
for (l = 0; l <= pt->last_level; l++) {
472
struct nv30_miptree_level *lvl = &mt->level[l];
473
unsigned nbx = util_format_get_nblocksx(pt->format, w);
474
unsigned nby = util_format_get_nblocksy(pt->format, h);
475
476
lvl->offset = size;
477
lvl->pitch = mt->uniform_pitch;
478
if (!lvl->pitch)
479
lvl->pitch = nbx * blocksz;
480
481
lvl->zslice_size = lvl->pitch * nby;
482
size += lvl->zslice_size * d;
483
484
w = u_minify(w, 1);
485
h = u_minify(h, 1);
486
d = u_minify(d, 1);
487
}
488
489
mt->layer_size = size;
490
if (pt->target == PIPE_TEXTURE_CUBE) {
491
if (!mt->uniform_pitch)
492
mt->layer_size = align(mt->layer_size, 128);
493
size = mt->layer_size * 6;
494
}
495
496
ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 256, size, NULL, &mt->base.bo);
497
if (ret) {
498
FREE(mt);
499
return NULL;
500
}
501
502
mt->base.domain = NOUVEAU_BO_VRAM;
503
return &mt->base.base;
504
}
505
506
struct pipe_resource *
507
nv30_miptree_from_handle(struct pipe_screen *pscreen,
508
const struct pipe_resource *tmpl,
509
struct winsys_handle *handle)
510
{
511
struct nv30_miptree *mt;
512
unsigned stride;
513
514
/* only supports 2D, non-mipmapped textures for the moment */
515
if ((tmpl->target != PIPE_TEXTURE_2D &&
516
tmpl->target != PIPE_TEXTURE_RECT) ||
517
tmpl->last_level != 0 ||
518
tmpl->depth0 != 1 ||
519
tmpl->array_size > 1)
520
return NULL;
521
522
mt = CALLOC_STRUCT(nv30_miptree);
523
if (!mt)
524
return NULL;
525
526
mt->base.bo = nouveau_screen_bo_from_handle(pscreen, handle, &stride);
527
if (mt->base.bo == NULL) {
528
FREE(mt);
529
return NULL;
530
}
531
532
mt->base.base = *tmpl;
533
pipe_reference_init(&mt->base.base.reference, 1);
534
mt->base.base.screen = pscreen;
535
mt->uniform_pitch = stride;
536
mt->level[0].pitch = mt->uniform_pitch;
537
mt->level[0].offset = 0;
538
539
/* no need to adjust bo reference count */
540
return &mt->base.base;
541
}
542
543
struct pipe_surface *
544
nv30_miptree_surface_new(struct pipe_context *pipe,
545
struct pipe_resource *pt,
546
const struct pipe_surface *tmpl)
547
{
548
struct nv30_miptree *mt = nv30_miptree(pt); /* guaranteed */
549
struct nv30_surface *ns;
550
struct pipe_surface *ps;
551
struct nv30_miptree_level *lvl = &mt->level[tmpl->u.tex.level];
552
553
ns = CALLOC_STRUCT(nv30_surface);
554
if (!ns)
555
return NULL;
556
ps = &ns->base;
557
558
pipe_reference_init(&ps->reference, 1);
559
pipe_resource_reference(&ps->texture, pt);
560
ps->context = pipe;
561
ps->format = tmpl->format;
562
ps->u.tex.level = tmpl->u.tex.level;
563
ps->u.tex.first_layer = tmpl->u.tex.first_layer;
564
ps->u.tex.last_layer = tmpl->u.tex.last_layer;
565
566
ns->width = u_minify(pt->width0, ps->u.tex.level);
567
ns->height = u_minify(pt->height0, ps->u.tex.level);
568
ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;
569
ns->offset = layer_offset(pt, ps->u.tex.level, ps->u.tex.first_layer);
570
if (mt->swizzled)
571
ns->pitch = 4096; /* random, just something the hw won't reject.. */
572
else
573
ns->pitch = lvl->pitch;
574
575
/* comment says there are going to be removed, but they're used by the st */
576
ps->width = ns->width;
577
ps->height = ns->height;
578
return ps;
579
}
580
581
void
582
nv30_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps)
583
{
584
struct nv30_surface *ns = nv30_surface(ps);
585
586
pipe_resource_reference(&ps->texture, NULL);
587
FREE(ns);
588
}
589
590