drm-uapi: use local files, not system libdrm
[mesa.git] / src / gallium / drivers / nouveau / nvc0 / nvc0_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 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.
21 */
22
23 #include "drm-uapi/drm_fourcc.h"
24
25 #include "pipe/p_state.h"
26 #include "pipe/p_defines.h"
27 #include "state_tracker/drm_driver.h"
28 #include "util/u_inlines.h"
29 #include "util/u_format.h"
30
31 #include "nvc0/nvc0_context.h"
32 #include "nvc0/nvc0_resource.h"
33
34 static uint32_t
35 nvc0_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz, bool is_3d)
36 {
37 return nv50_tex_choose_tile_dims_helper(nx, ny, nz, is_3d);
38 }
39
40 static uint32_t
41 nvc0_mt_choose_storage_type(struct nv50_miptree *mt, bool compressed)
42 {
43 const unsigned ms = util_logbase2(mt->base.base.nr_samples);
44
45 uint32_t tile_flags;
46
47 if (unlikely(mt->base.base.bind & PIPE_BIND_CURSOR))
48 return 0;
49 if (unlikely(mt->base.base.flags & NOUVEAU_RESOURCE_FLAG_LINEAR))
50 return 0;
51
52 switch (mt->base.base.format) {
53 case PIPE_FORMAT_Z16_UNORM:
54 if (compressed)
55 tile_flags = 0x02 + ms;
56 else
57 tile_flags = 0x01;
58 break;
59 case PIPE_FORMAT_X8Z24_UNORM:
60 case PIPE_FORMAT_S8X24_UINT:
61 case PIPE_FORMAT_S8_UINT_Z24_UNORM:
62 if (compressed)
63 tile_flags = 0x51 + ms;
64 else
65 tile_flags = 0x46;
66 break;
67 case PIPE_FORMAT_X24S8_UINT:
68 case PIPE_FORMAT_Z24X8_UNORM:
69 case PIPE_FORMAT_Z24_UNORM_S8_UINT:
70 if (compressed)
71 tile_flags = 0x17 + ms;
72 else
73 tile_flags = 0x11;
74 break;
75 case PIPE_FORMAT_Z32_FLOAT:
76 if (compressed)
77 tile_flags = 0x86 + ms;
78 else
79 tile_flags = 0x7b;
80 break;
81 case PIPE_FORMAT_X32_S8X24_UINT:
82 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
83 if (compressed)
84 tile_flags = 0xce + ms;
85 else
86 tile_flags = 0xc3;
87 break;
88 default:
89 switch (util_format_get_blocksizebits(mt->base.base.format)) {
90 case 128:
91 if (compressed)
92 tile_flags = 0xf4 + ms * 2;
93 else
94 tile_flags = 0xfe;
95 break;
96 case 64:
97 if (compressed) {
98 switch (ms) {
99 case 0: tile_flags = 0xe6; break;
100 case 1: tile_flags = 0xeb; break;
101 case 2: tile_flags = 0xed; break;
102 case 3: tile_flags = 0xf2; break;
103 default:
104 return 0;
105 }
106 } else {
107 tile_flags = 0xfe;
108 }
109 break;
110 case 32:
111 if (compressed && ms) {
112 switch (ms) {
113 /* This one makes things blurry:
114 case 0: tile_flags = 0xdb; break;
115 */
116 case 1: tile_flags = 0xdd; break;
117 case 2: tile_flags = 0xdf; break;
118 case 3: tile_flags = 0xe4; break;
119 default:
120 return 0;
121 }
122 } else {
123 tile_flags = 0xfe;
124 }
125 break;
126 case 16:
127 case 8:
128 tile_flags = 0xfe;
129 break;
130 default:
131 return 0;
132 }
133 break;
134 }
135
136 return tile_flags;
137 }
138
139 static inline bool
140 nvc0_miptree_init_ms_mode(struct nv50_miptree *mt)
141 {
142 switch (mt->base.base.nr_samples) {
143 case 8:
144 mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS8;
145 mt->ms_x = 2;
146 mt->ms_y = 1;
147 break;
148 case 4:
149 mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS4;
150 mt->ms_x = 1;
151 mt->ms_y = 1;
152 break;
153 case 2:
154 mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS2;
155 mt->ms_x = 1;
156 break;
157 case 1:
158 case 0:
159 mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS1;
160 break;
161 default:
162 NOUVEAU_ERR("invalid nr_samples: %u\n", mt->base.base.nr_samples);
163 return false;
164 }
165 return true;
166 }
167
168 static void
169 nvc0_miptree_init_layout_video(struct nv50_miptree *mt)
170 {
171 const struct pipe_resource *pt = &mt->base.base;
172 const unsigned blocksize = util_format_get_blocksize(pt->format);
173
174 assert(pt->last_level == 0);
175 assert(mt->ms_x == 0 && mt->ms_y == 0);
176 assert(!util_format_is_compressed(pt->format));
177
178 mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
179
180 mt->level[0].tile_mode = 0x10;
181 mt->level[0].pitch = align(pt->width0 * blocksize, 64);
182 mt->total_size = align(pt->height0, 16) * mt->level[0].pitch * (mt->layout_3d ? pt->depth0 : 1);
183
184 if (pt->array_size > 1) {
185 mt->layer_stride = align(mt->total_size, NVC0_TILE_SIZE(0x10));
186 mt->total_size = mt->layer_stride * pt->array_size;
187 }
188 }
189
190 static void
191 nvc0_miptree_init_layout_tiled(struct nv50_miptree *mt)
192 {
193 struct pipe_resource *pt = &mt->base.base;
194 unsigned w, h, d, l;
195 const unsigned blocksize = util_format_get_blocksize(pt->format);
196
197 mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
198
199 w = pt->width0 << mt->ms_x;
200 h = pt->height0 << mt->ms_y;
201
202 /* For 3D textures, a mipmap is spanned by all the layers, for array
203 * textures and cube maps, each layer contains its own mipmaps.
204 */
205 d = mt->layout_3d ? pt->depth0 : 1;
206
207 assert(!mt->ms_mode || !pt->last_level);
208
209 for (l = 0; l <= pt->last_level; ++l) {
210 struct nv50_miptree_level *lvl = &mt->level[l];
211 unsigned tsx, tsy, tsz;
212 unsigned nbx = util_format_get_nblocksx(pt->format, w);
213 unsigned nby = util_format_get_nblocksy(pt->format, h);
214
215 lvl->offset = mt->total_size;
216
217 lvl->tile_mode = nvc0_tex_choose_tile_dims(nbx, nby, d, mt->layout_3d);
218
219 tsx = NVC0_TILE_SIZE_X(lvl->tile_mode); /* x is tile row pitch in bytes */
220 tsy = NVC0_TILE_SIZE_Y(lvl->tile_mode);
221 tsz = NVC0_TILE_SIZE_Z(lvl->tile_mode);
222
223 lvl->pitch = align(nbx * blocksize, tsx);
224
225 mt->total_size += lvl->pitch * align(nby, tsy) * align(d, tsz);
226
227 w = u_minify(w, 1);
228 h = u_minify(h, 1);
229 d = u_minify(d, 1);
230 }
231
232 if (pt->array_size > 1) {
233 mt->layer_stride = align(mt->total_size,
234 NVC0_TILE_SIZE(mt->level[0].tile_mode));
235 mt->total_size = mt->layer_stride * pt->array_size;
236 }
237 }
238
239 static uint64_t nvc0_miptree_get_modifier(struct nv50_miptree *mt)
240 {
241 union nouveau_bo_config *config = &mt->base.bo->config;
242 uint64_t modifier;
243
244 if (mt->layout_3d)
245 return DRM_FORMAT_MOD_INVALID;
246
247 switch (config->nvc0.memtype) {
248 case 0x00:
249 modifier = DRM_FORMAT_MOD_LINEAR;
250 break;
251
252 case 0xfe:
253 switch (NVC0_TILE_MODE_Y(config->nvc0.tile_mode)) {
254 case 0:
255 modifier = DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_ONE_GOB;
256 break;
257
258 case 1:
259 modifier = DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_TWO_GOB;
260 break;
261
262 case 2:
263 modifier = DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_FOUR_GOB;
264 break;
265
266 case 3:
267 modifier = DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_EIGHT_GOB;
268 break;
269
270 case 4:
271 modifier = DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_SIXTEEN_GOB;
272 break;
273
274 case 5:
275 modifier = DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB;
276 break;
277
278 default:
279 modifier = DRM_FORMAT_MOD_INVALID;
280 break;
281 }
282 break;
283
284 default:
285 modifier = DRM_FORMAT_MOD_INVALID;
286 break;
287 }
288
289 return modifier;
290 }
291
292 static boolean
293 nvc0_miptree_get_handle(struct pipe_screen *pscreen,
294 struct pipe_resource *pt,
295 struct winsys_handle *whandle)
296 {
297 struct nv50_miptree *mt = nv50_miptree(pt);
298 boolean ret;
299
300 ret = nv50_miptree_get_handle(pscreen, pt, whandle);
301 if (!ret)
302 return ret;
303
304 whandle->modifier = nvc0_miptree_get_modifier(mt);
305
306 return true;
307 }
308
309 const struct u_resource_vtbl nvc0_miptree_vtbl =
310 {
311 nvc0_miptree_get_handle, /* get_handle */
312 nv50_miptree_destroy, /* resource_destroy */
313 nvc0_miptree_transfer_map, /* transfer_map */
314 u_default_transfer_flush_region, /* transfer_flush_region */
315 nvc0_miptree_transfer_unmap, /* transfer_unmap */
316 };
317
318 struct pipe_resource *
319 nvc0_miptree_create(struct pipe_screen *pscreen,
320 const struct pipe_resource *templ,
321 const uint64_t *modifiers, unsigned int count)
322 {
323 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
324 struct nouveau_drm *drm = nouveau_screen(pscreen)->drm;
325 struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree);
326 struct pipe_resource *pt = &mt->base.base;
327 bool compressed = drm->version >= 0x01000101;
328 int ret;
329 union nouveau_bo_config bo_config;
330 uint32_t bo_flags;
331
332 if (!mt)
333 return NULL;
334
335 mt->base.vtbl = &nvc0_miptree_vtbl;
336 *pt = *templ;
337 pipe_reference_init(&pt->reference, 1);
338 pt->screen = pscreen;
339
340 if (pt->usage == PIPE_USAGE_STAGING) {
341 switch (pt->target) {
342 case PIPE_TEXTURE_2D:
343 case PIPE_TEXTURE_RECT:
344 if (pt->last_level == 0 &&
345 !util_format_is_depth_or_stencil(pt->format) &&
346 pt->nr_samples <= 1)
347 pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
348 break;
349 default:
350 break;
351 }
352 }
353
354 if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_LINEAR)
355 pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
356
357 if (pt->bind & PIPE_BIND_LINEAR)
358 pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;
359
360 bo_config.nvc0.memtype = nvc0_mt_choose_storage_type(mt, compressed);
361
362 if (!nvc0_miptree_init_ms_mode(mt)) {
363 FREE(mt);
364 return NULL;
365 }
366
367 if (unlikely(pt->flags & NVC0_RESOURCE_FLAG_VIDEO)) {
368 nvc0_miptree_init_layout_video(mt);
369 } else
370 if (likely(bo_config.nvc0.memtype)) {
371 nvc0_miptree_init_layout_tiled(mt);
372 } else
373 if (!nv50_miptree_init_layout_linear(mt, 128)) {
374 FREE(mt);
375 return NULL;
376 }
377 bo_config.nvc0.tile_mode = mt->level[0].tile_mode;
378
379 if (!bo_config.nvc0.memtype && (pt->usage == PIPE_USAGE_STAGING || pt->bind & PIPE_BIND_SHARED))
380 mt->base.domain = NOUVEAU_BO_GART;
381 else
382 mt->base.domain = NV_VRAM_DOMAIN(nouveau_screen(pscreen));
383
384 bo_flags = mt->base.domain | NOUVEAU_BO_NOSNOOP;
385
386 if (mt->base.base.bind & (PIPE_BIND_CURSOR | PIPE_BIND_DISPLAY_TARGET))
387 bo_flags |= NOUVEAU_BO_CONTIG;
388
389 ret = nouveau_bo_new(dev, bo_flags, 4096, mt->total_size, &bo_config,
390 &mt->base.bo);
391 if (ret) {
392 FREE(mt);
393 return NULL;
394 }
395 mt->base.address = mt->base.bo->offset;
396
397 NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_count, 1);
398 NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_bytes,
399 mt->total_size);
400
401 return pt;
402 }
403
404 /* Offset of zslice @z from start of level @l. */
405 inline unsigned
406 nvc0_mt_zslice_offset(const struct nv50_miptree *mt, unsigned l, unsigned z)
407 {
408 const struct pipe_resource *pt = &mt->base.base;
409
410 unsigned tds = NVC0_TILE_SHIFT_Z(mt->level[l].tile_mode);
411 unsigned ths = NVC0_TILE_SHIFT_Y(mt->level[l].tile_mode);
412
413 unsigned nby = util_format_get_nblocksy(pt->format,
414 u_minify(pt->height0, l));
415
416 /* to next 2D tile slice within a 3D tile */
417 unsigned stride_2d = NVC0_TILE_SIZE_2D(mt->level[l].tile_mode);
418
419 /* to slice in the next (in z direction) 3D tile */
420 unsigned stride_3d = (align(nby, (1 << ths)) * mt->level[l].pitch) << tds;
421
422 return (z & (1 << (tds - 1))) * stride_2d + (z >> tds) * stride_3d;
423 }
424
425 /* Surface functions.
426 */
427
428 struct pipe_surface *
429 nvc0_miptree_surface_new(struct pipe_context *pipe,
430 struct pipe_resource *pt,
431 const struct pipe_surface *templ)
432 {
433 struct nv50_surface *ns = nv50_surface_from_miptree(nv50_miptree(pt), templ);
434 if (!ns)
435 return NULL;
436 ns->base.context = pipe;
437 return &ns->base;
438 }