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
+ (w
<< mt
->ms_x
);
120 rect
->y1
= rect
->y0
+ (h
<< mt
->ms_y
);
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
)
130 struct nv30_context
*nv30
= nv30_context(pipe
);
131 struct nv30_rect src
, dst
;
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
);
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
);
145 nv30_transfer_rect(nv30
, NEAREST
, &src
, &dst
);
149 nv30_resource_resolve(struct nv30_context
*nv30
,
150 const struct pipe_blit_info
*info
)
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
;
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
);
165 /* On nv3x we must use sifm which is restricted to 1024x1024 tiles */
166 for (y
= src
.y0
; y
< y1
; y
+= h
) {
175 dst
.y1
= dst
.y0
+ (h
>> src_mt
->ms_y
);
176 dst
.h
= h
>> src_mt
->ms_y
;
178 for (x
= x0
; x
< x1
; x
+= w
) {
183 src
.offset
= y
* src
.pitch
+ x
* src
.cpp
;
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
;
193 nv30_transfer_rect(nv30
, BILINEAR
, &src
, &dst
);
199 nv30_blit(struct pipe_context
*pipe
,
200 const struct pipe_blit_info
*blit_info
)
202 struct nv30_context
*nv30
= nv30_context(pipe
);
203 struct pipe_blit_info info
= *blit_info
;
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
);
213 if (util_try_blit_via_copy_region(pipe
, &info
)) {
217 if (info
.mask
& PIPE_MASK_S
) {
218 debug_printf("nv30: cannot blit stencil, skipping\n");
219 info
.mask
&= ~PIPE_MASK_S
;
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
));
229 /* XXX turn off occlusion queries */
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
,
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
);
255 nv30_flush_resource(struct pipe_context
*pipe
,
256 struct pipe_resource
*resource
)
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
)
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
;
273 tx
= CALLOC_STRUCT(nv30_transfer
);
276 pipe_resource_reference(&tx
->base
.resource
, pt
);
277 tx
->base
.level
= level
;
278 tx
->base
.usage
= usage
;
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
) *
285 tx
->nblocksx
= util_format_get_nblocksx(pt
->format
, box
->width
);
286 tx
->nblocksy
= util_format_get_nblocksy(pt
->format
, box
->height
);
288 define_rect(pt
, level
, box
->z
, box
->x
, box
->y
,
289 tx
->nblocksx
, tx
->nblocksy
, &tx
->img
);
291 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_GART
| NOUVEAU_BO_MAP
, 0,
292 tx
->base
.layer_stride
* tx
->base
.box
.depth
, NULL
,
295 pipe_resource_reference(&tx
->base
.resource
, NULL
);
300 tx
->tmp
.domain
= NOUVEAU_BO_GART
;
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
;
309 tx
->tmp
.x1
= tx
->tmp
.w
;
310 tx
->tmp
.y1
= tx
->tmp
.h
;
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
;
318 for (i
= 0; i
< box
->depth
; ++i
) {
319 nv30_transfer_rect(nv30
, NEAREST
, &tx
->img
, &tx
->tmp
);
320 if (is_3d
&& mt
->swizzled
)
323 tx
->img
.offset
+= mt
->level
[level
].zslice_size
;
325 tx
->img
.offset
+= mt
->layer_size
;
326 tx
->tmp
.offset
+= tx
->base
.layer_stride
;
329 tx
->img
.offset
= offset
;
333 if (tx
->tmp
.bo
->map
) {
334 *ptransfer
= &tx
->base
;
335 return tx
->tmp
.bo
->map
;
338 if (usage
& PIPE_TRANSFER_READ
)
339 access
|= NOUVEAU_BO_RD
;
340 if (usage
& PIPE_TRANSFER_WRITE
)
341 access
|= NOUVEAU_BO_WR
;
343 ret
= nouveau_bo_map(tx
->tmp
.bo
, access
, nv30
->base
.client
);
345 pipe_resource_reference(&tx
->base
.resource
, NULL
);
350 *ptransfer
= &tx
->base
;
351 return tx
->tmp
.bo
->map
;
355 nv30_miptree_transfer_unmap(struct pipe_context
*pipe
,
356 struct pipe_transfer
*ptx
)
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
);
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
)
370 tx
->img
.offset
+= mt
->level
[tx
->base
.level
].zslice_size
;
372 tx
->img
.offset
+= mt
->layer_size
;
373 tx
->tmp
.offset
+= tx
->base
.layer_stride
;
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
);
380 nouveau_bo_ref(NULL
, &tx
->tmp
.bo
);
382 pipe_resource_reference(&ptx
->resource
, NULL
);
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
,
394 struct pipe_resource
*
395 nv30_miptree_create(struct pipe_screen
*pscreen
,
396 const struct pipe_resource
*tmpl
)
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
;
405 switch (tmpl
->nr_samples
) {
407 mt
->ms_mode
= 0x00004000;
412 mt
->ms_mode
= 0x00003000;
417 mt
->ms_mode
= 0x00000000;
423 mt
->base
.vtbl
= &nv30_miptree_vtbl
;
425 pipe_reference_init(&pt
->reference
, 1);
426 pt
->screen
= pscreen
;
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
);
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
);
452 if (!mt
->uniform_pitch
)
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
);
462 lvl
->pitch
= mt
->uniform_pitch
;
464 lvl
->pitch
= nbx
* blocksz
;
466 lvl
->zslice_size
= lvl
->pitch
* nby
;
467 size
+= lvl
->zslice_size
* d
;
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;
481 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_VRAM
, 256, size
, NULL
, &mt
->base
.bo
);
487 mt
->base
.domain
= NOUVEAU_BO_VRAM
;
488 return &mt
->base
.base
;
491 struct pipe_resource
*
492 nv30_miptree_from_handle(struct pipe_screen
*pscreen
,
493 const struct pipe_resource
*tmpl
,
494 struct winsys_handle
*handle
)
496 struct nv30_miptree
*mt
;
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 ||
504 tmpl
->array_size
> 1)
507 mt
= CALLOC_STRUCT(nv30_miptree
);
511 mt
->base
.bo
= nouveau_screen_bo_from_handle(pscreen
, handle
, &stride
);
512 if (mt
->base
.bo
== NULL
) {
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;
525 /* no need to adjust bo reference count */
526 return &mt
->base
.base
;
529 struct pipe_surface
*
530 nv30_miptree_surface_new(struct pipe_context
*pipe
,
531 struct pipe_resource
*pt
,
532 const struct pipe_surface
*tmpl
)
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
];
539 ns
= CALLOC_STRUCT(nv30_surface
);
544 pipe_reference_init(&ps
->reference
, 1);
545 pipe_resource_reference(&ps
->texture
, pt
);
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
;
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
);
557 ns
->pitch
= 4096; /* random, just something the hw won't reject.. */
559 ns
->pitch
= lvl
->pitch
;
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
;
568 nv30_miptree_surface_del(struct pipe_context
*pipe
, struct pipe_surface
*ps
)
570 struct nv30_surface
*ns
= nv30_surface(ps
);
572 pipe_resource_reference(&ps
->texture
, NULL
);