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 "nvc0_context.h"
29 #include "nvc0_resource.h"
30 #include "nvc0_transfer.h"
32 static INLINE
uint32_t
33 get_tile_dims(unsigned nx
, unsigned ny
, unsigned nz
)
35 uint32_t tile_mode
= 0x000;
37 if (ny
> 64) tile_mode
= 0x040; /* height 128 tiles */
39 if (ny
> 32) tile_mode
= 0x030; /* height 64 tiles */
41 if (ny
> 16) tile_mode
= 0x020; /* height 32 tiles */
43 if (ny
> 8) tile_mode
= 0x010; /* height 16 tiles */
48 if (tile_mode
> 0x020)
51 if (nz
> 16 && tile_mode
< 0x020)
52 return tile_mode
| 0x500; /* depth 32 tiles */
53 if (nz
> 8) return tile_mode
| 0x400; /* depth 16 tiles */
54 if (nz
> 4) return tile_mode
| 0x300; /* depth 8 tiles */
55 if (nz
> 2) return tile_mode
| 0x200; /* depth 4 tiles */
57 return tile_mode
| 0x100;
60 static INLINE
unsigned
61 get_zslice_offset(uint32_t tile_mode
, unsigned z
, unsigned pitch
, unsigned nbh
)
63 unsigned tile_h
= NVC0_TILE_H(tile_mode
);
64 unsigned tile_d
= NVC0_TILE_D(tile_mode
);
66 /* pitch_2d == to next slice within this volume tile */
67 /* pitch_3d == size (in bytes) of a volume tile */
68 unsigned pitch_2d
= tile_h
* 64;
69 unsigned pitch_3d
= tile_d
* align(nbh
, tile_h
) * pitch
;
71 return (z
% tile_d
) * pitch_2d
+ (z
/ tile_d
) * pitch_3d
;
75 nvc0_miptree_destroy(struct pipe_screen
*pscreen
, struct pipe_resource
*pt
)
77 struct nvc0_miptree
*mt
= nvc0_miptree(pt
);
80 for (l
= 0; l
<= pt
->last_level
; ++l
)
81 FREE(mt
->level
[l
].image_offset
);
83 nouveau_screen_bo_release(pscreen
, mt
->base
.bo
);
89 nvc0_miptree_get_handle(struct pipe_screen
*pscreen
,
90 struct pipe_resource
*pt
,
91 struct winsys_handle
*whandle
)
93 struct nvc0_miptree
*mt
= nvc0_miptree(pt
);
96 if (!mt
|| !mt
->base
.bo
)
99 stride
= util_format_get_stride(mt
->base
.base
.format
,
100 mt
->base
.base
.width0
);
102 return nouveau_screen_bo_get_handle(pscreen
,
108 const struct u_resource_vtbl nvc0_miptree_vtbl
=
110 nvc0_miptree_get_handle
, /* get_handle */
111 nvc0_miptree_destroy
, /* resource_destroy */
112 NULL
, /* is_resource_referenced */
113 nvc0_miptree_transfer_new
, /* get_transfer */
114 nvc0_miptree_transfer_del
, /* transfer_destroy */
115 nvc0_miptree_transfer_map
, /* transfer_map */
116 u_default_transfer_flush_region
, /* transfer_flush_region */
117 nvc0_miptree_transfer_unmap
, /* transfer_unmap */
118 u_default_transfer_inline_write
/* transfer_inline_write */
121 struct pipe_resource
*
122 nvc0_miptree_create(struct pipe_screen
*pscreen
,
123 const struct pipe_resource
*templ
)
125 struct nouveau_device
*dev
= nouveau_screen(pscreen
)->device
;
126 struct nvc0_miptree
*mt
= CALLOC_STRUCT(nvc0_miptree
);
127 struct pipe_resource
*pt
= &mt
->base
.base
;
129 unsigned w
, h
, d
, l
, image_alignment
, alloc_size
;
135 mt
->base
.vtbl
= &nvc0_miptree_vtbl
;
137 pipe_reference_init(&pt
->reference
, 1);
138 pt
->screen
= pscreen
;
144 switch (pt
->format
) {
145 case PIPE_FORMAT_Z16_UNORM
:
146 tile_flags
= 0x0700; /* COMPRESSED */
147 tile_flags
= 0x0200; /* NORMAL ? */
148 tile_flags
= 0x0100; /* NORMAL ? */
150 case PIPE_FORMAT_S8_USCALED_Z24_UNORM
:
151 tile_flags
= 0x5300; /* MSAA 4, COMPRESSED */
152 tile_flags
= 0x4600; /* NORMAL */
154 case PIPE_FORMAT_Z24X8_UNORM
:
155 case PIPE_FORMAT_Z24_UNORM_S8_USCALED
:
156 tile_flags
= 0x1100; /* NORMAL */
157 if (w
* h
>= 128 * 128 && 0)
158 tile_flags
= 0x1700; /* COMPRESSED, requires magic */
160 case PIPE_FORMAT_R32G32B32A32_FLOAT
:
161 tile_flags
= 0xf500; /* COMPRESSED */
162 tile_flags
= 0xf700; /* MSAA 2 */
163 tile_flags
= 0xf900; /* MSAA 4 */
164 tile_flags
= 0xfe00; /* NORMAL */
166 case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED
:
167 tile_flags
= 0xce00; /* COMPRESSED */
168 tile_flags
= 0xcf00; /* MSAA 2, COMPRESSED */
169 tile_flags
= 0xd000; /* MSAA 4, COMPRESSED */
170 tile_flags
= 0xc300; /* NORMAL */
172 case PIPE_FORMAT_R16G16B16A16_UNORM
:
173 tile_flags
= 0xe900; /* COMPRESSED */
176 tile_flags
= 0xe000; /* MSAA 4, COMPRESSED 32 BIT */
177 tile_flags
= 0xfe00; /* NORMAL 32 BIT */
178 if (w
* h
>= 128 * 128 && 0)
179 tile_flags
= 0xdb00; /* COMPRESSED 32 BIT, requires magic */
183 /* XXX: texture arrays */
184 mt
->image_nr
= (pt
->target
== PIPE_TEXTURE_CUBE
) ? 6 : 1;
186 for (l
= 0; l
<= pt
->last_level
; l
++) {
187 struct nvc0_miptree_level
*lvl
= &mt
->level
[l
];
188 unsigned nby
= util_format_get_nblocksy(pt
->format
, h
);
190 lvl
->image_offset
= CALLOC(mt
->image_nr
, sizeof(int));
191 lvl
->pitch
= align(util_format_get_stride(pt
->format
, w
), 64);
192 lvl
->tile_mode
= get_tile_dims(w
, nby
, d
);
199 image_alignment
= NVC0_TILE_H(mt
->level
[0].tile_mode
) * 64;
200 image_alignment
*= NVC0_TILE_D(mt
->level
[0].tile_mode
);
202 /* NOTE the distinction between arrays of mip-mapped 2D textures and
203 * mip-mapped 3D textures. We can't use image_nr == depth for 3D mip.
205 for (i
= 0; i
< mt
->image_nr
; i
++) {
206 for (l
= 0; l
<= pt
->last_level
; l
++) {
207 struct nvc0_miptree_level
*lvl
= &mt
->level
[l
];
209 unsigned tile_h
= NVC0_TILE_H(lvl
->tile_mode
);
210 unsigned tile_d
= NVC0_TILE_D(lvl
->tile_mode
);
212 h
= u_minify(pt
->height0
, l
);
213 d
= u_minify(pt
->depth0
, l
);
216 size
*= align(util_format_get_nblocksy(pt
->format
, h
), tile_h
);
217 size
*= align(d
, tile_d
);
219 lvl
->image_offset
[i
] = mt
->total_size
;
221 mt
->total_size
+= size
;
223 mt
->total_size
= align(mt
->total_size
, image_alignment
);
226 alloc_size
= mt
->total_size
;
227 if (tile_flags
== 0x1700)
228 alloc_size
*= 3; /* HiZ, XXX: correct size */
230 ret
= nouveau_bo_new_tile(dev
, NOUVEAU_BO_VRAM
, 256, alloc_size
,
231 mt
->level
[0].tile_mode
, tile_flags
,
234 for (l
= 0; l
<= pt
->last_level
; ++l
)
235 FREE(mt
->level
[l
].image_offset
);
243 struct pipe_resource
*
244 nvc0_miptree_from_handle(struct pipe_screen
*pscreen
,
245 const struct pipe_resource
*templ
,
246 struct winsys_handle
*whandle
)
248 struct nvc0_miptree
*mt
;
251 /* only supports 2D, non-mip mapped textures for the moment */
252 if ((templ
->target
!= PIPE_TEXTURE_2D
&&
253 templ
->target
!= PIPE_TEXTURE_RECT
) ||
254 templ
->last_level
!= 0 ||
258 mt
= CALLOC_STRUCT(nvc0_miptree
);
262 mt
->base
.bo
= nouveau_screen_bo_from_handle(pscreen
, whandle
, &stride
);
263 if (mt
->base
.bo
== NULL
) {
268 mt
->base
.base
= *templ
;
269 mt
->base
.vtbl
= &nvc0_miptree_vtbl
;
270 pipe_reference_init(&mt
->base
.base
.reference
, 1);
271 mt
->base
.base
.screen
= pscreen
;
273 mt
->level
[0].pitch
= stride
;
274 mt
->level
[0].image_offset
= CALLOC(1, sizeof(unsigned));
275 mt
->level
[0].tile_mode
= mt
->base
.bo
->tile_mode
;
277 /* no need to adjust bo reference count */
278 return &mt
->base
.base
;
282 /* Surface functions.
285 struct pipe_surface
*
286 nvc0_miptree_surface_new(struct pipe_screen
*pscreen
, struct pipe_resource
*pt
,
287 unsigned face
, unsigned level
, unsigned zslice
,
290 struct nvc0_miptree
*mt
= nvc0_miptree(pt
);
291 struct nvc0_miptree_level
*lvl
= &mt
->level
[level
];
292 struct pipe_surface
*ps
;
295 if (pt
->target
== PIPE_TEXTURE_CUBE
)
298 ps
= CALLOC_STRUCT(pipe_surface
);
301 pipe_resource_reference(&ps
->texture
, pt
);
302 ps
->format
= pt
->format
;
303 ps
->width
= u_minify(pt
->width0
, level
);
304 ps
->height
= u_minify(pt
->height0
, level
);
306 pipe_reference_init(&ps
->reference
, 1);
310 ps
->offset
= lvl
->image_offset
[img
];
312 if (pt
->target
== PIPE_TEXTURE_3D
)
313 ps
->offset
+= get_zslice_offset(lvl
->tile_mode
, zslice
, lvl
->pitch
,
314 util_format_get_nblocksy(pt
->format
,
320 nvc0_miptree_surface_del(struct pipe_surface
*ps
)
322 struct nvc0_surface
*s
= nvc0_surface(ps
);
324 pipe_resource_reference(&ps
->texture
, NULL
);