76b60592bfb9218df0d7197bd0abd8e3cea4131b
[mesa.git] / src / gallium / drivers / nv50 / nv50_miptree.c
1 /*
2 * Copyright 2008 Ben Skeggs
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
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
20 * SOFTWARE.
21 */
22
23 #include "pipe/p_state.h"
24 #include "pipe/p_defines.h"
25 #include "util/u_inlines.h"
26 #include "util/u_format.h"
27
28 #include "nv50_context.h"
29 #include "nv50_resource.h"
30
31 static INLINE uint32_t
32 nv50_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz)
33 {
34 return nvc0_tex_choose_tile_dims(nx, ny * 2, nz) >> 4;
35 }
36
37 static uint32_t
38 nv50_mt_choose_storage_type(struct nv50_miptree *mt, boolean compressed)
39 {
40 const unsigned ms = util_logbase2(mt->base.base.nr_samples);
41
42 uint32_t tile_flags;
43
44 if (mt->base.base.bind & PIPE_BIND_CURSOR)
45 return NOUVEAU_BO_TILE_SCANOUT;
46
47 switch (mt->base.base.format) {
48 case PIPE_FORMAT_Z16_UNORM:
49 tile_flags = 0x6c00 + (ms << 8);
50 break;
51 case PIPE_FORMAT_S8_UINT_Z24_UNORM:
52 tile_flags = 0x1800 + (ms << 8);
53 break;
54 case PIPE_FORMAT_Z24X8_UNORM:
55 case PIPE_FORMAT_Z24_UNORM_S8_UINT:
56 tile_flags = 0x22800 + (ms << 8);
57 break;
58 case PIPE_FORMAT_Z32_FLOAT:
59 tile_flags = 0x4000 + (ms << 8);
60 break;
61 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
62 tile_flags = 0x6000 + (ms << 8);
63 break;
64 default:
65 switch (util_format_get_blocksizebits(mt->base.base.format)) {
66 case 128:
67 assert(ms < 3);
68 tile_flags = 0x7400;
69 break;
70 case 64:
71 switch (ms) {
72 case 2: tile_flags = 0x17c00; break;
73 case 3: tile_flags = 0x17d00; break;
74 default:
75 tile_flags = 0x7000;
76 break;
77 }
78 break;
79 case 32:
80 if (mt->base.base.bind & PIPE_BIND_SCANOUT) {
81 assert(ms == 0);
82 tile_flags = 0x7a00;
83 } else {
84 switch (ms) {
85 case 2: tile_flags = 0x17800; break;
86 case 3: tile_flags = 0x17900; break;
87 default:
88 tile_flags = 0x7000;
89 break;
90 }
91 }
92 break;
93 case 16:
94 case 8:
95 tile_flags = 0x7000;
96 break;
97 default:
98 return 0;
99 }
100 if (mt->base.base.bind & PIPE_BIND_CURSOR)
101 tile_flags = 0;
102 }
103
104 if (mt->base.base.bind & (PIPE_BIND_SCANOUT | PIPE_BIND_CURSOR))
105 tile_flags |= NOUVEAU_BO_TILE_SCANOUT;
106
107 if (!compressed)
108 tile_flags &= ~0x30000;
109
110 if (unlikely(mt->base.base.flags & NOUVEAU_RESOURCE_FLAG_LINEAR))
111 tile_flags &= ~0x3ff00;
112
113 return tile_flags;
114 }
115
116 void
117 nv50_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt)
118 {
119 struct nv50_miptree *mt = nv50_miptree(pt);
120
121 nouveau_screen_bo_release(pscreen, mt->base.bo);
122
123 FREE(mt);
124 }
125
126 boolean
127 nv50_miptree_get_handle(struct pipe_screen *pscreen,
128 struct pipe_resource *pt,
129 struct winsys_handle *whandle)
130 {
131 struct nv50_miptree *mt = nv50_miptree(pt);
132 unsigned stride;
133
134 if (!mt || !mt->base.bo)
135 return FALSE;
136
137 stride = util_format_get_stride(mt->base.base.format,
138 mt->base.base.width0);
139
140 return nouveau_screen_bo_get_handle(pscreen,
141 mt->base.bo,
142 stride,
143 whandle);
144 }
145
146 const struct u_resource_vtbl nv50_miptree_vtbl =
147 {
148 nv50_miptree_get_handle, /* get_handle */
149 nv50_miptree_destroy, /* resource_destroy */
150 nv50_miptree_transfer_new, /* get_transfer */
151 nv50_miptree_transfer_del, /* transfer_destroy */
152 nv50_miptree_transfer_map, /* transfer_map */
153 u_default_transfer_flush_region, /* transfer_flush_region */
154 nv50_miptree_transfer_unmap, /* transfer_unmap */
155 u_default_transfer_inline_write /* transfer_inline_write */
156 };
157
158 static INLINE boolean
159 nv50_miptree_init_ms_mode(struct nv50_miptree *mt)
160 {
161 switch (mt->base.base.nr_samples) {
162 case 8:
163 mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS8;
164 mt->ms_x = 2;
165 mt->ms_y = 1;
166 break;
167 case 4:
168 mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS4;
169 mt->ms_x = 1;
170 mt->ms_y = 1;
171 break;
172 case 2:
173 mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS2;
174 mt->ms_x = 1;
175 break;
176 case 1:
177 case 0:
178 mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS1;
179 break;
180 default:
181 NOUVEAU_ERR("invalid nr_samples: %u\n", mt->base.base.nr_samples);
182 return FALSE;
183 }
184 return TRUE;
185 }
186
187 boolean
188 nv50_miptree_init_layout_linear(struct nv50_miptree *mt)
189 {
190 struct pipe_resource *pt = &mt->base.base;
191 const unsigned blocksize = util_format_get_blocksize(pt->format);
192
193 if (util_format_is_depth_or_stencil(pt->format))
194 return FALSE;
195
196 if ((pt->last_level > 0) || (pt->depth0 > 1) || (pt->array_size > 1))
197 return FALSE;
198 if (mt->ms_x | mt->ms_y)
199 return FALSE;
200
201 mt->level[0].pitch = align(pt->width0 * blocksize, 64);
202
203 mt->total_size = mt->level[0].pitch * pt->height0;
204
205 return TRUE;
206 }
207
208 static void
209 nv50_miptree_init_layout_tiled(struct nv50_miptree *mt)
210 {
211 struct pipe_resource *pt = &mt->base.base;
212 unsigned w, h, d, l;
213 const unsigned blocksize = util_format_get_blocksize(pt->format);
214
215 mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
216
217 w = pt->width0 << mt->ms_x;
218 h = pt->height0 << mt->ms_y;
219
220 /* For 3D textures, a mipmap is spanned by all the layers, for array
221 * textures and cube maps, each layer contains its own mipmaps.
222 */
223 d = mt->layout_3d ? pt->depth0 : 1;
224
225 for (l = 0; l <= pt->last_level; ++l) {
226 struct nv50_miptree_level *lvl = &mt->level[l];
227 unsigned tsx, tsy, tsz;
228 unsigned nbx = util_format_get_nblocksx(pt->format, w);
229 unsigned nby = util_format_get_nblocksy(pt->format, h);
230
231 lvl->offset = mt->total_size;
232
233 lvl->tile_mode = nv50_tex_choose_tile_dims(nbx, nby, d);
234
235 tsx = NV50_TILE_SIZE_X(lvl->tile_mode); /* x is tile row pitch in bytes */
236 tsy = NV50_TILE_SIZE_Y(lvl->tile_mode);
237 tsz = NV50_TILE_SIZE_Z(lvl->tile_mode);
238
239 lvl->pitch = align(nbx * blocksize, tsx);
240
241 mt->total_size += lvl->pitch * align(nby, tsy) * align(d, tsz);
242
243 w = u_minify(w, 1);
244 h = u_minify(h, 1);
245 d = u_minify(d, 1);
246 }
247
248 if (pt->array_size > 1) {
249 mt->layer_stride = align(mt->total_size,
250 NV50_TILE_SIZE(mt->level[0].tile_mode));
251 mt->total_size = mt->layer_stride * pt->array_size;
252 }
253 }
254
255 struct pipe_resource *
256 nv50_miptree_create(struct pipe_screen *pscreen,
257 const struct pipe_resource *templ)
258 {
259 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
260 struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree);
261 struct pipe_resource *pt = &mt->base.base;
262 int ret;
263 uint32_t tile_flags;
264
265 if (!mt)
266 return NULL;
267
268 mt->base.vtbl = &nv50_miptree_vtbl;
269 *pt = *templ;
270 pipe_reference_init(&pt->reference, 1);
271 pt->screen = pscreen;
272
273 tile_flags = nv50_mt_choose_storage_type(mt, TRUE);
274
275 if (!nv50_miptree_init_ms_mode(mt)) {
276 FREE(mt);
277 return NULL;
278 }
279
280 if (tile_flags & NOUVEAU_BO_TILE_LAYOUT_MASK) {
281 nv50_miptree_init_layout_tiled(mt);
282 } else
283 if (!nv50_miptree_init_layout_linear(mt)) {
284 FREE(mt);
285 return NULL;
286 }
287
288 ret = nouveau_bo_new_tile(dev, NOUVEAU_BO_VRAM, 4096,
289 mt->total_size,
290 mt->level[0].tile_mode, tile_flags,
291 &mt->base.bo);
292 if (ret) {
293 FREE(mt);
294 return NULL;
295 }
296 mt->base.domain = NOUVEAU_BO_VRAM;
297
298 return pt;
299 }
300
301 struct pipe_resource *
302 nv50_miptree_from_handle(struct pipe_screen *pscreen,
303 const struct pipe_resource *templ,
304 struct winsys_handle *whandle)
305 {
306 struct nv50_miptree *mt;
307 unsigned stride;
308
309 /* only supports 2D, non-mipmapped textures for the moment */
310 if ((templ->target != PIPE_TEXTURE_2D &&
311 templ->target != PIPE_TEXTURE_RECT) ||
312 templ->last_level != 0 ||
313 templ->depth0 != 1 ||
314 templ->array_size > 1)
315 return NULL;
316
317 mt = CALLOC_STRUCT(nv50_miptree);
318 if (!mt)
319 return NULL;
320
321 mt->base.bo = nouveau_screen_bo_from_handle(pscreen, whandle, &stride);
322 if (mt->base.bo == NULL) {
323 FREE(mt);
324 return NULL;
325 }
326
327 mt->base.base = *templ;
328 mt->base.vtbl = &nv50_miptree_vtbl;
329 pipe_reference_init(&mt->base.base.reference, 1);
330 mt->base.base.screen = pscreen;
331 mt->level[0].pitch = stride;
332 mt->level[0].offset = 0;
333 mt->level[0].tile_mode = mt->base.bo->tile_mode;
334
335 /* no need to adjust bo reference count */
336 return &mt->base.base;
337 }
338
339
340 /* Offset of zslice @z from start of level @l. */
341 INLINE unsigned
342 nv50_mt_zslice_offset(const struct nv50_miptree *mt, unsigned l, unsigned z)
343 {
344 const struct pipe_resource *pt = &mt->base.base;
345
346 unsigned tds = NV50_TILE_SHIFT_Z(mt->level[l].tile_mode);
347 unsigned ths = NV50_TILE_SHIFT_Y(mt->level[l].tile_mode);
348
349 unsigned nby = util_format_get_nblocksy(pt->format,
350 u_minify(pt->height0, l));
351
352 /* to next 2D tile slice within a 3D tile */
353 unsigned stride_2d = NV50_TILE_SIZE_2D(mt->level[l].tile_mode);
354
355 /* to slice in the next (in z direction) 3D tile */
356 unsigned stride_3d = (align(nby, (1 << ths)) * mt->level[l].pitch) << tds;
357
358 return (z & ((1 << tds) - 1)) * stride_2d + (z >> tds) * stride_3d;
359 }
360
361 /* Surface functions.
362 */
363
364 struct nv50_surface *
365 nv50_surface_from_miptree(struct nv50_miptree *mt,
366 const struct pipe_surface *templ)
367 {
368 struct pipe_surface *ps;
369 struct nv50_surface *ns = CALLOC_STRUCT(nv50_surface);
370 if (!ns)
371 return NULL;
372 ps = &ns->base;
373
374 pipe_reference_init(&ps->reference, 1);
375 pipe_resource_reference(&ps->texture, &mt->base.base);
376
377 ps->format = templ->format;
378 ps->usage = templ->usage;
379 ps->u.tex.level = templ->u.tex.level;
380 ps->u.tex.first_layer = templ->u.tex.first_layer;
381 ps->u.tex.last_layer = templ->u.tex.last_layer;
382
383 ns->width = u_minify(mt->base.base.width0, ps->u.tex.level);
384 ns->height = u_minify(mt->base.base.height0, ps->u.tex.level);
385 ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;
386 ns->offset = mt->level[templ->u.tex.level].offset;
387
388 /* comment says there are going to be removed, but they're used by the st */
389 ps->width = ns->width;
390 ps->height = ns->height;
391
392 ns->width <<= mt->ms_x;
393 ns->height <<= mt->ms_y;
394
395 return ns;
396 }
397
398 struct pipe_surface *
399 nv50_miptree_surface_new(struct pipe_context *pipe,
400 struct pipe_resource *pt,
401 const struct pipe_surface *templ)
402 {
403 struct nv50_miptree *mt = nv50_miptree(pt);
404 struct nv50_surface *ns = nv50_surface_from_miptree(mt, templ);
405 if (!ns)
406 return NULL;
407 ns->base.context = pipe;
408
409 if (ns->base.u.tex.first_layer) {
410 const unsigned l = ns->base.u.tex.level;
411 const unsigned z = ns->base.u.tex.first_layer;
412
413 if (mt->layout_3d) {
414 ns->offset += nv50_mt_zslice_offset(mt, l, z);
415
416 /* TODO: switch to depth 1 tiles; but actually this shouldn't happen */
417 if (ns->depth > 1 &&
418 (z & (NV50_TILE_SIZE_Z(mt->level[l].tile_mode) - 1)))
419 NOUVEAU_ERR("Creating unsupported 3D surface !\n");
420 } else {
421 ns->offset += mt->layer_stride * z;
422 }
423 }
424
425 return &ns->base;
426 }