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