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