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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 #include "util/u_format.h"
27 #include "util/u_inlines.h"
28 #include "util/u_surface.h"
30 #include "nouveau/nv_m2mf.xml.h"
31 #include "nv30_screen.h"
32 #include "nv30_context.h"
33 #include "nv30_resource.h"
34 #include "nv30_transfer.h"
36 static INLINE
unsigned
37 layer_offset(struct pipe_resource
*pt
, unsigned level
, unsigned layer
)
39 struct nv30_miptree
*mt
= nv30_miptree(pt
);
40 struct nv30_miptree_level
*lvl
= &mt
->level
[level
];
42 if (pt
->target
== PIPE_TEXTURE_CUBE
)
43 return (layer
* mt
->layer_size
) + lvl
->offset
;
45 return lvl
->offset
+ (layer
* lvl
->zslice_size
);
49 nv30_miptree_get_handle(struct pipe_screen
*pscreen
,
50 struct pipe_resource
*pt
,
51 struct winsys_handle
*handle
)
53 struct nv30_miptree
*mt
= nv30_miptree(pt
);
56 if (!mt
|| !mt
->base
.bo
)
59 stride
= mt
->level
[0].pitch
;
61 return nouveau_screen_bo_get_handle(pscreen
, mt
->base
.bo
, stride
, handle
);
65 nv30_miptree_destroy(struct pipe_screen
*pscreen
, struct pipe_resource
*pt
)
67 struct nv30_miptree
*mt
= nv30_miptree(pt
);
69 nouveau_bo_ref(NULL
, &mt
->base
.bo
);
73 struct nv30_transfer
{
74 struct pipe_transfer base
;
81 static INLINE
struct nv30_transfer
*
82 nv30_transfer(struct pipe_transfer
*ptx
)
84 return (struct nv30_transfer
*)ptx
;
88 define_rect(struct pipe_resource
*pt
, unsigned level
, unsigned z
,
89 unsigned x
, unsigned y
, unsigned w
, unsigned h
,
90 struct nv30_rect
*rect
)
92 struct nv30_miptree
*mt
= nv30_miptree(pt
);
93 struct nv30_miptree_level
*lvl
= &mt
->level
[level
];
95 rect
->w
= u_minify(pt
->width0
, level
) << mt
->ms_x
;
96 rect
->w
= util_format_get_nblocksx(pt
->format
, rect
->w
);
97 rect
->h
= u_minify(pt
->height0
, level
) << mt
->ms_y
;
98 rect
->h
= util_format_get_nblocksy(pt
->format
, rect
->h
);
102 if (pt
->target
== PIPE_TEXTURE_3D
) {
103 rect
->d
= u_minify(pt
->depth0
, level
);
108 rect
->pitch
= lvl
->pitch
;
111 rect
->bo
= mt
->base
.bo
;
112 rect
->domain
= NOUVEAU_BO_VRAM
;
113 rect
->offset
= layer_offset(pt
, level
, z
);
114 rect
->cpp
= util_format_get_blocksize(pt
->format
);
116 rect
->x0
= util_format_get_nblocksx(pt
->format
, x
) << mt
->ms_x
;
117 rect
->y0
= util_format_get_nblocksy(pt
->format
, y
) << mt
->ms_y
;
118 rect
->x1
= rect
->x0
+ (w
<< mt
->ms_x
);
119 rect
->y1
= rect
->y0
+ (h
<< mt
->ms_y
);
123 nv30_resource_copy_region(struct pipe_context
*pipe
,
124 struct pipe_resource
*dstres
, unsigned dst_level
,
125 unsigned dstx
, unsigned dsty
, unsigned dstz
,
126 struct pipe_resource
*srcres
, unsigned src_level
,
127 const struct pipe_box
*src_box
)
129 struct nv30_context
*nv30
= nv30_context(pipe
);
130 struct nv30_rect src
, dst
;
132 if (dstres
->target
== PIPE_BUFFER
&& srcres
->target
== PIPE_BUFFER
) {
133 util_resource_copy_region(pipe
, dstres
, dst_level
, dstx
, dsty
, dstz
,
134 srcres
, src_level
, src_box
);
138 define_rect(srcres
, src_level
, src_box
->z
, src_box
->x
, src_box
->y
,
139 src_box
->width
, src_box
->height
, &src
);
140 define_rect(dstres
, dst_level
, dstz
, dstx
, dsty
,
141 src_box
->width
, src_box
->height
, &dst
);
143 nv30_transfer_rect(nv30
, NEAREST
, &src
, &dst
);
147 nv30_resource_resolve(struct pipe_context
*pipe
,
148 const struct pipe_resolve_info
*info
)
151 struct nv30_context
*nv30
= nv30_context(pipe
);
152 struct nv30_rect src
, dst
;
154 define_rect(info
->src
.res
, 0, 0, info
->src
.x0
, info
->src
.y0
,
155 info
->src
.x1
- info
->src
.x0
, info
->src
.y1
- info
->src
.y0
, &src
);
156 define_rect(info
->dst
.res
, info
->dst
.level
, 0, info
->dst
.x0
, info
->dst
.y0
,
157 info
->dst
.x1
- info
->dst
.x0
, info
->dst
.y1
- info
->dst
.y0
, &dst
);
159 nv30_transfer_rect(nv30
, BILINEAR
, &src
, &dst
);
164 nv30_blit(struct pipe_context
*pipe
,
165 const struct pipe_blit_info
*blit_info
)
167 struct nv30_context
*nv30
= nv30_context(pipe
);
168 struct pipe_blit_info info
= *blit_info
;
170 if (info
.src
.resource
->nr_samples
> 1 &&
171 info
.dst
.resource
->nr_samples
<= 1 &&
172 !util_format_is_depth_or_stencil(info
.src
.resource
->format
) &&
173 !util_format_is_pure_integer(info
.src
.resource
->format
)) {
174 debug_printf("nv30: color resolve unimplemented\n");
178 if (util_try_blit_via_copy_region(pipe
, &info
)) {
182 if (info
.mask
& PIPE_MASK_S
) {
183 debug_printf("nv30: cannot blit stencil, skipping\n");
184 info
.mask
&= ~PIPE_MASK_S
;
187 if (!util_blitter_is_blit_supported(nv30
->blitter
, &info
)) {
188 debug_printf("nv30: blit unsupported %s -> %s\n",
189 util_format_short_name(info
.src
.resource
->format
),
190 util_format_short_name(info
.dst
.resource
->format
));
194 /* XXX turn off occlusion queries */
196 util_blitter_save_vertex_buffers(nv30
->blitter
,
199 util_blitter_save_vertex_elements(nv30
->blitter
, nv30
->vertex
);
200 util_blitter_save_vertex_shader(nv30
->blitter
, nv30
->vertprog
.program
);
201 util_blitter_save_rasterizer(nv30
->blitter
, nv30
->rast
);
202 util_blitter_save_viewport(nv30
->blitter
, &nv30
->viewport
);
203 util_blitter_save_scissor(nv30
->blitter
, &nv30
->scissor
);
204 util_blitter_save_fragment_shader(nv30
->blitter
, nv30
->fragprog
.program
);
205 util_blitter_save_blend(nv30
->blitter
, nv30
->blend
);
206 util_blitter_save_depth_stencil_alpha(nv30
->blitter
,
208 util_blitter_save_stencil_ref(nv30
->blitter
, &nv30
->stencil_ref
);
209 util_blitter_save_sample_mask(nv30
->blitter
, nv30
->sample_mask
);
210 util_blitter_save_framebuffer(nv30
->blitter
, &nv30
->framebuffer
);
211 util_blitter_save_fragment_sampler_states(nv30
->blitter
,
212 nv30
->fragprog
.num_samplers
,
213 (void**)nv30
->fragprog
.samplers
);
214 util_blitter_save_fragment_sampler_views(nv30
->blitter
,
215 nv30
->fragprog
.num_textures
, nv30
->fragprog
.textures
);
216 util_blitter_save_render_condition(nv30
->blitter
, nv30
->render_cond_query
,
217 nv30
->render_cond_mode
);
218 util_blitter_blit(nv30
->blitter
, &info
);
222 nv30_miptree_transfer_map(struct pipe_context
*pipe
, struct pipe_resource
*pt
,
223 unsigned level
, unsigned usage
,
224 const struct pipe_box
*box
,
225 struct pipe_transfer
**ptransfer
)
227 struct nv30_context
*nv30
= nv30_context(pipe
);
228 struct nouveau_device
*dev
= nv30
->screen
->base
.device
;
229 struct nv30_transfer
*tx
;
233 tx
= CALLOC_STRUCT(nv30_transfer
);
236 pipe_resource_reference(&tx
->base
.resource
, pt
);
237 tx
->base
.level
= level
;
238 tx
->base
.usage
= usage
;
240 tx
->base
.stride
= util_format_get_nblocksx(pt
->format
, box
->width
) *
241 util_format_get_blocksize(pt
->format
);
242 tx
->base
.layer_stride
= util_format_get_nblocksy(pt
->format
, box
->height
) *
245 tx
->nblocksx
= util_format_get_nblocksx(pt
->format
, box
->width
);
246 tx
->nblocksy
= util_format_get_nblocksy(pt
->format
, box
->height
);
248 define_rect(pt
, level
, box
->z
, box
->x
, box
->y
,
249 tx
->nblocksx
, tx
->nblocksy
, &tx
->img
);
251 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_GART
| NOUVEAU_BO_MAP
, 0,
252 tx
->base
.layer_stride
, NULL
, &tx
->tmp
.bo
);
254 pipe_resource_reference(&tx
->base
.resource
, NULL
);
259 tx
->tmp
.domain
= NOUVEAU_BO_GART
;
261 tx
->tmp
.pitch
= tx
->base
.stride
;
262 tx
->tmp
.cpp
= tx
->img
.cpp
;
263 tx
->tmp
.w
= tx
->nblocksx
;
264 tx
->tmp
.h
= tx
->nblocksy
;
268 tx
->tmp
.x1
= tx
->tmp
.w
;
269 tx
->tmp
.y1
= tx
->tmp
.h
;
272 if (usage
& PIPE_TRANSFER_READ
)
273 nv30_transfer_rect(nv30
, NEAREST
, &tx
->img
, &tx
->tmp
);
275 if (tx
->tmp
.bo
->map
) {
276 *ptransfer
= &tx
->base
;
277 return tx
->tmp
.bo
->map
;
280 if (usage
& PIPE_TRANSFER_READ
)
281 access
|= NOUVEAU_BO_RD
;
282 if (usage
& PIPE_TRANSFER_WRITE
)
283 access
|= NOUVEAU_BO_WR
;
285 ret
= nouveau_bo_map(tx
->tmp
.bo
, access
, nv30
->base
.client
);
287 pipe_resource_reference(&tx
->base
.resource
, NULL
);
292 *ptransfer
= &tx
->base
;
293 return tx
->tmp
.bo
->map
;
297 nv30_miptree_transfer_unmap(struct pipe_context
*pipe
,
298 struct pipe_transfer
*ptx
)
300 struct nv30_context
*nv30
= nv30_context(pipe
);
301 struct nv30_transfer
*tx
= nv30_transfer(ptx
);
303 if (ptx
->usage
& PIPE_TRANSFER_WRITE
)
304 nv30_transfer_rect(nv30
, NEAREST
, &tx
->tmp
, &tx
->img
);
306 nouveau_bo_ref(NULL
, &tx
->tmp
.bo
);
307 pipe_resource_reference(&ptx
->resource
, NULL
);
311 const struct u_resource_vtbl nv30_miptree_vtbl
= {
312 nv30_miptree_get_handle
,
313 nv30_miptree_destroy
,
314 nv30_miptree_transfer_map
,
315 u_default_transfer_flush_region
,
316 nv30_miptree_transfer_unmap
,
317 u_default_transfer_inline_write
320 struct pipe_resource
*
321 nv30_miptree_create(struct pipe_screen
*pscreen
,
322 const struct pipe_resource
*tmpl
)
324 struct nouveau_device
*dev
= nouveau_screen(pscreen
)->device
;
325 struct nv30_miptree
*mt
= CALLOC_STRUCT(nv30_miptree
);
326 struct pipe_resource
*pt
= &mt
->base
.base
;
327 unsigned blocksz
, size
;
331 switch (tmpl
->nr_samples
) {
333 mt
->ms_mode
= 0x00004000;
338 mt
->ms_mode
= 0x00003000;
343 mt
->ms_mode
= 0x00000000;
349 mt
->base
.vtbl
= &nv30_miptree_vtbl
;
351 pipe_reference_init(&pt
->reference
, 1);
352 pt
->screen
= pscreen
;
354 w
= pt
->width0
<< mt
->ms_x
;
355 h
= pt
->height0
<< mt
->ms_y
;
356 d
= (pt
->target
== PIPE_TEXTURE_3D
) ? pt
->depth0
: 1;
357 blocksz
= util_format_get_blocksize(pt
->format
);
359 if ((pt
->target
== PIPE_TEXTURE_RECT
) ||
360 !util_is_power_of_two(pt
->width0
) ||
361 !util_is_power_of_two(pt
->height0
) ||
362 !util_is_power_of_two(pt
->depth0
) ||
363 util_format_is_compressed(pt
->format
) ||
364 util_format_is_float(pt
->format
) || mt
->ms_mode
) {
365 mt
->uniform_pitch
= util_format_get_nblocksx(pt
->format
, w
) * blocksz
;
366 mt
->uniform_pitch
= align(mt
->uniform_pitch
, 64);
369 if (!mt
->uniform_pitch
)
373 for (l
= 0; l
<= pt
->last_level
; l
++) {
374 struct nv30_miptree_level
*lvl
= &mt
->level
[l
];
375 unsigned nbx
= util_format_get_nblocksx(pt
->format
, w
);
376 unsigned nby
= util_format_get_nblocksx(pt
->format
, h
);
379 lvl
->pitch
= mt
->uniform_pitch
;
381 lvl
->pitch
= nbx
* blocksz
;
383 lvl
->zslice_size
= lvl
->pitch
* nby
;
384 size
+= lvl
->zslice_size
* d
;
391 mt
->layer_size
= size
;
392 if (pt
->target
== PIPE_TEXTURE_CUBE
) {
393 if (!mt
->uniform_pitch
)
394 mt
->layer_size
= align(mt
->layer_size
, 128);
395 size
= mt
->layer_size
* 6;
398 ret
= nouveau_bo_new(dev
, NOUVEAU_BO_VRAM
, 256, size
, NULL
, &mt
->base
.bo
);
404 mt
->base
.domain
= NOUVEAU_BO_VRAM
;
405 return &mt
->base
.base
;
408 struct pipe_resource
*
409 nv30_miptree_from_handle(struct pipe_screen
*pscreen
,
410 const struct pipe_resource
*tmpl
,
411 struct winsys_handle
*handle
)
413 struct nv30_miptree
*mt
;
416 /* only supports 2D, non-mipmapped textures for the moment */
417 if ((tmpl
->target
!= PIPE_TEXTURE_2D
&&
418 tmpl
->target
!= PIPE_TEXTURE_RECT
) ||
419 tmpl
->last_level
!= 0 ||
421 tmpl
->array_size
> 1)
424 mt
= CALLOC_STRUCT(nv30_miptree
);
428 mt
->base
.bo
= nouveau_screen_bo_from_handle(pscreen
, handle
, &stride
);
429 if (mt
->base
.bo
== NULL
) {
434 mt
->base
.base
= *tmpl
;
435 mt
->base
.vtbl
= &nv30_miptree_vtbl
;
436 pipe_reference_init(&mt
->base
.base
.reference
, 1);
437 mt
->base
.base
.screen
= pscreen
;
438 mt
->uniform_pitch
= stride
;
439 mt
->level
[0].pitch
= mt
->uniform_pitch
;
440 mt
->level
[0].offset
= 0;
442 /* no need to adjust bo reference count */
443 return &mt
->base
.base
;
446 struct pipe_surface
*
447 nv30_miptree_surface_new(struct pipe_context
*pipe
,
448 struct pipe_resource
*pt
,
449 const struct pipe_surface
*tmpl
)
451 struct nv30_miptree
*mt
= nv30_miptree(pt
); /* guaranteed */
452 struct nv30_surface
*ns
;
453 struct pipe_surface
*ps
;
454 struct nv30_miptree_level
*lvl
= &mt
->level
[tmpl
->u
.tex
.level
];
456 ns
= CALLOC_STRUCT(nv30_surface
);
461 pipe_reference_init(&ps
->reference
, 1);
462 pipe_resource_reference(&ps
->texture
, pt
);
464 ps
->format
= tmpl
->format
;
465 ps
->usage
= tmpl
->usage
;
466 ps
->u
.tex
.level
= tmpl
->u
.tex
.level
;
467 ps
->u
.tex
.first_layer
= tmpl
->u
.tex
.first_layer
;
468 ps
->u
.tex
.last_layer
= tmpl
->u
.tex
.last_layer
;
470 ns
->width
= u_minify(pt
->width0
, ps
->u
.tex
.level
);
471 ns
->height
= u_minify(pt
->height0
, ps
->u
.tex
.level
);
472 ns
->depth
= ps
->u
.tex
.last_layer
- ps
->u
.tex
.first_layer
+ 1;
473 ns
->offset
= layer_offset(pt
, ps
->u
.tex
.level
, ps
->u
.tex
.first_layer
);
475 ns
->pitch
= 4096; /* random, just something the hw won't reject.. */
477 ns
->pitch
= lvl
->pitch
;
479 /* comment says there are going to be removed, but they're used by the st */
480 ps
->width
= ns
->width
;
481 ps
->height
= ns
->height
;
486 nv30_miptree_surface_del(struct pipe_context
*pipe
, struct pipe_surface
*ps
)
488 struct nv30_surface
*ns
= nv30_surface(ps
);
490 pipe_resource_reference(&ps
->texture
, NULL
);