c80f7f493268af28190ddc55d64d913f7920d0d5
[platform/upstream/libdrm.git] / radeon / radeon_surface.c
1 /*
2  * Copyright © 2011 Red Hat All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sub license, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
14  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15  * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
16  * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19  * USE OR OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * The above copyright notice and this permission notice (including the
22  * next paragraph) shall be included in all copies or substantial portions
23  * of the Software.
24  */
25 /*
26  * Authors:
27  *      Jérôme Glisse <jglisse@redhat.com>
28  */
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/mman.h>
34 #include <sys/ioctl.h>
35 #include "drm.h"
36 #include "xf86drm.h"
37 #include "radeon_drm.h"
38 #include "radeon_surface.h"
39
40 #define ALIGN(value, alignment) (((value) + alignment - 1) & ~(alignment - 1))
41 #define MAX2(A, B)              ((A) > (B) ? (A) : (B))
42 #define MIN2(A, B)              ((A) < (B) ? (A) : (B))
43
44 /* keep this private */
45 enum radeon_family {
46     CHIP_UNKNOWN,
47     CHIP_R600,
48     CHIP_RV610,
49     CHIP_RV630,
50     CHIP_RV670,
51     CHIP_RV620,
52     CHIP_RV635,
53     CHIP_RS780,
54     CHIP_RS880,
55     CHIP_RV770,
56     CHIP_RV730,
57     CHIP_RV710,
58     CHIP_RV740,
59     CHIP_CEDAR,
60     CHIP_REDWOOD,
61     CHIP_JUNIPER,
62     CHIP_CYPRESS,
63     CHIP_HEMLOCK,
64     CHIP_PALM,
65     CHIP_SUMO,
66     CHIP_SUMO2,
67     CHIP_BARTS,
68     CHIP_TURKS,
69     CHIP_CAICOS,
70     CHIP_CAYMAN,
71     CHIP_ARUBA,
72     CHIP_TAHITI,
73     CHIP_PITCAIRN,
74     CHIP_VERDE,
75     CHIP_LAST,
76 };
77
78 typedef int (*hw_init_surface_t)(struct radeon_surface_manager *surf_man,
79                                  struct radeon_surface *surf);
80 typedef int (*hw_best_surface_t)(struct radeon_surface_manager *surf_man,
81                                  struct radeon_surface *surf);
82
83 struct radeon_hw_info {
84     /* apply to r6, eg */
85     uint32_t                    group_bytes;
86     uint32_t                    num_banks;
87     uint32_t                    num_pipes;
88     /* apply to eg */
89     uint32_t                    row_size;
90     unsigned                    allow_2d;
91 };
92
93 struct radeon_surface_manager {
94     int                         fd;
95     uint32_t                    device_id;
96     struct radeon_hw_info       hw_info;
97     unsigned                    family;
98     hw_init_surface_t           surface_init;
99     hw_best_surface_t           surface_best;
100 };
101
102 /* helper */
103 static int radeon_get_value(int fd, unsigned req, uint32_t *value)
104 {
105     struct drm_radeon_info info = {};
106     int r;
107
108     *value = 0;
109     info.request = req;
110     info.value = (uintptr_t)value;
111     r = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info,
112                             sizeof(struct drm_radeon_info));
113     return r;
114 }
115
116 static int radeon_get_family(struct radeon_surface_manager *surf_man)
117 {
118     switch (surf_man->device_id) {
119 #define CHIPSET(pci_id, name, fam) case pci_id: surf_man->family = CHIP_##fam; break;
120 #include "r600_pci_ids.h"
121 #undef CHIPSET
122     default:
123         return -EINVAL;
124     }
125     return 0;
126 }
127
128 static unsigned next_power_of_two(unsigned x)
129 {
130    if (x <= 1)
131        return 1;
132
133    return (1 << ((sizeof(unsigned) * 8) - __builtin_clz(x - 1)));
134 }
135
136 static unsigned mip_minify(unsigned size, unsigned level)
137 {
138     unsigned val;
139
140     val = MAX2(1, size >> level);
141     if (level > 0)
142         val = next_power_of_two(val);
143     return val;
144 }
145
146 static void surf_minify(struct radeon_surface *surf,
147                         unsigned level,
148                         uint32_t xalign, uint32_t yalign, uint32_t zalign,
149                         unsigned offset)
150 {
151     surf->level[level].npix_x = mip_minify(surf->npix_x, level);
152     surf->level[level].npix_y = mip_minify(surf->npix_y, level);
153     surf->level[level].npix_z = mip_minify(surf->npix_z, level);
154     surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w;
155     surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h;
156     surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d;
157     if (surf->level[level].mode == RADEON_SURF_MODE_2D) {
158         if (surf->level[level].nblk_x < xalign || surf->level[level].nblk_y < yalign) {
159             surf->level[level].mode = RADEON_SURF_MODE_1D;
160             return;
161         }
162     }
163     surf->level[level].nblk_x  = ALIGN(surf->level[level].nblk_x, xalign);
164     surf->level[level].nblk_y  = ALIGN(surf->level[level].nblk_y, yalign);
165     surf->level[level].nblk_z  = ALIGN(surf->level[level].nblk_z, zalign);
166
167     surf->level[level].offset = offset;
168     surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe;
169     surf->level[level].slice_size = surf->level[level].pitch_bytes * surf->level[level].nblk_y;
170
171     surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size;
172 }
173
174 /* ===========================================================================
175  * r600/r700 family
176  */
177 static int r6_init_hw_info(struct radeon_surface_manager *surf_man)
178 {
179     uint32_t tiling_config;
180     drmVersionPtr version;
181     int r;
182
183     r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
184                          &tiling_config);
185     if (r) {
186         return r;
187     }
188
189     surf_man->hw_info.allow_2d = 0;
190     version = drmGetVersion(surf_man->fd);
191     if (version && version->version_minor >= 14) {
192         surf_man->hw_info.allow_2d = 1;
193     }
194     drmFreeVersion(version);
195
196     switch ((tiling_config & 0xe) >> 1) {
197     case 0:
198         surf_man->hw_info.num_pipes = 1;
199         break;
200     case 1:
201         surf_man->hw_info.num_pipes = 2;
202         break;
203     case 2:
204         surf_man->hw_info.num_pipes = 4;
205         break;
206     case 3:
207         surf_man->hw_info.num_pipes = 8;
208         break;
209     default:
210         surf_man->hw_info.num_pipes = 8;
211         surf_man->hw_info.allow_2d = 0;
212         break;
213     }
214
215     switch ((tiling_config & 0x30) >> 4) {
216     case 0:
217         surf_man->hw_info.num_banks = 4;
218         break;
219     case 1:
220         surf_man->hw_info.num_banks = 8;
221         break;
222     default:
223         surf_man->hw_info.num_banks = 8;
224         surf_man->hw_info.allow_2d = 0;
225         break;
226     }
227
228     switch ((tiling_config & 0xc0) >> 6) {
229     case 0:
230         surf_man->hw_info.group_bytes = 256;
231         break;
232     case 1:
233         surf_man->hw_info.group_bytes = 512;
234         break;
235     default:
236         surf_man->hw_info.group_bytes = 256;
237         surf_man->hw_info.allow_2d = 0;
238         break;
239     }
240     return 0;
241 }
242
243 static int r6_surface_init_linear(struct radeon_surface_manager *surf_man,
244                                   struct radeon_surface *surf,
245                                   uint64_t offset, unsigned start_level)
246 {
247     uint32_t xalign, yalign, zalign;
248     unsigned i;
249
250     /* compute alignment */
251     if (!start_level) {
252         surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
253     }
254     /* the 32 alignment is for scanout, cb or db but to allow texture to be
255      * easily bound as such we force this alignment to all surface
256      */
257     xalign = MAX2(1, surf_man->hw_info.group_bytes / surf->bpe);
258     yalign = 1;
259     zalign = 1;
260     if (surf->flags & RADEON_SURF_SCANOUT) {
261         xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
262     }
263
264     /* build mipmap tree */
265     for (i = start_level; i <= surf->last_level; i++) {
266         surf->level[i].mode = RADEON_SURF_MODE_LINEAR;
267         surf_minify(surf, i, xalign, yalign, zalign, offset);
268         /* level0 and first mipmap need to have alignment */
269         offset = surf->bo_size;
270         if ((i == 0)) {
271             offset = ALIGN(offset, surf->bo_alignment);
272         }
273     }
274     return 0;
275 }
276
277 static int r6_surface_init_linear_aligned(struct radeon_surface_manager *surf_man,
278                                           struct radeon_surface *surf,
279                                           uint64_t offset, unsigned start_level)
280 {
281     uint32_t xalign, yalign, zalign;
282     unsigned i;
283
284     /* compute alignment */
285     if (!start_level) {
286         surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
287     }
288     xalign = MAX2(64, surf_man->hw_info.group_bytes / surf->bpe);
289     yalign = 1;
290     zalign = 1;
291
292     /* build mipmap tree */
293     for (i = start_level; i <= surf->last_level; i++) {
294         surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
295         surf_minify(surf, i, xalign, yalign, zalign, offset);
296         /* level0 and first mipmap need to have alignment */
297         offset = surf->bo_size;
298         if ((i == 0)) {
299             offset = ALIGN(offset, surf->bo_alignment);
300         }
301     }
302     return 0;
303 }
304
305 static int r6_surface_init_1d(struct radeon_surface_manager *surf_man,
306                               struct radeon_surface *surf,
307                               uint64_t offset, unsigned start_level)
308 {
309     uint32_t xalign, yalign, zalign, tilew;
310     unsigned i;
311
312     /* compute alignment */
313     tilew = 8;
314     xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples);
315     xalign = MAX2(tilew, xalign);
316     yalign = tilew;
317     zalign = 1;
318     if (surf->flags & RADEON_SURF_SCANOUT) {
319         xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
320     }
321     if (!start_level) {
322         surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
323     }
324
325     /* build mipmap tree */
326     for (i = start_level; i <= surf->last_level; i++) {
327         surf->level[i].mode = RADEON_SURF_MODE_1D;
328         surf_minify(surf, i, xalign, yalign, zalign, offset);
329         /* level0 and first mipmap need to have alignment */
330         offset = surf->bo_size;
331         if ((i == 0)) {
332             offset = ALIGN(offset, surf->bo_alignment);
333         }
334     }
335     return 0;
336 }
337
338 static int r6_surface_init_2d(struct radeon_surface_manager *surf_man,
339                               struct radeon_surface *surf,
340                               uint64_t offset, unsigned start_level)
341 {
342     uint32_t xalign, yalign, zalign, tilew;
343     unsigned i;
344
345     /* compute alignment */
346     tilew = 8;
347     zalign = 1;
348     xalign = (surf_man->hw_info.group_bytes * surf_man->hw_info.num_banks) /
349              (tilew * surf->bpe * surf->nsamples);
350     xalign = MAX2(tilew * surf_man->hw_info.num_banks, xalign);
351     yalign = tilew * surf_man->hw_info.num_pipes;
352     if (surf->flags & RADEON_SURF_SCANOUT) {
353         xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
354     }
355     if (!start_level) {
356         surf->bo_alignment =
357             MAX2(surf_man->hw_info.num_pipes *
358                  surf_man->hw_info.num_banks *
359                  surf->bpe * 64,
360                  xalign * yalign * surf->nsamples * surf->bpe);
361     }
362
363     /* build mipmap tree */
364     for (i = start_level; i <= surf->last_level; i++) {
365         surf->level[i].mode = RADEON_SURF_MODE_2D;
366         surf_minify(surf, i, xalign, yalign, zalign, offset);
367         if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
368             return r6_surface_init_1d(surf_man, surf, offset, i);
369         }
370         /* level0 and first mipmap need to have alignment */
371         offset = surf->bo_size;
372         if ((i == 0)) {
373             offset = ALIGN(offset, surf->bo_alignment);
374         }
375     }
376     return 0;
377 }
378
379 static int r6_surface_init(struct radeon_surface_manager *surf_man,
380                            struct radeon_surface *surf)
381 {
382     unsigned mode;
383     int r;
384
385     /* tiling mode */
386     mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
387
388     /* always enable z & stencil together */
389     if (surf->flags & RADEON_SURF_ZBUFFER) {
390         surf->flags |= RADEON_SURF_SBUFFER;
391     }
392     if (surf->flags & RADEON_SURF_SBUFFER) {
393         surf->flags |= RADEON_SURF_ZBUFFER;
394     }
395     if (surf->flags & RADEON_SURF_ZBUFFER) {
396         /* zbuffer only support 1D or 2D tiled surface */
397         switch (mode) {
398         case RADEON_SURF_MODE_1D:
399         case RADEON_SURF_MODE_2D:
400             break;
401         default:
402             mode = RADEON_SURF_MODE_1D;
403             surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
404             surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
405             break;
406         }
407     }
408
409     /* force 1d on kernel that can't do 2d */
410     if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
411         mode = RADEON_SURF_MODE_1D;
412         surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
413         surf->flags |= RADEON_SURF_SET(mode, MODE);
414     }
415
416     /* check surface dimension */
417     if (surf->npix_x > 8192 || surf->npix_y > 8192 || surf->npix_z > 8192) {
418         return -EINVAL;
419     }
420
421     /* check mipmap last_level */
422     if (surf->last_level > 14) {
423         return -EINVAL;
424     }
425
426     /* check tiling mode */
427     switch (mode) {
428     case RADEON_SURF_MODE_LINEAR:
429         r = r6_surface_init_linear(surf_man, surf, 0, 0);
430         break;
431     case RADEON_SURF_MODE_LINEAR_ALIGNED:
432         r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
433         break;
434     case RADEON_SURF_MODE_1D:
435         r = r6_surface_init_1d(surf_man, surf, 0, 0);
436         break;
437     case RADEON_SURF_MODE_2D:
438         r = r6_surface_init_2d(surf_man, surf, 0, 0);
439         break;
440     default:
441         return -EINVAL;
442     }
443     return r;
444 }
445
446 static int r6_surface_best(struct radeon_surface_manager *surf_man,
447                            struct radeon_surface *surf)
448 {
449     /* no value to optimize for r6xx/r7xx */
450     return 0;
451 }
452
453
454 /* ===========================================================================
455  * evergreen family
456  */
457 static int eg_init_hw_info(struct radeon_surface_manager *surf_man)
458 {
459     uint32_t tiling_config;
460     drmVersionPtr version;
461     int r;
462
463     r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
464                          &tiling_config);
465     if (r) {
466         return r;
467     }
468
469     surf_man->hw_info.allow_2d = 0;
470     version = drmGetVersion(surf_man->fd);
471     if (version && version->version_minor >= 16) {
472         surf_man->hw_info.allow_2d = 1;
473     }
474     drmFreeVersion(version);
475
476     switch (tiling_config & 0xf) {
477     case 0:
478         surf_man->hw_info.num_pipes = 1;
479         break;
480     case 1:
481         surf_man->hw_info.num_pipes = 2;
482         break;
483     case 2:
484         surf_man->hw_info.num_pipes = 4;
485         break;
486     case 3:
487         surf_man->hw_info.num_pipes = 8;
488         break;
489     default:
490         surf_man->hw_info.num_pipes = 8;
491         surf_man->hw_info.allow_2d = 0;
492         break;
493     }
494
495     switch ((tiling_config & 0xf0) >> 4) {
496     case 0:
497         surf_man->hw_info.num_banks = 4;
498         break;
499     case 1:
500         surf_man->hw_info.num_banks = 8;
501         break;
502     case 2:
503         surf_man->hw_info.num_banks = 16;
504         break;
505     default:
506         surf_man->hw_info.num_banks = 8;
507         surf_man->hw_info.allow_2d = 0;
508         break;
509     }
510
511     switch ((tiling_config & 0xf00) >> 8) {
512     case 0:
513         surf_man->hw_info.group_bytes = 256;
514         break;
515     case 1:
516         surf_man->hw_info.group_bytes = 512;
517         break;
518     default:
519         surf_man->hw_info.group_bytes = 256;
520         surf_man->hw_info.allow_2d = 0;
521         break;
522     }
523
524     switch ((tiling_config & 0xf000) >> 12) {
525     case 0:
526         surf_man->hw_info.row_size = 1024;
527         break;
528     case 1:
529         surf_man->hw_info.row_size = 2048;
530         break;
531     case 2:
532         surf_man->hw_info.row_size = 4096;
533         break;
534     default:
535         surf_man->hw_info.row_size = 4096;
536         surf_man->hw_info.allow_2d = 0;
537         break;
538     }
539     return 0;
540 }
541
542 static void eg_surf_minify(struct radeon_surface *surf,
543                            unsigned level,
544                            unsigned slice_pt,
545                            unsigned mtilew,
546                            unsigned mtileh,
547                            unsigned mtileb,
548                            unsigned offset)
549 {
550     unsigned mtile_pr, mtile_ps;
551
552     surf->level[level].npix_x = mip_minify(surf->npix_x, level);
553     surf->level[level].npix_y = mip_minify(surf->npix_y, level);
554     surf->level[level].npix_z = mip_minify(surf->npix_z, level);
555     surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w;
556     surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h;
557     surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d;
558     if (surf->level[level].mode == RADEON_SURF_MODE_2D) {
559         if (surf->level[level].nblk_x < mtilew || surf->level[level].nblk_y < mtileh) {
560             surf->level[level].mode = RADEON_SURF_MODE_1D;
561             return;
562         }
563     }
564     surf->level[level].nblk_x  = ALIGN(surf->level[level].nblk_x, mtilew);
565     surf->level[level].nblk_y  = ALIGN(surf->level[level].nblk_y, mtileh);
566     surf->level[level].nblk_z  = ALIGN(surf->level[level].nblk_z, 1);
567
568     /* macro tile per row */
569     mtile_pr = surf->level[level].nblk_x / mtilew;
570     /* macro tile per slice */
571     mtile_ps = (mtile_pr * surf->level[level].nblk_y) / mtileh;
572
573     surf->level[level].offset = offset;
574     surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe * slice_pt;
575     surf->level[level].slice_size = mtile_ps * mtileb * slice_pt;
576
577     surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size;
578 }
579
580 static int eg_surface_init_1d(struct radeon_surface_manager *surf_man,
581                               struct radeon_surface *surf,
582                               uint64_t offset, unsigned start_level)
583 {
584     uint32_t xalign, yalign, zalign, tilew;
585     unsigned i;
586
587     /* compute alignment */
588     tilew = 8;
589     xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples);
590     if (surf->flags & RADEON_SURF_SBUFFER) {
591         xalign = surf_man->hw_info.group_bytes / (tilew * surf->nsamples);
592     }
593     xalign = MAX2(tilew, xalign);
594     yalign = tilew;
595     zalign = 1;
596     if (surf->flags & RADEON_SURF_SCANOUT) {
597         xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
598     }
599     if (!start_level) {
600         surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
601     }
602
603     /* build mipmap tree */
604     for (i = start_level; i <= surf->last_level; i++) {
605         surf->level[i].mode = RADEON_SURF_MODE_1D;
606         surf_minify(surf, i, xalign, yalign, zalign, offset);
607         /* level0 and first mipmap need to have alignment */
608         offset = surf->bo_size;
609         if ((i == 0)) {
610             offset = ALIGN(offset, surf->bo_alignment);
611         }
612     }
613
614     if (surf->flags & RADEON_SURF_SBUFFER) {
615         surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment);
616         surf->bo_size = surf->stencil_offset + surf->bo_size / 4;
617     }
618
619     return 0;
620 }
621
622 static int eg_surface_init_2d(struct radeon_surface_manager *surf_man,
623                               struct radeon_surface *surf,
624                               uint64_t offset, unsigned start_level)
625 {
626     unsigned tilew, tileh, tileb;
627     unsigned mtilew, mtileh, mtileb;
628     unsigned slice_pt;
629     unsigned i;
630
631     /* compute tile values */
632     tilew = 8;
633     tileh = 8;
634     tileb = tilew * tileh * surf->bpe * surf->nsamples;
635     /* slices per tile */
636     slice_pt = 1;
637     if (tileb > surf->tile_split) {
638         slice_pt = tileb / surf->tile_split;
639     }
640     tileb = tileb / slice_pt;
641
642     /* macro tile width & height */
643     mtilew = (tilew * surf->bankw * surf_man->hw_info.num_pipes) * surf->mtilea;
644     mtileh = (tileh * surf->bankh * surf_man->hw_info.num_banks) / surf->mtilea;
645     /* macro tile bytes */
646     mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb;
647
648     if (!start_level) {
649         surf->bo_alignment = MAX2(256, mtileb);
650     }
651
652     /* build mipmap tree */
653     for (i = start_level; i <= surf->last_level; i++) {
654         surf->level[i].mode = RADEON_SURF_MODE_2D;
655         eg_surf_minify(surf, i, slice_pt, mtilew, mtileh, mtileb, offset);
656         if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
657             return eg_surface_init_1d(surf_man, surf, offset, i);
658         }
659         /* level0 and first mipmap need to have alignment */
660         offset = surf->bo_size;
661         if ((i == 0)) {
662             offset = ALIGN(offset, surf->bo_alignment);
663         }
664     }
665
666     if (surf->flags & RADEON_SURF_SBUFFER) {
667         surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment);
668         surf->bo_size = surf->stencil_offset + surf->bo_size / 4;
669     }
670
671     return 0;
672 }
673
674 static int eg_surface_sanity(struct radeon_surface_manager *surf_man,
675                              struct radeon_surface *surf,
676                              unsigned mode)
677 {
678     unsigned tileb;
679
680     /* check surface dimension */
681     if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) {
682         return -EINVAL;
683     }
684
685     /* check mipmap last_level */
686     if (surf->last_level > 15) {
687         return -EINVAL;
688     }
689
690     /* force 1d on kernel that can't do 2d */
691     if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
692         mode = RADEON_SURF_MODE_1D;
693         surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
694         surf->flags |= RADEON_SURF_SET(mode, MODE);
695     }
696
697     /* check tile split */
698     if (mode == RADEON_SURF_MODE_2D) {
699         switch (surf->tile_split) {
700         case 64:
701         case 128:
702         case 256:
703         case 512:
704         case 1024:
705         case 2048:
706         case 4096:
707             break;
708         default:
709             return -EINVAL;
710         }
711         switch (surf->mtilea) {
712         case 1:
713         case 2:
714         case 4:
715         case 8:
716             break;
717         default:
718             return -EINVAL;
719         }
720         /* check aspect ratio */
721         if (surf_man->hw_info.num_banks < surf->mtilea) {
722             return -EINVAL;
723         }
724         /* check bank width */
725         switch (surf->bankw) {
726         case 1:
727         case 2:
728         case 4:
729         case 8:
730             break;
731         default:
732             return -EINVAL;
733         }
734         /* check bank height */
735         switch (surf->bankh) {
736         case 1:
737         case 2:
738         case 4:
739         case 8:
740             break;
741         default:
742             return -EINVAL;
743         }
744         tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
745         if ((tileb * surf->bankh * surf->bankw) < surf_man->hw_info.group_bytes) {
746             return -EINVAL;
747         }
748     }
749
750     return 0;
751 }
752
753 static int eg_surface_init(struct radeon_surface_manager *surf_man,
754                            struct radeon_surface *surf)
755 {
756     unsigned mode;
757     int r;
758
759     /* tiling mode */
760     mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
761
762     /* for some reason eg need to have room for stencil right after depth */
763     if (surf->flags & RADEON_SURF_ZBUFFER) {
764         surf->flags |= RADEON_SURF_SBUFFER;
765     }
766     if (surf->flags & RADEON_SURF_SBUFFER) {
767         surf->flags |= RADEON_SURF_ZBUFFER;
768     }
769     if (surf->flags & RADEON_SURF_ZBUFFER) {
770         /* zbuffer only support 1D or 2D tiled surface */
771         switch (mode) {
772         case RADEON_SURF_MODE_1D:
773         case RADEON_SURF_MODE_2D:
774             break;
775         default:
776             mode = RADEON_SURF_MODE_1D;
777             surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
778             surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
779             break;
780         }
781     }
782
783     r = eg_surface_sanity(surf_man, surf, mode);
784     if (r) {
785         return r;
786     }
787
788     surf->stencil_offset = 0;
789     surf->stencil_tile_split = 0;
790
791     /* check tiling mode */
792     switch (mode) {
793     case RADEON_SURF_MODE_LINEAR:
794         r = r6_surface_init_linear(surf_man, surf, 0, 0);
795         break;
796     case RADEON_SURF_MODE_LINEAR_ALIGNED:
797         r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
798         break;
799     case RADEON_SURF_MODE_1D:
800         r = eg_surface_init_1d(surf_man, surf, 0, 0);
801         break;
802     case RADEON_SURF_MODE_2D:
803         r = eg_surface_init_2d(surf_man, surf, 0, 0);
804         break;
805     default:
806         return -EINVAL;
807     }
808     return r;
809 }
810
811 static unsigned log2_int(unsigned x)
812 {
813     unsigned l;
814
815     if (x < 2) {
816         return 0;
817     }
818     for (l = 2; ; l++) {
819         if ((unsigned)(1 << l) > x) {
820             return l - 1;
821         }
822     }
823     return 0;
824 }
825
826 /* compute best tile_split, bankw, bankh, mtilea
827  * depending on surface
828  */
829 static int eg_surface_best(struct radeon_surface_manager *surf_man,
830                            struct radeon_surface *surf)
831 {
832     unsigned mode, tileb, h_over_w;
833     int r;
834
835     /* tiling mode */
836     mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
837
838     /* for some reason eg need to have room for stencil right after depth */
839     if (surf->flags & RADEON_SURF_ZBUFFER) {
840         surf->flags |= RADEON_SURF_SBUFFER;
841     }
842
843     /* set some default value to avoid sanity check choking on them */
844     surf->tile_split = 1024;
845     surf->bankw = 1;
846     surf->bankh = 1;
847     surf->mtilea = surf_man->hw_info.num_banks;
848     tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
849     for (; surf->bankh <= 8; surf->bankh *= 2) {
850         if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) {
851             break;
852         }
853     }
854     if (surf->mtilea > 8) {
855         surf->mtilea = 8;
856     }
857
858     r = eg_surface_sanity(surf_man, surf, mode);
859     if (r) {
860         return r;
861     }
862
863     if (mode != RADEON_SURF_MODE_2D) {
864         /* nothing to do for non 2D tiled surface */
865         return 0;
866     }
867
868     /* set tile split to row size, optimize latter for multi-sample surface
869      * tile split >= 256 for render buffer surface. Also depth surface want
870      * smaller value for optimal performances.
871      */
872     surf->tile_split = surf_man->hw_info.row_size;
873     surf->stencil_tile_split = surf_man->hw_info.row_size / 2;
874
875     /* bankw or bankh greater than 1 increase alignment requirement, not
876      * sure if it's worth using smaller bankw & bankh to stick with 2D
877      * tiling on small surface rather than falling back to 1D tiling.
878      * Use recommanded value based on tile size for now.
879      *
880      * fmask buffer has different optimal value figure them out once we
881      * use it.
882      */
883     if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
884         /* assume 1 bytes for stencil, we optimize for stencil as stencil
885          * and depth shares surface values
886          */
887         tileb = MIN2(surf->tile_split, 64 * surf->nsamples);
888     } else {
889         tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
890     }
891
892     /* use bankw of 1 to minimize width alignment, might be interesting to
893      * increase it for large surface
894      */
895     surf->bankw = 1;
896     switch (tileb) {
897     case 64:
898         surf->bankh = 4;
899         break;
900     case 128:
901     case 256:
902         surf->bankh = 2;
903         break;
904     default:
905         surf->bankh = 1;
906         break;
907     }
908     /* double check the constraint */
909     for (; surf->bankh <= 8; surf->bankh *= 2) {
910         if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) {
911             break;
912         }
913     }
914
915     h_over_w = (((surf->bankh * surf_man->hw_info.num_banks) << 16) /
916                 (surf->bankw * surf_man->hw_info.num_pipes)) >> 16;
917     surf->mtilea = 1 << (log2_int(h_over_w) >> 1);
918
919     return 0;
920 }
921
922
923 /* ===========================================================================
924  * public API
925  */
926 struct radeon_surface_manager *radeon_surface_manager_new(int fd)
927 {
928     struct radeon_surface_manager *surf_man;
929
930     surf_man = calloc(1, sizeof(struct radeon_surface_manager));
931     if (surf_man == NULL) {
932         return NULL;
933     }
934     surf_man->fd = fd;
935     if (radeon_get_value(fd, RADEON_INFO_DEVICE_ID, &surf_man->device_id)) {
936         goto out_err;
937     }
938     if (radeon_get_family(surf_man)) {
939         goto out_err;
940     }
941
942     if (surf_man->family <= CHIP_RV740) {
943         if (r6_init_hw_info(surf_man)) {
944             goto out_err;
945         }
946         surf_man->surface_init = &r6_surface_init;
947         surf_man->surface_best = &r6_surface_best;
948     } else {
949         if (eg_init_hw_info(surf_man)) {
950             goto out_err;
951         }
952         surf_man->surface_init = &eg_surface_init;
953         surf_man->surface_best = &eg_surface_best;
954     }
955
956     return surf_man;
957 out_err:
958     free(surf_man);
959     return NULL;
960 }
961
962 void radeon_surface_manager_free(struct radeon_surface_manager *surf_man)
963 {
964     free(surf_man);
965 }
966
967 static int radeon_surface_sanity(struct radeon_surface_manager *surf_man,
968                                  struct radeon_surface *surf,
969                                  unsigned type,
970                                  unsigned mode)
971 {
972     if (surf_man == NULL || surf_man->surface_init == NULL || surf == NULL) {
973         return -EINVAL;
974     }
975
976     /* all dimension must be at least 1 ! */
977     if (!surf->npix_x || !surf->npix_y || !surf->npix_z) {
978         return -EINVAL;
979     }
980     if (!surf->blk_w || !surf->blk_h || !surf->blk_d) {
981         return -EINVAL;
982     }
983     if (!surf->array_size) {
984         return -EINVAL;
985     }
986     /* array size must be a power of 2 */
987     surf->array_size = next_power_of_two(surf->array_size);
988
989     switch (surf->nsamples) {
990     case 1:
991     case 2:
992     case 4:
993     case 8:
994         break;
995     default:
996         return -EINVAL;
997     }
998     /* check type */
999     switch (type) {
1000     case RADEON_SURF_TYPE_1D:
1001         if (surf->npix_y > 1) {
1002             return -EINVAL;
1003         }
1004     case RADEON_SURF_TYPE_2D:
1005         if (surf->npix_z > 1) {
1006             return -EINVAL;
1007         }
1008         break;
1009     case RADEON_SURF_TYPE_CUBEMAP:
1010         if (surf->npix_z > 1) {
1011             return -EINVAL;
1012         }
1013         /* deal with cubemap as they were texture array */
1014         if (surf_man->family >= CHIP_RV770) {
1015             surf->array_size = 8;
1016         } else {
1017             surf->array_size = 6;
1018         }
1019         break;
1020     case RADEON_SURF_TYPE_3D:
1021         break;
1022     case RADEON_SURF_TYPE_1D_ARRAY:
1023         if (surf->npix_y > 1) {
1024             return -EINVAL;
1025         }
1026     case RADEON_SURF_TYPE_2D_ARRAY:
1027         break;
1028     default:
1029         return -EINVAL;
1030     }
1031     return 0;
1032 }
1033
1034 int radeon_surface_init(struct radeon_surface_manager *surf_man,
1035                         struct radeon_surface *surf)
1036 {
1037     unsigned mode, type;
1038     int r;
1039
1040     type = RADEON_SURF_GET(surf->flags, TYPE);
1041     mode = RADEON_SURF_GET(surf->flags, MODE);
1042
1043     r = radeon_surface_sanity(surf_man, surf, type, mode);
1044     if (r) {
1045         return r;
1046     }
1047     return surf_man->surface_init(surf_man, surf);
1048 }
1049
1050 int radeon_surface_best(struct radeon_surface_manager *surf_man,
1051                         struct radeon_surface *surf)
1052 {
1053     unsigned mode, type;
1054     int r;
1055
1056     type = RADEON_SURF_GET(surf->flags, TYPE);
1057     mode = RADEON_SURF_GET(surf->flags, MODE);
1058
1059     r = radeon_surface_sanity(surf_man, surf, type, mode);
1060     if (r) {
1061         return r;
1062     }
1063     return surf_man->surface_best(surf_man, surf);
1064 }