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_transfer
*tx
;
272 tx
= CALLOC_STRUCT(nv30_transfer
);
275 pipe_resource_reference(&tx
->base
.resource
, pt
);
276 tx
->base
.level
= level
;
277 tx
->base
.usage
= usage
;
279 tx
->base
.stride
= align(util_format_get_nblocksx(pt
->format
, box
->width
) *
280 util_format_get_blocksize(pt
->format
), 64);
281 tx
->base
.layer_stride
= util_format_get_nblocksy(pt
->format
, box
->height
) *
284 tx
->nblocksx
= util_format_get_nblocksx(pt
->format
, box
->width
);
285 tx
->nblocksy
= util_format_get_nblocksy(pt
->format
, box
->height
);
287 define_rect(pt
, level
, box
->z
, box
->x
, box
->y
,
288 tx
->nblocksx
, tx
->nblocksy
, &tx
->img
);
290 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_GART
| NOUVEAU_BO_MAP
, 0,
291 tx
->base
.layer_stride
, NULL
, &tx
->tmp
.bo
);
293 pipe_resource_reference(&tx
->base
.resource
, NULL
);
298 tx
->tmp
.domain
= NOUVEAU_BO_GART
;
300 tx
->tmp
.pitch
= tx
->base
.stride
;
301 tx
->tmp
.cpp
= tx
->img
.cpp
;
302 tx
->tmp
.w
= tx
->nblocksx
;
303 tx
->tmp
.h
= tx
->nblocksy
;
307 tx
->tmp
.x1
= tx
->tmp
.w
;
308 tx
->tmp
.y1
= tx
->tmp
.h
;
311 if (usage
& PIPE_TRANSFER_READ
)
312 nv30_transfer_rect(nv30
, NEAREST
, &tx
->img
, &tx
->tmp
);
314 if (tx
->tmp
.bo
->map
) {
315 *ptransfer
= &tx
->base
;
316 return tx
->tmp
.bo
->map
;
319 if (usage
& PIPE_TRANSFER_READ
)
320 access
|= NOUVEAU_BO_RD
;
321 if (usage
& PIPE_TRANSFER_WRITE
)
322 access
|= NOUVEAU_BO_WR
;
324 ret
= nouveau_bo_map(tx
->tmp
.bo
, access
, nv30
->base
.client
);
326 pipe_resource_reference(&tx
->base
.resource
, NULL
);
331 *ptransfer
= &tx
->base
;
332 return tx
->tmp
.bo
->map
;
336 nv30_miptree_transfer_unmap(struct pipe_context
*pipe
,
337 struct pipe_transfer
*ptx
)
339 struct nv30_context
*nv30
= nv30_context(pipe
);
340 struct nv30_transfer
*tx
= nv30_transfer(ptx
);
342 if (ptx
->usage
& PIPE_TRANSFER_WRITE
) {
343 nv30_transfer_rect(nv30
, NEAREST
, &tx
->tmp
, &tx
->img
);
345 /* Allow the copies above to finish executing before freeing the source */
346 nouveau_fence_work(nv30
->screen
->base
.fence
.current
,
347 nouveau_fence_unref_bo
, tx
->tmp
.bo
);
349 nouveau_bo_ref(NULL
, &tx
->tmp
.bo
);
351 pipe_resource_reference(&ptx
->resource
, NULL
);
355 const struct u_resource_vtbl nv30_miptree_vtbl
= {
356 nv30_miptree_get_handle
,
357 nv30_miptree_destroy
,
358 nv30_miptree_transfer_map
,
359 u_default_transfer_flush_region
,
360 nv30_miptree_transfer_unmap
,
361 u_default_transfer_inline_write
364 struct pipe_resource
*
365 nv30_miptree_create(struct pipe_screen
*pscreen
,
366 const struct pipe_resource
*tmpl
)
368 struct nouveau_device
*dev
= nouveau_screen(pscreen
)->device
;
369 struct nv30_miptree
*mt
= CALLOC_STRUCT(nv30_miptree
);
370 struct pipe_resource
*pt
= &mt
->base
.base
;
371 unsigned blocksz
, size
;
375 switch (tmpl
->nr_samples
) {
377 mt
->ms_mode
= 0x00004000;
382 mt
->ms_mode
= 0x00003000;
387 mt
->ms_mode
= 0x00000000;
393 mt
->base
.vtbl
= &nv30_miptree_vtbl
;
395 pipe_reference_init(&pt
->reference
, 1);
396 pt
->screen
= pscreen
;
398 w
= pt
->width0
<< mt
->ms_x
;
399 h
= pt
->height0
<< mt
->ms_y
;
400 d
= (pt
->target
== PIPE_TEXTURE_3D
) ? pt
->depth0
: 1;
401 blocksz
= util_format_get_blocksize(pt
->format
);
403 if ((pt
->target
== PIPE_TEXTURE_RECT
) ||
404 (pt
->bind
& PIPE_BIND_SCANOUT
) ||
405 !util_is_power_of_two(pt
->width0
) ||
406 !util_is_power_of_two(pt
->height0
) ||
407 !util_is_power_of_two(pt
->depth0
) ||
408 util_format_is_compressed(pt
->format
) ||
409 util_format_is_float(pt
->format
) || mt
->ms_mode
) {
410 mt
->uniform_pitch
= util_format_get_nblocksx(pt
->format
, w
) * blocksz
;
411 mt
->uniform_pitch
= align(mt
->uniform_pitch
, 64);
412 if (pt
->bind
& PIPE_BIND_SCANOUT
) {
413 struct nv30_screen
*screen
= nv30_screen(pscreen
);
414 int pitch_align
= MAX2(
415 screen
->eng3d
->oclass
>= NV40_3D_CLASS
? 1024 : 256,
416 /* round_down_pow2(mt->uniform_pitch / 4) */
417 1 << (util_last_bit(mt
->uniform_pitch
/ 4) - 1));
418 mt
->uniform_pitch
= align(mt
->uniform_pitch
, pitch_align
);
422 if (!mt
->uniform_pitch
)
426 for (l
= 0; l
<= pt
->last_level
; l
++) {
427 struct nv30_miptree_level
*lvl
= &mt
->level
[l
];
428 unsigned nbx
= util_format_get_nblocksx(pt
->format
, w
);
429 unsigned nby
= util_format_get_nblocksx(pt
->format
, h
);
432 lvl
->pitch
= mt
->uniform_pitch
;
434 lvl
->pitch
= nbx
* blocksz
;
436 lvl
->zslice_size
= lvl
->pitch
* nby
;
437 size
+= lvl
->zslice_size
* d
;
444 mt
->layer_size
= size
;
445 if (pt
->target
== PIPE_TEXTURE_CUBE
) {
446 if (!mt
->uniform_pitch
)
447 mt
->layer_size
= align(mt
->layer_size
, 128);
448 size
= mt
->layer_size
* 6;
451 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_VRAM
, 256, size
, NULL
, &mt
->base
.bo
);
457 mt
->base
.domain
= NOUVEAU_BO_VRAM
;
458 return &mt
->base
.base
;
461 struct pipe_resource
*
462 nv30_miptree_from_handle(struct pipe_screen
*pscreen
,
463 const struct pipe_resource
*tmpl
,
464 struct winsys_handle
*handle
)
466 struct nv30_miptree
*mt
;
469 /* only supports 2D, non-mipmapped textures for the moment */
470 if ((tmpl
->target
!= PIPE_TEXTURE_2D
&&
471 tmpl
->target
!= PIPE_TEXTURE_RECT
) ||
472 tmpl
->last_level
!= 0 ||
474 tmpl
->array_size
> 1)
477 mt
= CALLOC_STRUCT(nv30_miptree
);
481 mt
->base
.bo
= nouveau_screen_bo_from_handle(pscreen
, handle
, &stride
);
482 if (mt
->base
.bo
== NULL
) {
487 mt
->base
.base
= *tmpl
;
488 mt
->base
.vtbl
= &nv30_miptree_vtbl
;
489 pipe_reference_init(&mt
->base
.base
.reference
, 1);
490 mt
->base
.base
.screen
= pscreen
;
491 mt
->uniform_pitch
= stride
;
492 mt
->level
[0].pitch
= mt
->uniform_pitch
;
493 mt
->level
[0].offset
= 0;
495 /* no need to adjust bo reference count */
496 return &mt
->base
.base
;
499 struct pipe_surface
*
500 nv30_miptree_surface_new(struct pipe_context
*pipe
,
501 struct pipe_resource
*pt
,
502 const struct pipe_surface
*tmpl
)
504 struct nv30_miptree
*mt
= nv30_miptree(pt
); /* guaranteed */
505 struct nv30_surface
*ns
;
506 struct pipe_surface
*ps
;
507 struct nv30_miptree_level
*lvl
= &mt
->level
[tmpl
->u
.tex
.level
];
509 ns
= CALLOC_STRUCT(nv30_surface
);
514 pipe_reference_init(&ps
->reference
, 1);
515 pipe_resource_reference(&ps
->texture
, pt
);
517 ps
->format
= tmpl
->format
;
518 ps
->u
.tex
.level
= tmpl
->u
.tex
.level
;
519 ps
->u
.tex
.first_layer
= tmpl
->u
.tex
.first_layer
;
520 ps
->u
.tex
.last_layer
= tmpl
->u
.tex
.last_layer
;
522 ns
->width
= u_minify(pt
->width0
, ps
->u
.tex
.level
);
523 ns
->height
= u_minify(pt
->height0
, ps
->u
.tex
.level
);
524 ns
->depth
= ps
->u
.tex
.last_layer
- ps
->u
.tex
.first_layer
+ 1;
525 ns
->offset
= layer_offset(pt
, ps
->u
.tex
.level
, ps
->u
.tex
.first_layer
);
527 ns
->pitch
= 4096; /* random, just something the hw won't reject.. */
529 ns
->pitch
= lvl
->pitch
;
531 /* comment says there are going to be removed, but they're used by the st */
532 ps
->width
= ns
->width
;
533 ps
->height
= ns
->height
;
538 nv30_miptree_surface_del(struct pipe_context
*pipe
, struct pipe_surface
*ps
)
540 struct nv30_surface
*ns
= nv30_surface(ps
);
542 pipe_resource_reference(&ps
->texture
, NULL
);