2 * Copyright 2012 Red Hat Inc.
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.
26 #include "util/u_format.h"
27 #include "util/u_inlines.h"
28 #include "util/u_surface.h"
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"
37 static inline unsigned
38 layer_offset(struct pipe_resource
*pt
, unsigned level
, unsigned layer
)
40 struct nv30_miptree
*mt
= nv30_miptree(pt
);
41 struct nv30_miptree_level
*lvl
= &mt
->level
[level
];
43 if (pt
->target
== PIPE_TEXTURE_CUBE
)
44 return (layer
* mt
->layer_size
) + lvl
->offset
;
46 return lvl
->offset
+ (layer
* lvl
->zslice_size
);
50 nv30_miptree_get_handle(struct pipe_screen
*pscreen
,
51 struct pipe_resource
*pt
,
52 struct winsys_handle
*handle
)
54 struct nv30_miptree
*mt
= nv30_miptree(pt
);
57 if (!mt
|| !mt
->base
.bo
)
60 stride
= mt
->level
[0].pitch
;
62 return nouveau_screen_bo_get_handle(pscreen
, mt
->base
.bo
, stride
, handle
);
66 nv30_miptree_destroy(struct pipe_screen
*pscreen
, struct pipe_resource
*pt
)
68 struct nv30_miptree
*mt
= nv30_miptree(pt
);
70 nouveau_bo_ref(NULL
, &mt
->base
.bo
);
74 struct nv30_transfer
{
75 struct pipe_transfer base
;
82 static inline struct nv30_transfer
*
83 nv30_transfer(struct pipe_transfer
*ptx
)
85 return (struct nv30_transfer
*)ptx
;
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
)
93 struct nv30_miptree
*mt
= nv30_miptree(pt
);
94 struct nv30_miptree_level
*lvl
= &mt
->level
[level
];
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
);
103 if (pt
->target
== PIPE_TEXTURE_3D
) {
104 rect
->d
= u_minify(pt
->depth0
, level
);
109 rect
->pitch
= lvl
->pitch
;
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
);
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
+ (util_format_get_nblocksx(pt
->format
, w
) << mt
->ms_x
);
120 rect
->y1
= rect
->y0
+ (util_format_get_nblocksy(pt
->format
, h
) << mt
->ms_y
);
122 /* XXX There's some indication that swizzled formats > 4 bytes are treated
123 * differently. However that only applies to RGBA16_FLOAT, RGBA32_FLOAT,
124 * and the DXT* formats. The former aren't properly supported yet, and the
125 * latter avoid swizzled layouts.
127 if (mt->swizzled && rect->cpp > 4) {
128 unsigned scale = rect->cpp / 4;
138 nv30_resource_copy_region(struct pipe_context
*pipe
,
139 struct pipe_resource
*dstres
, unsigned dst_level
,
140 unsigned dstx
, unsigned dsty
, unsigned dstz
,
141 struct pipe_resource
*srcres
, unsigned src_level
,
142 const struct pipe_box
*src_box
)
144 struct nv30_context
*nv30
= nv30_context(pipe
);
145 struct nv30_rect src
, dst
;
147 if (dstres
->target
== PIPE_BUFFER
&& srcres
->target
== PIPE_BUFFER
) {
148 nouveau_copy_buffer(&nv30
->base
,
149 nv04_resource(dstres
), dstx
,
150 nv04_resource(srcres
), src_box
->x
, src_box
->width
);
154 define_rect(srcres
, src_level
, src_box
->z
, src_box
->x
, src_box
->y
,
155 src_box
->width
, src_box
->height
, &src
);
156 define_rect(dstres
, dst_level
, dstz
, dstx
, dsty
,
157 src_box
->width
, src_box
->height
, &dst
);
159 nv30_transfer_rect(nv30
, NEAREST
, &src
, &dst
);
163 nv30_resource_resolve(struct nv30_context
*nv30
,
164 const struct pipe_blit_info
*info
)
166 struct nv30_miptree
*src_mt
= nv30_miptree(info
->src
.resource
);
167 struct nv30_rect src
, dst
;
168 unsigned x
, x0
, x1
, y
, y1
, w
, h
;
170 define_rect(info
->src
.resource
, 0, info
->src
.box
.z
, info
->src
.box
.x
,
171 info
->src
.box
.y
, info
->src
.box
.width
, info
->src
.box
.height
, &src
);
172 define_rect(info
->dst
.resource
, 0, info
->dst
.box
.z
, info
->dst
.box
.x
,
173 info
->dst
.box
.y
, info
->dst
.box
.width
, info
->dst
.box
.height
, &dst
);
179 /* On nv3x we must use sifm which is restricted to 1024x1024 tiles */
180 for (y
= src
.y0
; y
< y1
; y
+= h
) {
189 dst
.y1
= dst
.y0
+ (h
>> src_mt
->ms_y
);
190 dst
.h
= h
>> src_mt
->ms_y
;
192 for (x
= x0
; x
< x1
; x
+= w
) {
197 src
.offset
= y
* src
.pitch
+ x
* src
.cpp
;
202 dst
.offset
= (y
>> src_mt
->ms_y
) * dst
.pitch
+
203 (x
>> src_mt
->ms_x
) * dst
.cpp
;
204 dst
.x1
= dst
.x0
+ (w
>> src_mt
->ms_x
);
205 dst
.w
= w
>> src_mt
->ms_x
;
207 nv30_transfer_rect(nv30
, BILINEAR
, &src
, &dst
);
213 nv30_blit(struct pipe_context
*pipe
,
214 const struct pipe_blit_info
*blit_info
)
216 struct nv30_context
*nv30
= nv30_context(pipe
);
217 struct pipe_blit_info info
= *blit_info
;
219 if (info
.src
.resource
->nr_samples
> 1 &&
220 info
.dst
.resource
->nr_samples
<= 1 &&
221 !util_format_is_depth_or_stencil(info
.src
.resource
->format
) &&
222 !util_format_is_pure_integer(info
.src
.resource
->format
)) {
223 nv30_resource_resolve(nv30
, blit_info
);
227 if (util_try_blit_via_copy_region(pipe
, &info
)) {
231 if (info
.mask
& PIPE_MASK_S
) {
232 debug_printf("nv30: cannot blit stencil, skipping\n");
233 info
.mask
&= ~PIPE_MASK_S
;
236 if (!util_blitter_is_blit_supported(nv30
->blitter
, &info
)) {
237 debug_printf("nv30: blit unsupported %s -> %s\n",
238 util_format_short_name(info
.src
.resource
->format
),
239 util_format_short_name(info
.dst
.resource
->format
));
243 /* XXX turn off occlusion queries */
245 util_blitter_save_vertex_buffer_slot(nv30
->blitter
, nv30
->vtxbuf
);
246 util_blitter_save_vertex_elements(nv30
->blitter
, nv30
->vertex
);
247 util_blitter_save_vertex_shader(nv30
->blitter
, nv30
->vertprog
.program
);
248 util_blitter_save_rasterizer(nv30
->blitter
, nv30
->rast
);
249 util_blitter_save_viewport(nv30
->blitter
, &nv30
->viewport
);
250 util_blitter_save_scissor(nv30
->blitter
, &nv30
->scissor
);
251 util_blitter_save_fragment_shader(nv30
->blitter
, nv30
->fragprog
.program
);
252 util_blitter_save_blend(nv30
->blitter
, nv30
->blend
);
253 util_blitter_save_depth_stencil_alpha(nv30
->blitter
,
255 util_blitter_save_stencil_ref(nv30
->blitter
, &nv30
->stencil_ref
);
256 util_blitter_save_sample_mask(nv30
->blitter
, nv30
->sample_mask
);
257 util_blitter_save_framebuffer(nv30
->blitter
, &nv30
->framebuffer
);
258 util_blitter_save_fragment_sampler_states(nv30
->blitter
,
259 nv30
->fragprog
.num_samplers
,
260 (void**)nv30
->fragprog
.samplers
);
261 util_blitter_save_fragment_sampler_views(nv30
->blitter
,
262 nv30
->fragprog
.num_textures
, nv30
->fragprog
.textures
);
263 util_blitter_save_render_condition(nv30
->blitter
, nv30
->render_cond_query
,
264 nv30
->render_cond_cond
, nv30
->render_cond_mode
);
265 util_blitter_blit(nv30
->blitter
, &info
);
269 nv30_flush_resource(struct pipe_context
*pipe
,
270 struct pipe_resource
*resource
)
275 nv30_miptree_transfer_map(struct pipe_context
*pipe
, struct pipe_resource
*pt
,
276 unsigned level
, unsigned usage
,
277 const struct pipe_box
*box
,
278 struct pipe_transfer
**ptransfer
)
280 struct nv30_context
*nv30
= nv30_context(pipe
);
281 struct nouveau_device
*dev
= nv30
->screen
->base
.device
;
282 struct nv30_miptree
*mt
= nv30_miptree(pt
);
283 struct nv30_transfer
*tx
;
287 tx
= CALLOC_STRUCT(nv30_transfer
);
290 pipe_resource_reference(&tx
->base
.resource
, pt
);
291 tx
->base
.level
= level
;
292 tx
->base
.usage
= usage
;
294 tx
->base
.stride
= align(util_format_get_nblocksx(pt
->format
, box
->width
) *
295 util_format_get_blocksize(pt
->format
), 64);
296 tx
->base
.layer_stride
= util_format_get_nblocksy(pt
->format
, box
->height
) *
299 tx
->nblocksx
= util_format_get_nblocksx(pt
->format
, box
->width
);
300 tx
->nblocksy
= util_format_get_nblocksy(pt
->format
, box
->height
);
302 define_rect(pt
, level
, box
->z
, box
->x
, box
->y
,
303 box
->width
, box
->height
, &tx
->img
);
305 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_GART
| NOUVEAU_BO_MAP
, 0,
306 tx
->base
.layer_stride
* tx
->base
.box
.depth
, NULL
,
309 pipe_resource_reference(&tx
->base
.resource
, NULL
);
314 tx
->tmp
.domain
= NOUVEAU_BO_GART
;
316 tx
->tmp
.pitch
= tx
->base
.stride
;
317 tx
->tmp
.cpp
= tx
->img
.cpp
;
318 tx
->tmp
.w
= tx
->nblocksx
;
319 tx
->tmp
.h
= tx
->nblocksy
;
323 tx
->tmp
.x1
= tx
->tmp
.w
;
324 tx
->tmp
.y1
= tx
->tmp
.h
;
327 if (usage
& PIPE_TRANSFER_READ
) {
328 bool is_3d
= mt
->base
.base
.target
== PIPE_TEXTURE_3D
;
329 unsigned offset
= tx
->img
.offset
;
330 unsigned z
= tx
->img
.z
;
332 for (i
= 0; i
< box
->depth
; ++i
) {
333 nv30_transfer_rect(nv30
, NEAREST
, &tx
->img
, &tx
->tmp
);
334 if (is_3d
&& mt
->swizzled
)
337 tx
->img
.offset
+= mt
->level
[level
].zslice_size
;
339 tx
->img
.offset
+= mt
->layer_size
;
340 tx
->tmp
.offset
+= tx
->base
.layer_stride
;
343 tx
->img
.offset
= offset
;
347 if (tx
->tmp
.bo
->map
) {
348 *ptransfer
= &tx
->base
;
349 return tx
->tmp
.bo
->map
;
352 if (usage
& PIPE_TRANSFER_READ
)
353 access
|= NOUVEAU_BO_RD
;
354 if (usage
& PIPE_TRANSFER_WRITE
)
355 access
|= NOUVEAU_BO_WR
;
357 ret
= nouveau_bo_map(tx
->tmp
.bo
, access
, nv30
->base
.client
);
359 pipe_resource_reference(&tx
->base
.resource
, NULL
);
364 *ptransfer
= &tx
->base
;
365 return tx
->tmp
.bo
->map
;
369 nv30_miptree_transfer_unmap(struct pipe_context
*pipe
,
370 struct pipe_transfer
*ptx
)
372 struct nv30_context
*nv30
= nv30_context(pipe
);
373 struct nv30_transfer
*tx
= nv30_transfer(ptx
);
374 struct nv30_miptree
*mt
= nv30_miptree(tx
->base
.resource
);
377 if (ptx
->usage
& PIPE_TRANSFER_WRITE
) {
378 bool is_3d
= mt
->base
.base
.target
== PIPE_TEXTURE_3D
;
379 for (i
= 0; i
< tx
->base
.box
.depth
; ++i
) {
380 nv30_transfer_rect(nv30
, NEAREST
, &tx
->tmp
, &tx
->img
);
381 if (is_3d
&& mt
->swizzled
)
384 tx
->img
.offset
+= mt
->level
[tx
->base
.level
].zslice_size
;
386 tx
->img
.offset
+= mt
->layer_size
;
387 tx
->tmp
.offset
+= tx
->base
.layer_stride
;
390 /* Allow the copies above to finish executing before freeing the source */
391 nouveau_fence_work(nv30
->screen
->base
.fence
.current
,
392 nouveau_fence_unref_bo
, tx
->tmp
.bo
);
394 nouveau_bo_ref(NULL
, &tx
->tmp
.bo
);
396 pipe_resource_reference(&ptx
->resource
, NULL
);
400 const struct u_resource_vtbl nv30_miptree_vtbl
= {
401 nv30_miptree_get_handle
,
402 nv30_miptree_destroy
,
403 nv30_miptree_transfer_map
,
404 u_default_transfer_flush_region
,
405 nv30_miptree_transfer_unmap
,
408 struct pipe_resource
*
409 nv30_miptree_create(struct pipe_screen
*pscreen
,
410 const struct pipe_resource
*tmpl
)
412 struct nouveau_device
*dev
= nouveau_screen(pscreen
)->device
;
413 struct nv30_miptree
*mt
= CALLOC_STRUCT(nv30_miptree
);
414 struct pipe_resource
*pt
= &mt
->base
.base
;
415 unsigned blocksz
, size
;
419 switch (tmpl
->nr_samples
) {
421 mt
->ms_mode
= 0x00004000;
426 mt
->ms_mode
= 0x00003000;
431 mt
->ms_mode
= 0x00000000;
437 mt
->base
.vtbl
= &nv30_miptree_vtbl
;
439 pipe_reference_init(&pt
->reference
, 1);
440 pt
->screen
= pscreen
;
442 w
= pt
->width0
<< mt
->ms_x
;
443 h
= pt
->height0
<< mt
->ms_y
;
444 d
= (pt
->target
== PIPE_TEXTURE_3D
) ? pt
->depth0
: 1;
445 blocksz
= util_format_get_blocksize(pt
->format
);
447 if ((pt
->target
== PIPE_TEXTURE_RECT
) ||
448 (pt
->bind
& PIPE_BIND_SCANOUT
) ||
449 !util_is_power_of_two_or_zero(pt
->width0
) ||
450 !util_is_power_of_two_or_zero(pt
->height0
) ||
451 !util_is_power_of_two_or_zero(pt
->depth0
) ||
453 mt
->uniform_pitch
= util_format_get_nblocksx(pt
->format
, w
) * blocksz
;
454 mt
->uniform_pitch
= align(mt
->uniform_pitch
, 64);
455 if (pt
->bind
& PIPE_BIND_SCANOUT
) {
456 struct nv30_screen
*screen
= nv30_screen(pscreen
);
457 int pitch_align
= MAX2(
458 screen
->eng3d
->oclass
>= NV40_3D_CLASS
? 1024 : 256,
459 /* round_down_pow2(mt->uniform_pitch / 4) */
460 1 << (util_last_bit(mt
->uniform_pitch
/ 4) - 1));
461 mt
->uniform_pitch
= align(mt
->uniform_pitch
, pitch_align
);
465 if (util_format_is_compressed(pt
->format
)) {
466 // Compressed (DXT) formats are packed tightly. We don't mark them as
467 // swizzled, since their layout is largely linear. However we do end up
468 // omitting the LINEAR flag when texturing them, as the levels are not
469 // uniformly sized (for POT sizes).
470 } else if (!mt
->uniform_pitch
) {
475 for (l
= 0; l
<= pt
->last_level
; l
++) {
476 struct nv30_miptree_level
*lvl
= &mt
->level
[l
];
477 unsigned nbx
= util_format_get_nblocksx(pt
->format
, w
);
478 unsigned nby
= util_format_get_nblocksy(pt
->format
, h
);
481 lvl
->pitch
= mt
->uniform_pitch
;
483 lvl
->pitch
= nbx
* blocksz
;
485 lvl
->zslice_size
= lvl
->pitch
* nby
;
486 size
+= lvl
->zslice_size
* d
;
493 mt
->layer_size
= size
;
494 if (pt
->target
== PIPE_TEXTURE_CUBE
) {
495 if (!mt
->uniform_pitch
)
496 mt
->layer_size
= align(mt
->layer_size
, 128);
497 size
= mt
->layer_size
* 6;
500 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_VRAM
, 256, size
, NULL
, &mt
->base
.bo
);
506 mt
->base
.domain
= NOUVEAU_BO_VRAM
;
507 return &mt
->base
.base
;
510 struct pipe_resource
*
511 nv30_miptree_from_handle(struct pipe_screen
*pscreen
,
512 const struct pipe_resource
*tmpl
,
513 struct winsys_handle
*handle
)
515 struct nv30_miptree
*mt
;
518 /* only supports 2D, non-mipmapped textures for the moment */
519 if ((tmpl
->target
!= PIPE_TEXTURE_2D
&&
520 tmpl
->target
!= PIPE_TEXTURE_RECT
) ||
521 tmpl
->last_level
!= 0 ||
523 tmpl
->array_size
> 1)
526 mt
= CALLOC_STRUCT(nv30_miptree
);
530 mt
->base
.bo
= nouveau_screen_bo_from_handle(pscreen
, handle
, &stride
);
531 if (mt
->base
.bo
== NULL
) {
536 mt
->base
.base
= *tmpl
;
537 mt
->base
.vtbl
= &nv30_miptree_vtbl
;
538 pipe_reference_init(&mt
->base
.base
.reference
, 1);
539 mt
->base
.base
.screen
= pscreen
;
540 mt
->uniform_pitch
= stride
;
541 mt
->level
[0].pitch
= mt
->uniform_pitch
;
542 mt
->level
[0].offset
= 0;
544 /* no need to adjust bo reference count */
545 return &mt
->base
.base
;
548 struct pipe_surface
*
549 nv30_miptree_surface_new(struct pipe_context
*pipe
,
550 struct pipe_resource
*pt
,
551 const struct pipe_surface
*tmpl
)
553 struct nv30_miptree
*mt
= nv30_miptree(pt
); /* guaranteed */
554 struct nv30_surface
*ns
;
555 struct pipe_surface
*ps
;
556 struct nv30_miptree_level
*lvl
= &mt
->level
[tmpl
->u
.tex
.level
];
558 ns
= CALLOC_STRUCT(nv30_surface
);
563 pipe_reference_init(&ps
->reference
, 1);
564 pipe_resource_reference(&ps
->texture
, pt
);
566 ps
->format
= tmpl
->format
;
567 ps
->u
.tex
.level
= tmpl
->u
.tex
.level
;
568 ps
->u
.tex
.first_layer
= tmpl
->u
.tex
.first_layer
;
569 ps
->u
.tex
.last_layer
= tmpl
->u
.tex
.last_layer
;
571 ns
->width
= u_minify(pt
->width0
, ps
->u
.tex
.level
);
572 ns
->height
= u_minify(pt
->height0
, ps
->u
.tex
.level
);
573 ns
->depth
= ps
->u
.tex
.last_layer
- ps
->u
.tex
.first_layer
+ 1;
574 ns
->offset
= layer_offset(pt
, ps
->u
.tex
.level
, ps
->u
.tex
.first_layer
);
576 ns
->pitch
= 4096; /* random, just something the hw won't reject.. */
578 ns
->pitch
= lvl
->pitch
;
580 /* comment says there are going to be removed, but they're used by the st */
581 ps
->width
= ns
->width
;
582 ps
->height
= ns
->height
;
587 nv30_miptree_surface_del(struct pipe_context
*pipe
, struct pipe_surface
*ps
)
589 struct nv30_surface
*ns
= nv30_surface(ps
);
591 pipe_resource_reference(&ps
->texture
, NULL
);