874a0927388e5abf05069cde58af093afb8a63d8
[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     }
194     drmFreeVersion(version);
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     }
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     }
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;
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)
247     uint32_t xalign, yalign, zalign;
248     unsigned i;
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     }
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;
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)
281     uint32_t xalign, yalign, zalign;
282     unsigned i;
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;
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;
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)
309     uint32_t xalign, yalign, zalign, tilew;
310     unsigned i;
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     }
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;
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)
342     uint32_t xalign, yalign, zalign, tilew;
343     unsigned i;
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     }
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;
379 static int r6_surface_init(struct radeon_surface_manager *surf_man,
380                            struct radeon_surface *surf)
382     unsigned mode;
383     int r;
385     /* tiling mode */
386     mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
388     if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
389         /* zbuffer only support 1D or 2D tiled surface */
390         switch (mode) {
391         case RADEON_SURF_MODE_1D:
392         case RADEON_SURF_MODE_2D:
393             break;
394         default:
395             mode = RADEON_SURF_MODE_1D;
396             surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
397             surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
398             break;
399         }
400     }
402     /* force 1d on kernel that can't do 2d */
403     if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
404         mode = RADEON_SURF_MODE_1D;
405         surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
406         surf->flags |= RADEON_SURF_SET(mode, MODE);
407     }
409     /* check surface dimension */
410     if (surf->npix_x > 8192 || surf->npix_y > 8192 || surf->npix_z > 8192) {
411         return -EINVAL;
412     }
414     /* check mipmap last_level */
415     if (surf->last_level > 14) {
416         return -EINVAL;
417     }
419     /* check tiling mode */
420     switch (mode) {
421     case RADEON_SURF_MODE_LINEAR:
422         r = r6_surface_init_linear(surf_man, surf, 0, 0);
423         break;
424     case RADEON_SURF_MODE_LINEAR_ALIGNED:
425         r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
426         break;
427     case RADEON_SURF_MODE_1D:
428         r = r6_surface_init_1d(surf_man, surf, 0, 0);
429         break;
430     case RADEON_SURF_MODE_2D:
431         r = r6_surface_init_2d(surf_man, surf, 0, 0);
432         break;
433     default:
434         return -EINVAL;
435     }
436     return r;
439 static int r6_surface_best(struct radeon_surface_manager *surf_man,
440                            struct radeon_surface *surf)
442     /* no value to optimize for r6xx/r7xx */
443     return 0;
447 /* ===========================================================================
448  * evergreen family
449  */
450 static int eg_init_hw_info(struct radeon_surface_manager *surf_man)
452     uint32_t tiling_config;
453     drmVersionPtr version;
454     int r;
456     r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
457                          &tiling_config);
458     if (r) {
459         return r;
460     }
462     surf_man->hw_info.allow_2d = 0;
463     version = drmGetVersion(surf_man->fd);
464     if (version && version->version_minor >= 16) {
465         surf_man->hw_info.allow_2d = 1;
466     }
467     drmFreeVersion(version);
469     switch (tiling_config & 0xf) {
470     case 0:
471         surf_man->hw_info.num_pipes = 1;
472         break;
473     case 1:
474         surf_man->hw_info.num_pipes = 2;
475         break;
476     case 2:
477         surf_man->hw_info.num_pipes = 4;
478         break;
479     case 3:
480         surf_man->hw_info.num_pipes = 8;
481         break;
482     default:
483         surf_man->hw_info.num_pipes = 8;
484         surf_man->hw_info.allow_2d = 0;
485         break;
486     }
488     switch ((tiling_config & 0xf0) >> 4) {
489     case 0:
490         surf_man->hw_info.num_banks = 4;
491         break;
492     case 1:
493         surf_man->hw_info.num_banks = 8;
494         break;
495     case 2:
496         surf_man->hw_info.num_banks = 16;
497         break;
498     default:
499         surf_man->hw_info.num_banks = 8;
500         surf_man->hw_info.allow_2d = 0;
501         break;
502     }
504     switch ((tiling_config & 0xf00) >> 8) {
505     case 0:
506         surf_man->hw_info.group_bytes = 256;
507         break;
508     case 1:
509         surf_man->hw_info.group_bytes = 512;
510         break;
511     default:
512         surf_man->hw_info.group_bytes = 256;
513         surf_man->hw_info.allow_2d = 0;
514         break;
515     }
517     switch ((tiling_config & 0xf000) >> 12) {
518     case 0:
519         surf_man->hw_info.row_size = 1024;
520         break;
521     case 1:
522         surf_man->hw_info.row_size = 2048;
523         break;
524     case 2:
525         surf_man->hw_info.row_size = 4096;
526         break;
527     default:
528         surf_man->hw_info.row_size = 4096;
529         surf_man->hw_info.allow_2d = 0;
530         break;
531     }
532     return 0;
535 static void eg_surf_minify(struct radeon_surface *surf,
536                            unsigned level,
537                            unsigned slice_pt,
538                            unsigned mtilew,
539                            unsigned mtileh,
540                            unsigned mtileb,
541                            unsigned offset)
543     unsigned mtile_pr, mtile_ps;
545     surf->level[level].npix_x = mip_minify(surf->npix_x, level);
546     surf->level[level].npix_y = mip_minify(surf->npix_y, level);
547     surf->level[level].npix_z = mip_minify(surf->npix_z, level);
548     surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w;
549     surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h;
550     surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d;
551     if (surf->level[level].mode == RADEON_SURF_MODE_2D) {
552         if (surf->level[level].nblk_x < mtilew || surf->level[level].nblk_y < mtileh) {
553             surf->level[level].mode = RADEON_SURF_MODE_1D;
554             return;
555         }
556     }
557     surf->level[level].nblk_x  = ALIGN(surf->level[level].nblk_x, mtilew);
558     surf->level[level].nblk_y  = ALIGN(surf->level[level].nblk_y, mtileh);
559     surf->level[level].nblk_z  = ALIGN(surf->level[level].nblk_z, 1);
561     /* macro tile per row */
562     mtile_pr = surf->level[level].nblk_x / mtilew;
563     /* macro tile per slice */
564     mtile_ps = (mtile_pr * surf->level[level].nblk_y) / mtileh;
566     surf->level[level].offset = offset;
567     surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe * slice_pt;
568     surf->level[level].slice_size = mtile_ps * mtileb * slice_pt;
570     surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size;
573 static int eg_surface_init_1d(struct radeon_surface_manager *surf_man,
574                               struct radeon_surface *surf,
575                               uint64_t offset, unsigned start_level)
577     uint32_t xalign, yalign, zalign, tilew;
578     unsigned i;
580     /* compute alignment */
581     tilew = 8;
582     xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples);
583     if (surf->flags & RADEON_SURF_SBUFFER) {
584         xalign = surf_man->hw_info.group_bytes / (tilew * surf->nsamples);
585     }
586     xalign = MAX2(tilew, xalign);
587     yalign = tilew;
588     zalign = 1;
589     if (surf->flags & RADEON_SURF_SCANOUT) {
590         xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
591     }
592     if (!start_level) {
593         surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
594     }
596     /* build mipmap tree */
597     for (i = start_level; i <= surf->last_level; i++) {
598         surf->level[i].mode = RADEON_SURF_MODE_1D;
599         surf_minify(surf, i, xalign, yalign, zalign, offset);
600         /* level0 and first mipmap need to have alignment */
601         offset = surf->bo_size;
602         if ((i == 0)) {
603             offset = ALIGN(offset, surf->bo_alignment);
604         }
605     }
607     /* The depth and stencil buffers are in separate resources on evergreen.
608      * We allocate them in one buffer next to each other to simplify
609      * communication between the DDX and the Mesa driver. */
610     if ((surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) ==
611         (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
612         surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment);
613         surf->bo_size = surf->stencil_offset + surf->bo_size / 4;
614     }
616     return 0;
619 static int eg_surface_init_2d(struct radeon_surface_manager *surf_man,
620                               struct radeon_surface *surf,
621                               uint64_t offset, unsigned start_level)
623     unsigned tilew, tileh, tileb;
624     unsigned mtilew, mtileh, mtileb;
625     unsigned slice_pt;
626     unsigned i;
628     /* compute tile values */
629     tilew = 8;
630     tileh = 8;
631     tileb = tilew * tileh * surf->bpe * surf->nsamples;
632     /* slices per tile */
633     slice_pt = 1;
634     if (tileb > surf->tile_split) {
635         slice_pt = tileb / surf->tile_split;
636     }
637     tileb = tileb / slice_pt;
639     /* macro tile width & height */
640     mtilew = (tilew * surf->bankw * surf_man->hw_info.num_pipes) * surf->mtilea;
641     mtileh = (tileh * surf->bankh * surf_man->hw_info.num_banks) / surf->mtilea;
642     /* macro tile bytes */
643     mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb;
645     if (!start_level) {
646         surf->bo_alignment = MAX2(256, mtileb);
647     }
649     /* build mipmap tree */
650     for (i = start_level; i <= surf->last_level; i++) {
651         surf->level[i].mode = RADEON_SURF_MODE_2D;
652         eg_surf_minify(surf, i, slice_pt, mtilew, mtileh, mtileb, offset);
653         if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
654             return eg_surface_init_1d(surf_man, surf, offset, i);
655         }
656         /* level0 and first mipmap need to have alignment */
657         offset = surf->bo_size;
658         if ((i == 0)) {
659             offset = ALIGN(offset, surf->bo_alignment);
660         }
661     }
663     if ((surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) ==
664         (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
665         surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment);
666         surf->bo_size = surf->stencil_offset + surf->bo_size / 4;
667     }
669     return 0;
672 static int eg_surface_sanity(struct radeon_surface_manager *surf_man,
673                              struct radeon_surface *surf,
674                              unsigned mode)
676     unsigned tileb;
678     /* check surface dimension */
679     if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) {
680         return -EINVAL;
681     }
683     /* check mipmap last_level */
684     if (surf->last_level > 15) {
685         return -EINVAL;
686     }
688     /* force 1d on kernel that can't do 2d */
689     if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
690         mode = RADEON_SURF_MODE_1D;
691         surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
692         surf->flags |= RADEON_SURF_SET(mode, MODE);
693     }
695     /* check tile split */
696     if (mode == RADEON_SURF_MODE_2D) {
697         switch (surf->tile_split) {
698         case 64:
699         case 128:
700         case 256:
701         case 512:
702         case 1024:
703         case 2048:
704         case 4096:
705             break;
706         default:
707             return -EINVAL;
708         }
709         switch (surf->mtilea) {
710         case 1:
711         case 2:
712         case 4:
713         case 8:
714             break;
715         default:
716             return -EINVAL;
717         }
718         /* check aspect ratio */
719         if (surf_man->hw_info.num_banks < surf->mtilea) {
720             return -EINVAL;
721         }
722         /* check bank width */
723         switch (surf->bankw) {
724         case 1:
725         case 2:
726         case 4:
727         case 8:
728             break;
729         default:
730             return -EINVAL;
731         }
732         /* check bank height */
733         switch (surf->bankh) {
734         case 1:
735         case 2:
736         case 4:
737         case 8:
738             break;
739         default:
740             return -EINVAL;
741         }
742         tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
743         if ((tileb * surf->bankh * surf->bankw) < surf_man->hw_info.group_bytes) {
744             return -EINVAL;
745         }
746     }
748     return 0;
751 static int eg_surface_init(struct radeon_surface_manager *surf_man,
752                            struct radeon_surface *surf)
754     unsigned mode;
755     int r;
757     /* tiling mode */
758     mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
760     if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
761         /* zbuffer only support 1D or 2D tiled surface */
762         switch (mode) {
763         case RADEON_SURF_MODE_1D:
764         case RADEON_SURF_MODE_2D:
765             break;
766         default:
767             mode = RADEON_SURF_MODE_1D;
768             surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
769             surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
770             break;
771         }
772     }
774     r = eg_surface_sanity(surf_man, surf, mode);
775     if (r) {
776         return r;
777     }
779     surf->stencil_offset = 0;
780     surf->stencil_tile_split = 0;
782     /* check tiling mode */
783     switch (mode) {
784     case RADEON_SURF_MODE_LINEAR:
785         r = r6_surface_init_linear(surf_man, surf, 0, 0);
786         break;
787     case RADEON_SURF_MODE_LINEAR_ALIGNED:
788         r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
789         break;
790     case RADEON_SURF_MODE_1D:
791         r = eg_surface_init_1d(surf_man, surf, 0, 0);
792         break;
793     case RADEON_SURF_MODE_2D:
794         r = eg_surface_init_2d(surf_man, surf, 0, 0);
795         break;
796     default:
797         return -EINVAL;
798     }
799     return r;
802 static unsigned log2_int(unsigned x)
804     unsigned l;
806     if (x < 2) {
807         return 0;
808     }
809     for (l = 2; ; l++) {
810         if ((unsigned)(1 << l) > x) {
811             return l - 1;
812         }
813     }
814     return 0;
817 /* compute best tile_split, bankw, bankh, mtilea
818  * depending on surface
819  */
820 static int eg_surface_best(struct radeon_surface_manager *surf_man,
821                            struct radeon_surface *surf)
823     unsigned mode, tileb, h_over_w;
824     int r;
826     /* tiling mode */
827     mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
829     /* set some default value to avoid sanity check choking on them */
830     surf->tile_split = 1024;
831     surf->bankw = 1;
832     surf->bankh = 1;
833     surf->mtilea = surf_man->hw_info.num_banks;
834     tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
835     for (; surf->bankh <= 8; surf->bankh *= 2) {
836         if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) {
837             break;
838         }
839     }
840     if (surf->mtilea > 8) {
841         surf->mtilea = 8;
842     }
844     r = eg_surface_sanity(surf_man, surf, mode);
845     if (r) {
846         return r;
847     }
849     if (mode != RADEON_SURF_MODE_2D) {
850         /* nothing to do for non 2D tiled surface */
851         return 0;
852     }
854     /* set tile split to row size, optimize latter for multi-sample surface
855      * tile split >= 256 for render buffer surface. Also depth surface want
856      * smaller value for optimal performances.
857      */
858     surf->tile_split = surf_man->hw_info.row_size;
859     surf->stencil_tile_split = surf_man->hw_info.row_size / 2;
861     /* bankw or bankh greater than 1 increase alignment requirement, not
862      * sure if it's worth using smaller bankw & bankh to stick with 2D
863      * tiling on small surface rather than falling back to 1D tiling.
864      * Use recommanded value based on tile size for now.
865      *
866      * fmask buffer has different optimal value figure them out once we
867      * use it.
868      */
869     if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
870         /* assume 1 bytes for stencil, we optimize for stencil as stencil
871          * and depth shares surface values
872          */
873         tileb = MIN2(surf->tile_split, 64 * surf->nsamples);
874     } else {
875         tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
876     }
878     /* use bankw of 1 to minimize width alignment, might be interesting to
879      * increase it for large surface
880      */
881     surf->bankw = 1;
882     switch (tileb) {
883     case 64:
884         surf->bankh = 4;
885         break;
886     case 128:
887     case 256:
888         surf->bankh = 2;
889         break;
890     default:
891         surf->bankh = 1;
892         break;
893     }
894     /* double check the constraint */
895     for (; surf->bankh <= 8; surf->bankh *= 2) {
896         if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) {
897             break;
898         }
899     }
901     h_over_w = (((surf->bankh * surf_man->hw_info.num_banks) << 16) /
902                 (surf->bankw * surf_man->hw_info.num_pipes)) >> 16;
903     surf->mtilea = 1 << (log2_int(h_over_w) >> 1);
905     return 0;
909 /* ===========================================================================
910  * public API
911  */
912 struct radeon_surface_manager *radeon_surface_manager_new(int fd)
914     struct radeon_surface_manager *surf_man;
916     surf_man = calloc(1, sizeof(struct radeon_surface_manager));
917     if (surf_man == NULL) {
918         return NULL;
919     }
920     surf_man->fd = fd;
921     if (radeon_get_value(fd, RADEON_INFO_DEVICE_ID, &surf_man->device_id)) {
922         goto out_err;
923     }
924     if (radeon_get_family(surf_man)) {
925         goto out_err;
926     }
928     if (surf_man->family <= CHIP_RV740) {
929         if (r6_init_hw_info(surf_man)) {
930             goto out_err;
931         }
932         surf_man->surface_init = &r6_surface_init;
933         surf_man->surface_best = &r6_surface_best;
934     } else {
935         if (eg_init_hw_info(surf_man)) {
936             goto out_err;
937         }
938         surf_man->surface_init = &eg_surface_init;
939         surf_man->surface_best = &eg_surface_best;
940     }
942     return surf_man;
943 out_err:
944     free(surf_man);
945     return NULL;
948 void radeon_surface_manager_free(struct radeon_surface_manager *surf_man)
950     free(surf_man);
953 static int radeon_surface_sanity(struct radeon_surface_manager *surf_man,
954                                  struct radeon_surface *surf,
955                                  unsigned type,
956                                  unsigned mode)
958     if (surf_man == NULL || surf_man->surface_init == NULL || surf == NULL) {
959         return -EINVAL;
960     }
962     /* all dimension must be at least 1 ! */
963     if (!surf->npix_x || !surf->npix_y || !surf->npix_z) {
964         return -EINVAL;
965     }
966     if (!surf->blk_w || !surf->blk_h || !surf->blk_d) {
967         return -EINVAL;
968     }
969     if (!surf->array_size) {
970         return -EINVAL;
971     }
972     /* array size must be a power of 2 */
973     surf->array_size = next_power_of_two(surf->array_size);
975     switch (surf->nsamples) {
976     case 1:
977     case 2:
978     case 4:
979     case 8:
980         break;
981     default:
982         return -EINVAL;
983     }
984     /* check type */
985     switch (type) {
986     case RADEON_SURF_TYPE_1D:
987         if (surf->npix_y > 1) {
988             return -EINVAL;
989         }
990     case RADEON_SURF_TYPE_2D:
991         if (surf->npix_z > 1) {
992             return -EINVAL;
993         }
994         break;
995     case RADEON_SURF_TYPE_CUBEMAP:
996         if (surf->npix_z > 1) {
997             return -EINVAL;
998         }
999         /* deal with cubemap as they were texture array */
1000         if (surf_man->family >= CHIP_RV770) {
1001             surf->array_size = 8;
1002         } else {
1003             surf->array_size = 6;
1004         }
1005         break;
1006     case RADEON_SURF_TYPE_3D:
1007         break;
1008     case RADEON_SURF_TYPE_1D_ARRAY:
1009         if (surf->npix_y > 1) {
1010             return -EINVAL;
1011         }
1012     case RADEON_SURF_TYPE_2D_ARRAY:
1013         break;
1014     default:
1015         return -EINVAL;
1016     }
1017     return 0;
1020 int radeon_surface_init(struct radeon_surface_manager *surf_man,
1021                         struct radeon_surface *surf)
1023     unsigned mode, type;
1024     int r;
1026     type = RADEON_SURF_GET(surf->flags, TYPE);
1027     mode = RADEON_SURF_GET(surf->flags, MODE);
1029     r = radeon_surface_sanity(surf_man, surf, type, mode);
1030     if (r) {
1031         return r;
1032     }
1033     return surf_man->surface_init(surf_man, surf);
1036 int radeon_surface_best(struct radeon_surface_manager *surf_man,
1037                         struct radeon_surface *surf)
1039     unsigned mode, type;
1040     int r;
1042     type = RADEON_SURF_GET(surf->flags, TYPE);
1043     mode = RADEON_SURF_GET(surf->flags, MODE);
1045     r = radeon_surface_sanity(surf_man, surf, type, mode);
1046     if (r) {
1047         return r;
1048     }
1049     return surf_man->surface_best(surf_man, surf);