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