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