Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 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 "nv50_context.h"
29
#include "nv50_resource.h"
30
 
31
uint32_t
32
nv50_tex_choose_tile_dims_helper(unsigned nx, unsigned ny, unsigned nz)
33
{
34
   uint32_t tile_mode = 0x000;
35
 
36
   if (ny > 64) tile_mode = 0x040; /* height 128 tiles */
37
   else
38
   if (ny > 32) tile_mode = 0x030; /* height 64 tiles */
39
   else
40
   if (ny > 16) tile_mode = 0x020; /* height 32 tiles */
41
   else
42
   if (ny >  8) tile_mode = 0x010; /* height 16 tiles */
43
 
44
   if (nz == 1)
45
      return tile_mode;
46
   else
47
      if (tile_mode > 0x020)
48
         tile_mode = 0x020;
49
 
50
   if (nz > 16 && tile_mode < 0x020)
51
      return tile_mode | 0x500; /* depth 32 tiles */
52
   if (nz > 8) return tile_mode | 0x400; /* depth 16 tiles */
53
   if (nz > 4) return tile_mode | 0x300; /* depth 8 tiles */
54
   if (nz > 2) return tile_mode | 0x200; /* depth 4 tiles */
55
 
56
   return tile_mode | 0x100;
57
}
58
 
59
static uint32_t
60
nv50_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz)
61
{
62
   return nv50_tex_choose_tile_dims_helper(nx, ny * 2, nz);
63
}
64
 
65
static uint32_t
66
nv50_mt_choose_storage_type(struct nv50_miptree *mt, boolean compressed)
67
{
68
   const unsigned ms = mt->ms_x + mt->ms_y;
69
 
70
   uint32_t tile_flags;
71
 
72
   if (unlikely(mt->base.base.flags & NOUVEAU_RESOURCE_FLAG_LINEAR))
73
      return 0;
74
   if (unlikely(mt->base.base.bind & PIPE_BIND_CURSOR))
75
      return 0;
76
 
77
   switch (mt->base.base.format) {
78
   case PIPE_FORMAT_Z16_UNORM:
79
      tile_flags = 0x6c + ms;
80
      break;
81
   case PIPE_FORMAT_S8_UINT_Z24_UNORM:
82
      tile_flags = 0x18 + ms;
83
      break;
84
   case PIPE_FORMAT_Z24X8_UNORM:
85
   case PIPE_FORMAT_Z24_UNORM_S8_UINT:
86
      tile_flags = 0x128 + ms;
87
      break;
88
   case PIPE_FORMAT_Z32_FLOAT:
89
      tile_flags = 0x40 + ms;
90
      break;
91
   case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
92
      tile_flags = 0x60 + ms;
93
      break;
94
   default:
95
      switch (util_format_get_blocksizebits(mt->base.base.format)) {
96
      case 128:
97
         assert(ms < 3);
98
         tile_flags = 0x74;
99
         break;
100
      case 64:
101
         switch (ms) {
102
         case 2: tile_flags = 0xfc; break;
103
         case 3: tile_flags = 0xfd; break;
104
         default:
105
            tile_flags = 0x70;
106
            break;
107
         }
108
         break;
109
      case 32:
110
         if (mt->base.base.bind & PIPE_BIND_SCANOUT) {
111
            assert(ms == 0);
112
            tile_flags = 0x7a;
113
         } else {
114
            switch (ms) {
115
            case 2: tile_flags = 0xf8; break;
116
            case 3: tile_flags = 0xf9; break;
117
            default:
118
               tile_flags = 0x70;
119
               break;
120
            }
121
         }
122
         break;
123
      case 16:
124
      case 8:
125
         tile_flags = 0x70;
126
         break;
127
      default:
128
         return 0;
129
      }
130
      if (mt->base.base.bind & PIPE_BIND_CURSOR)
131
         tile_flags = 0;
132
   }
133
 
134
   if (!compressed)
135
      tile_flags &= ~0x180;
136
 
137
   return tile_flags;
138
}
139
 
140
void
141
nv50_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt)
142
{
143
   struct nv50_miptree *mt = nv50_miptree(pt);
144
 
145
   nouveau_bo_ref(NULL, &mt->base.bo);
146
 
147
   nouveau_fence_ref(NULL, &mt->base.fence);
148
   nouveau_fence_ref(NULL, &mt->base.fence_wr);
149
 
150
   NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_count, -1);
151
   NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_bytes,
152
                    -(uint64_t)mt->total_size);
153
 
154
   FREE(mt);
155
}
156
 
157
boolean
158
nv50_miptree_get_handle(struct pipe_screen *pscreen,
159
                        struct pipe_resource *pt,
160
                        struct winsys_handle *whandle)
161
{
162
   struct nv50_miptree *mt = nv50_miptree(pt);
163
   unsigned stride;
164
 
165
   if (!mt || !mt->base.bo)
166
      return FALSE;
167
 
168
   stride = mt->level[0].pitch;
169
 
170
   return nouveau_screen_bo_get_handle(pscreen,
171
                                       mt->base.bo,
172
                                       stride,
173
                                       whandle);
174
}
175
 
176
const struct u_resource_vtbl nv50_miptree_vtbl =
177
{
178
   nv50_miptree_get_handle,         /* get_handle */
179
   nv50_miptree_destroy,            /* resource_destroy */
180
   nv50_miptree_transfer_map,       /* transfer_map */
181
   u_default_transfer_flush_region, /* transfer_flush_region */
182
   nv50_miptree_transfer_unmap,     /* transfer_unmap */
183
   u_default_transfer_inline_write  /* transfer_inline_write */
184
};
185
 
186
static INLINE boolean
187
nv50_miptree_init_ms_mode(struct nv50_miptree *mt)
188
{
189
   switch (mt->base.base.nr_samples) {
190
   case 8:
191
      mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS8;
192
      mt->ms_x = 2;
193
      mt->ms_y = 1;
194
      break;
195
   case 4:
196
      mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS4;
197
      mt->ms_x = 1;
198
      mt->ms_y = 1;
199
      break;
200
   case 2:
201
      mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS2;
202
      mt->ms_x = 1;
203
      break;
204
   case 1:
205
   case 0:
206
      mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS1;
207
      break;
208
   default:
209
      NOUVEAU_ERR("invalid nr_samples: %u\n", mt->base.base.nr_samples);
210
      return FALSE;
211
   }
212
   return TRUE;
213
}
214
 
215
boolean
216
nv50_miptree_init_layout_linear(struct nv50_miptree *mt, unsigned pitch_align)
217
{
218
   struct pipe_resource *pt = &mt->base.base;
219
   const unsigned blocksize = util_format_get_blocksize(pt->format);
220
   unsigned h = pt->height0;
221
 
222
   if (util_format_is_depth_or_stencil(pt->format))
223
      return FALSE;
224
 
225
   if ((pt->last_level > 0) || (pt->depth0 > 1) || (pt->array_size > 1))
226
      return FALSE;
227
   if (mt->ms_x | mt->ms_y)
228
      return FALSE;
229
 
230
   mt->level[0].pitch = align(pt->width0 * blocksize, pitch_align);
231
 
232
   /* Account for very generous prefetch (allocate size as if tiled). */
233
   h = MAX2(h, 8);
234
   h = util_next_power_of_two(h);
235
 
236
   mt->total_size = mt->level[0].pitch * h;
237
 
238
   return TRUE;
239
}
240
 
241
static void
242
nv50_miptree_init_layout_video(struct nv50_miptree *mt)
243
{
244
   const struct pipe_resource *pt = &mt->base.base;
245
   const unsigned blocksize = util_format_get_blocksize(pt->format);
246
 
247
   assert(pt->last_level == 0);
248
   assert(mt->ms_x == 0 && mt->ms_y == 0);
249
   assert(!util_format_is_compressed(pt->format));
250
 
251
   mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
252
 
253
   mt->level[0].tile_mode = 0x20;
254
   mt->level[0].pitch = align(pt->width0 * blocksize, 64);
255
   mt->total_size = align(pt->height0, 16) * mt->level[0].pitch * (mt->layout_3d ? pt->depth0 : 1);
256
 
257
   if (pt->array_size > 1) {
258
      mt->layer_stride = align(mt->total_size, NV50_TILE_SIZE(0x20));
259
      mt->total_size = mt->layer_stride * pt->array_size;
260
   }
261
}
262
 
263
static void
264
nv50_miptree_init_layout_tiled(struct nv50_miptree *mt)
265
{
266
   struct pipe_resource *pt = &mt->base.base;
267
   unsigned w, h, d, l;
268
   const unsigned blocksize = util_format_get_blocksize(pt->format);
269
 
270
   mt->layout_3d = pt->target == PIPE_TEXTURE_3D;
271
 
272
   w = pt->width0 << mt->ms_x;
273
   h = pt->height0 << mt->ms_y;
274
 
275
   /* For 3D textures, a mipmap is spanned by all the layers, for array
276
    * textures and cube maps, each layer contains its own mipmaps.
277
    */
278
   d = mt->layout_3d ? pt->depth0 : 1;
279
 
280
   for (l = 0; l <= pt->last_level; ++l) {
281
      struct nv50_miptree_level *lvl = &mt->level[l];
282
      unsigned tsx, tsy, tsz;
283
      unsigned nbx = util_format_get_nblocksx(pt->format, w);
284
      unsigned nby = util_format_get_nblocksy(pt->format, h);
285
 
286
      lvl->offset = mt->total_size;
287
 
288
      lvl->tile_mode = nv50_tex_choose_tile_dims(nbx, nby, d);
289
 
290
      tsx = NV50_TILE_SIZE_X(lvl->tile_mode); /* x is tile row pitch in bytes */
291
      tsy = NV50_TILE_SIZE_Y(lvl->tile_mode);
292
      tsz = NV50_TILE_SIZE_Z(lvl->tile_mode);
293
 
294
      lvl->pitch = align(nbx * blocksize, tsx);
295
 
296
      mt->total_size += lvl->pitch * align(nby, tsy) * align(d, tsz);
297
 
298
      w = u_minify(w, 1);
299
      h = u_minify(h, 1);
300
      d = u_minify(d, 1);
301
   }
302
 
303
   if (pt->array_size > 1) {
304
      mt->layer_stride = align(mt->total_size,
305
                               NV50_TILE_SIZE(mt->level[0].tile_mode));
306
      mt->total_size = mt->layer_stride * pt->array_size;
307
   }
308
}
309
 
310
struct pipe_resource *
311
nv50_miptree_create(struct pipe_screen *pscreen,
312
                    const struct pipe_resource *templ)
313
{
314
   struct nouveau_device *dev = nouveau_screen(pscreen)->device;
315
   struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree);
316
   struct pipe_resource *pt = &mt->base.base;
317
   int ret;
318
   union nouveau_bo_config bo_config;
319
   uint32_t bo_flags;
320
 
321
   if (!mt)
322
      return NULL;
323
 
324
   mt->base.vtbl = &nv50_miptree_vtbl;
325
   *pt = *templ;
326
   pipe_reference_init(&pt->reference, 1);
327
   pt->screen = pscreen;
328
 
329
   bo_config.nv50.memtype = nv50_mt_choose_storage_type(mt, TRUE);
330
 
331
   if (!nv50_miptree_init_ms_mode(mt)) {
332
      FREE(mt);
333
      return NULL;
334
   }
335
 
336
   if (unlikely(pt->flags & NV50_RESOURCE_FLAG_VIDEO)) {
337
      nv50_miptree_init_layout_video(mt);
338
      /* BO allocation done by client */
339
      return pt;
340
   } else
341
   if (bo_config.nv50.memtype != 0) {
342
      nv50_miptree_init_layout_tiled(mt);
343
   } else
344
   if (!nv50_miptree_init_layout_linear(mt, 64)) {
345
      FREE(mt);
346
      return NULL;
347
   }
348
   bo_config.nv50.tile_mode = mt->level[0].tile_mode;
349
 
350
   bo_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP;
351
   if (mt->base.base.bind & (PIPE_BIND_CURSOR | PIPE_BIND_DISPLAY_TARGET))
352
      bo_flags |= NOUVEAU_BO_CONTIG;
353
 
354
   ret = nouveau_bo_new(dev, bo_flags, 4096, mt->total_size, &bo_config,
355
                        &mt->base.bo);
356
   if (ret) {
357
      FREE(mt);
358
      return NULL;
359
   }
360
   mt->base.domain = NOUVEAU_BO_VRAM;
361
   mt->base.address = mt->base.bo->offset;
362
 
363
   return pt;
364
}
365
 
366
struct pipe_resource *
367
nv50_miptree_from_handle(struct pipe_screen *pscreen,
368
                         const struct pipe_resource *templ,
369
                         struct winsys_handle *whandle)
370
{
371
   struct nv50_miptree *mt;
372
   unsigned stride;
373
 
374
   /* only supports 2D, non-mipmapped textures for the moment */
375
   if ((templ->target != PIPE_TEXTURE_2D &&
376
        templ->target != PIPE_TEXTURE_RECT) ||
377
       templ->last_level != 0 ||
378
       templ->depth0 != 1 ||
379
       templ->array_size > 1)
380
      return NULL;
381
 
382
   mt = CALLOC_STRUCT(nv50_miptree);
383
   if (!mt)
384
      return NULL;
385
 
386
   mt->base.bo = nouveau_screen_bo_from_handle(pscreen, whandle, &stride);
387
   if (mt->base.bo == NULL) {
388
      FREE(mt);
389
      return NULL;
390
   }
391
   mt->base.domain = NOUVEAU_BO_VRAM;
392
   mt->base.address = mt->base.bo->offset;
393
 
394
   mt->base.base = *templ;
395
   mt->base.vtbl = &nv50_miptree_vtbl;
396
   pipe_reference_init(&mt->base.base.reference, 1);
397
   mt->base.base.screen = pscreen;
398
   mt->level[0].pitch = stride;
399
   mt->level[0].offset = 0;
400
   mt->level[0].tile_mode = mt->base.bo->config.nv50.tile_mode;
401
 
402
   /* no need to adjust bo reference count */
403
   return &mt->base.base;
404
}
405
 
406
 
407
/* Offset of zslice @z from start of level @l. */
408
INLINE unsigned
409
nv50_mt_zslice_offset(const struct nv50_miptree *mt, unsigned l, unsigned z)
410
{
411
   const struct pipe_resource *pt = &mt->base.base;
412
 
413
   unsigned tds = NV50_TILE_SHIFT_Z(mt->level[l].tile_mode);
414
   unsigned ths = NV50_TILE_SHIFT_Y(mt->level[l].tile_mode);
415
 
416
   unsigned nby = util_format_get_nblocksy(pt->format,
417
                                           u_minify(pt->height0, l));
418
 
419
   /* to next 2D tile slice within a 3D tile */
420
   unsigned stride_2d = NV50_TILE_SIZE_2D(mt->level[l].tile_mode);
421
 
422
   /* to slice in the next (in z direction) 3D tile */
423
   unsigned stride_3d = (align(nby, (1 << ths)) * mt->level[l].pitch) << tds;
424
 
425
   return (z & ((1 << tds) - 1)) * stride_2d + (z >> tds) * stride_3d;
426
}
427
 
428
/* Surface functions.
429
 */
430
 
431
struct nv50_surface *
432
nv50_surface_from_miptree(struct nv50_miptree *mt,
433
                          const struct pipe_surface *templ)
434
{
435
   struct pipe_surface *ps;
436
   struct nv50_surface *ns = CALLOC_STRUCT(nv50_surface);
437
   if (!ns)
438
      return NULL;
439
   ps = &ns->base;
440
 
441
   pipe_reference_init(&ps->reference, 1);
442
   pipe_resource_reference(&ps->texture, &mt->base.base);
443
 
444
   ps->format = templ->format;
445
   ps->writable = templ->writable;
446
   ps->u.tex.level = templ->u.tex.level;
447
   ps->u.tex.first_layer = templ->u.tex.first_layer;
448
   ps->u.tex.last_layer = templ->u.tex.last_layer;
449
 
450
   ns->width = u_minify(mt->base.base.width0, ps->u.tex.level);
451
   ns->height = u_minify(mt->base.base.height0, ps->u.tex.level);
452
   ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;
453
   ns->offset = mt->level[templ->u.tex.level].offset;
454
 
455
   /* comment says there are going to be removed, but they're used by the st */
456
   ps->width = ns->width;
457
   ps->height = ns->height;
458
 
459
   ns->width <<= mt->ms_x;
460
   ns->height <<= mt->ms_y;
461
 
462
   return ns;
463
}
464
 
465
struct pipe_surface *
466
nv50_miptree_surface_new(struct pipe_context *pipe,
467
                         struct pipe_resource *pt,
468
                         const struct pipe_surface *templ)
469
{
470
   struct nv50_miptree *mt = nv50_miptree(pt);
471
   struct nv50_surface *ns = nv50_surface_from_miptree(mt, templ);
472
   if (!ns)
473
      return NULL;
474
   ns->base.context = pipe;
475
 
476
   if (ns->base.u.tex.first_layer) {
477
      const unsigned l = ns->base.u.tex.level;
478
      const unsigned z = ns->base.u.tex.first_layer;
479
 
480
      if (mt->layout_3d) {
481
         ns->offset += nv50_mt_zslice_offset(mt, l, z);
482
 
483
         /* TODO: switch to depth 1 tiles; but actually this shouldn't happen */
484
         if (ns->depth > 1 &&
485
             (z & (NV50_TILE_SIZE_Z(mt->level[l].tile_mode) - 1)))
486
            NOUVEAU_ERR("Creating unsupported 3D surface !\n");
487
      } else {
488
         ns->offset += mt->layer_stride * z;
489
      }
490
   }
491
 
492
   return &ns->base;
493
}