2 * Copyright 2008 Ben Skeggs
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
23 #include "pipe/p_state.h"
24 #include "pipe/p_defines.h"
25 #include "util/u_inlines.h"
26 #include "util/u_format.h"
28 #include "nv50_context.h"
29 #include "nv50_resource.h"
30 #include "nv50_transfer.h"
32 /* The restrictions in tile mode selection probably aren't necessary. */
33 static INLINE
uint32_t
34 get_tile_mode(unsigned ny
, unsigned d
)
36 uint32_t tile_mode
= 0x00;
38 if (ny
> 32) tile_mode
= 0x04; /* height 64 tiles */
40 if (ny
> 16) tile_mode
= 0x03; /* height 32 tiles */
42 if (ny
> 8) tile_mode
= 0x02; /* height 16 tiles */
44 if (ny
> 4) tile_mode
= 0x01; /* height 8 tiles */
52 if (d
> 16 && tile_mode
< 0x02)
53 return tile_mode
| 0x50; /* depth 32 tiles */
54 if (d
> 8) return tile_mode
| 0x40; /* depth 16 tiles */
55 if (d
> 4) return tile_mode
| 0x30; /* depth 8 tiles */
56 if (d
> 2) return tile_mode
| 0x20; /* depth 4 tiles */
58 return tile_mode
| 0x10;
61 static INLINE
unsigned
62 get_zslice_offset(unsigned tile_mode
, unsigned z
, unsigned pitch
, unsigned nb_h
)
64 unsigned tile_h
= get_tile_height(tile_mode
);
65 unsigned tile_d
= get_tile_depth(tile_mode
);
67 /* pitch_2d == to next slice within this volume-tile */
68 /* pitch_3d == size (in bytes) of a volume-tile */
69 unsigned pitch_2d
= tile_h
* 64;
70 unsigned pitch_3d
= tile_d
* align(nb_h
, tile_h
) * pitch
;
72 return (z
% tile_d
) * pitch_2d
+ (z
/ tile_d
) * pitch_3d
;
79 nv50_miptree_destroy(struct pipe_screen
*pscreen
,
80 struct pipe_resource
*pt
)
82 struct nv50_miptree
*mt
= nv50_miptree(pt
);
85 for (l
= 0; l
<= pt
->last_level
; ++l
)
86 FREE(mt
->level
[l
].image_offset
);
88 nouveau_screen_bo_release(pscreen
, mt
->base
.bo
);
93 nv50_miptree_get_handle(struct pipe_screen
*pscreen
,
94 struct pipe_resource
*pt
,
95 struct winsys_handle
*whandle
)
97 struct nv50_miptree
*mt
= nv50_miptree(pt
);
101 if (!mt
|| !mt
->base
.bo
)
104 stride
= util_format_get_stride(mt
->base
.base
.format
,
105 mt
->base
.base
.width0
);
107 return nouveau_screen_bo_get_handle(pscreen
,
114 const struct u_resource_vtbl nv50_miptree_vtbl
=
116 nv50_miptree_get_handle
, /* get_handle */
117 nv50_miptree_destroy
, /* resource_destroy */
118 NULL
, /* is_resource_referenced */
119 nv50_miptree_transfer_new
, /* get_transfer */
120 nv50_miptree_transfer_del
, /* transfer_destroy */
121 nv50_miptree_transfer_map
, /* transfer_map */
122 u_default_transfer_flush_region
, /* transfer_flush_region */
123 nv50_miptree_transfer_unmap
, /* transfer_unmap */
124 u_default_transfer_inline_write
/* transfer_inline_write */
129 struct pipe_resource
*
130 nv50_miptree_create(struct pipe_screen
*pscreen
, const struct pipe_resource
*tmp
)
132 struct nouveau_device
*dev
= nouveau_screen(pscreen
)->device
;
133 struct nv50_miptree
*mt
= CALLOC_STRUCT(nv50_miptree
);
134 struct pipe_resource
*pt
= &mt
->base
.base
;
135 unsigned width
= tmp
->width0
, height
= tmp
->height0
;
136 unsigned depth
= tmp
->depth0
, image_alignment
;
144 mt
->base
.vtbl
= &nv50_miptree_vtbl
;
145 pipe_reference_init(&pt
->reference
, 1);
146 pt
->screen
= pscreen
;
148 switch (pt
->format
) {
149 case PIPE_FORMAT_Z32_FLOAT
:
152 case PIPE_FORMAT_S8_USCALED_Z24_UNORM
:
155 case PIPE_FORMAT_Z16_UNORM
:
158 case PIPE_FORMAT_Z24X8_UNORM
:
159 case PIPE_FORMAT_Z24_UNORM_S8_USCALED
:
162 case PIPE_FORMAT_R32G32B32A32_FLOAT
:
163 case PIPE_FORMAT_R32G32B32_FLOAT
:
167 if ((pt
->bind
& PIPE_BIND_SCANOUT
) &&
168 util_format_get_blocksizebits(pt
->format
) == 32)
175 /* XXX: texture arrays */
176 mt
->image_nr
= (pt
->target
== PIPE_TEXTURE_CUBE
) ? 6 : 1;
178 for (l
= 0; l
<= pt
->last_level
; l
++) {
179 struct nv50_miptree_level
*lvl
= &mt
->level
[l
];
180 unsigned nblocksy
= util_format_get_nblocksy(pt
->format
, height
);
182 lvl
->image_offset
= CALLOC(mt
->image_nr
, sizeof(int));
183 lvl
->pitch
= align(util_format_get_stride(pt
->format
, width
), 64);
184 lvl
->tile_mode
= get_tile_mode(nblocksy
, depth
);
186 width
= u_minify(width
, 1);
187 height
= u_minify(height
, 1);
188 depth
= u_minify(depth
, 1);
191 image_alignment
= get_tile_height(mt
->level
[0].tile_mode
) * 64;
192 image_alignment
*= get_tile_depth(mt
->level
[0].tile_mode
);
194 /* NOTE the distinction between arrays of mip-mapped 2D textures and
195 * mip-mapped 3D textures. We can't use image_nr == depth for 3D mip.
197 for (i
= 0; i
< mt
->image_nr
; i
++) {
198 for (l
= 0; l
<= pt
->last_level
; l
++) {
199 struct nv50_miptree_level
*lvl
= &mt
->level
[l
];
201 unsigned tile_h
= get_tile_height(lvl
->tile_mode
);
202 unsigned tile_d
= get_tile_depth(lvl
->tile_mode
);
205 size
*= align(util_format_get_nblocksy(pt
->format
, u_minify(pt
->height0
, l
)), tile_h
);
206 size
*= align(u_minify(pt
->depth0
, l
), tile_d
);
208 lvl
->image_offset
[i
] = mt
->total_size
;
210 mt
->total_size
+= size
;
212 mt
->total_size
= align(mt
->total_size
, image_alignment
);
215 ret
= nouveau_bo_new_tile(dev
, NOUVEAU_BO_VRAM
, 256, mt
->total_size
,
216 mt
->level
[0].tile_mode
, tile_flags
,
219 for (l
= 0; l
<= pt
->last_level
; ++l
)
220 FREE(mt
->level
[l
].image_offset
);
229 struct pipe_resource
*
230 nv50_miptree_from_handle(struct pipe_screen
*pscreen
,
231 const struct pipe_resource
*template,
232 struct winsys_handle
*whandle
)
234 struct nv50_miptree
*mt
;
237 /* Only supports 2D, non-mipmapped textures for the moment */
238 if (template->target
!= PIPE_TEXTURE_2D
||
239 template->last_level
!= 0 ||
240 template->depth0
!= 1)
243 mt
= CALLOC_STRUCT(nv50_miptree
);
247 mt
->base
.bo
= nouveau_screen_bo_from_handle(pscreen
, whandle
, &stride
);
248 if (mt
->base
.bo
== NULL
) {
254 mt
->base
.base
= *template;
255 mt
->base
.vtbl
= &nv50_miptree_vtbl
;
256 pipe_reference_init(&mt
->base
.base
.reference
, 1);
257 mt
->base
.base
.screen
= pscreen
;
259 mt
->level
[0].pitch
= stride
;
260 mt
->level
[0].image_offset
= CALLOC(1, sizeof(unsigned));
261 mt
->level
[0].tile_mode
= mt
->base
.bo
->tile_mode
;
263 /* XXX: Need to adjust bo refcount??
265 /* nouveau_bo_ref(bo, &mt->base.bo); */
266 return &mt
->base
.base
;
274 struct pipe_surface
*
275 nv50_miptree_surface_new(struct pipe_screen
*pscreen
, struct pipe_resource
*pt
,
276 unsigned face
, unsigned level
, unsigned zslice
,
279 struct nv50_miptree
*mt
= nv50_miptree(pt
);
280 struct nv50_miptree_level
*lvl
= &mt
->level
[level
];
281 struct pipe_surface
*ps
;
284 if (pt
->target
== PIPE_TEXTURE_CUBE
)
287 ps
= CALLOC_STRUCT(pipe_surface
);
290 pipe_resource_reference(&ps
->texture
, pt
);
291 ps
->format
= pt
->format
;
292 ps
->width
= u_minify(pt
->width0
, level
);
293 ps
->height
= u_minify(pt
->height0
, level
);
295 pipe_reference_init(&ps
->reference
, 1);
299 ps
->offset
= lvl
->image_offset
[img
];
301 if (pt
->target
== PIPE_TEXTURE_3D
) {
302 unsigned nb_h
= util_format_get_nblocksy(pt
->format
, ps
->height
);
303 ps
->offset
+= get_zslice_offset(lvl
->tile_mode
, zslice
,
311 nv50_miptree_surface_del(struct pipe_surface
*ps
)
313 struct nv50_surface
*s
= nv50_surface(ps
);
315 pipe_resource_reference(&ps
->texture
, NULL
);