Back to index

libdrm  2.4.37
radeon_surface.c
Go to the documentation of this file.
00001 /*
00002  * Copyright © 2011 Red Hat All Rights Reserved.
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining
00005  * a copy of this software and associated documentation files (the
00006  * "Software"), to deal in the Software without restriction, including
00007  * without limitation the rights to use, copy, modify, merge, publish,
00008  * distribute, sub license, and/or sell copies of the Software, and to
00009  * permit persons to whom the Software is furnished to do so, subject to
00010  * the following conditions:
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00013  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
00014  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00015  * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
00016  * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00017  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00018  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
00019  * USE OR OTHER DEALINGS IN THE SOFTWARE.
00020  *
00021  * The above copyright notice and this permission notice (including the
00022  * next paragraph) shall be included in all copies or substantial portions
00023  * of the Software.
00024  */
00025 /*
00026  * Authors:
00027  *      Jérôme Glisse <jglisse@redhat.com>
00028  */
00029 #include <errno.h>
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <sys/mman.h>
00034 #include <sys/ioctl.h>
00035 #include "drm.h"
00036 #include "xf86drm.h"
00037 #include "radeon_drm.h"
00038 #include "radeon_surface.h"
00039 
00040 #define ALIGN(value, alignment) (((value) + alignment - 1) & ~(alignment - 1))
00041 #define MAX2(A, B)              ((A) > (B) ? (A) : (B))
00042 #define MIN2(A, B)              ((A) < (B) ? (A) : (B))
00043 
00044 /* keep this private */
00045 enum radeon_family {
00046     CHIP_UNKNOWN,
00047     CHIP_R600,
00048     CHIP_RV610,
00049     CHIP_RV630,
00050     CHIP_RV670,
00051     CHIP_RV620,
00052     CHIP_RV635,
00053     CHIP_RS780,
00054     CHIP_RS880,
00055     CHIP_RV770,
00056     CHIP_RV730,
00057     CHIP_RV710,
00058     CHIP_RV740,
00059     CHIP_CEDAR,
00060     CHIP_REDWOOD,
00061     CHIP_JUNIPER,
00062     CHIP_CYPRESS,
00063     CHIP_HEMLOCK,
00064     CHIP_PALM,
00065     CHIP_SUMO,
00066     CHIP_SUMO2,
00067     CHIP_BARTS,
00068     CHIP_TURKS,
00069     CHIP_CAICOS,
00070     CHIP_CAYMAN,
00071     CHIP_ARUBA,
00072     CHIP_TAHITI,
00073     CHIP_PITCAIRN,
00074     CHIP_VERDE,
00075     CHIP_LAST,
00076 };
00077 
00078 typedef int (*hw_init_surface_t)(struct radeon_surface_manager *surf_man,
00079                                  struct radeon_surface *surf);
00080 typedef int (*hw_best_surface_t)(struct radeon_surface_manager *surf_man,
00081                                  struct radeon_surface *surf);
00082 
00083 struct radeon_hw_info {
00084     /* apply to r6, eg */
00085     uint32_t                    group_bytes;
00086     uint32_t                    num_banks;
00087     uint32_t                    num_pipes;
00088     /* apply to eg */
00089     uint32_t                    row_size;
00090     unsigned                    allow_2d;
00091 };
00092 
00093 struct radeon_surface_manager {
00094     int                         fd;
00095     uint32_t                    device_id;
00096     struct radeon_hw_info       hw_info;
00097     unsigned                    family;
00098     hw_init_surface_t           surface_init;
00099     hw_best_surface_t           surface_best;
00100 };
00101 
00102 /* helper */
00103 static int radeon_get_value(int fd, unsigned req, uint32_t *value)
00104 {
00105     struct drm_radeon_info info = {};
00106     int r;
00107 
00108     *value = 0;
00109     info.request = req;
00110     info.value = (uintptr_t)value;
00111     r = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info,
00112                             sizeof(struct drm_radeon_info));
00113     return r;
00114 }
00115 
00116 static int radeon_get_family(struct radeon_surface_manager *surf_man)
00117 {
00118     switch (surf_man->device_id) {
00119 #define CHIPSET(pci_id, name, fam) case pci_id: surf_man->family = CHIP_##fam; break;
00120 #include "r600_pci_ids.h"
00121 #undef CHIPSET
00122     default:
00123         return -EINVAL;
00124     }
00125     return 0;
00126 }
00127 
00128 static unsigned next_power_of_two(unsigned x)
00129 {
00130    if (x <= 1)
00131        return 1;
00132 
00133    return (1 << ((sizeof(unsigned) * 8) - __builtin_clz(x - 1)));
00134 }
00135 
00136 static unsigned mip_minify(unsigned size, unsigned level)
00137 {
00138     unsigned val;
00139 
00140     val = MAX2(1, size >> level);
00141     if (level > 0)
00142         val = next_power_of_two(val);
00143     return val;
00144 }
00145 
00146 static void surf_minify(struct radeon_surface *surf,
00147                         unsigned level,
00148                         uint32_t xalign, uint32_t yalign, uint32_t zalign,
00149                         unsigned offset)
00150 {
00151     surf->level[level].npix_x = mip_minify(surf->npix_x, level);
00152     surf->level[level].npix_y = mip_minify(surf->npix_y, level);
00153     surf->level[level].npix_z = mip_minify(surf->npix_z, level);
00154     surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w;
00155     surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h;
00156     surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d;
00157     if (surf->level[level].mode == RADEON_SURF_MODE_2D) {
00158         if (surf->level[level].nblk_x < xalign || surf->level[level].nblk_y < yalign) {
00159             surf->level[level].mode = RADEON_SURF_MODE_1D;
00160             return;
00161         }
00162     }
00163     surf->level[level].nblk_x  = ALIGN(surf->level[level].nblk_x, xalign);
00164     surf->level[level].nblk_y  = ALIGN(surf->level[level].nblk_y, yalign);
00165     surf->level[level].nblk_z  = ALIGN(surf->level[level].nblk_z, zalign);
00166 
00167     surf->level[level].offset = offset;
00168     surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe;
00169     surf->level[level].slice_size = surf->level[level].pitch_bytes * surf->level[level].nblk_y;
00170 
00171     surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size;
00172 }
00173 
00174 /* ===========================================================================
00175  * r600/r700 family
00176  */
00177 static int r6_init_hw_info(struct radeon_surface_manager *surf_man)
00178 {
00179     uint32_t tiling_config;
00180     drmVersionPtr version;
00181     int r;
00182 
00183     r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
00184                          &tiling_config);
00185     if (r) {
00186         return r;
00187     }
00188 
00189     surf_man->hw_info.allow_2d = 0;
00190     version = drmGetVersion(surf_man->fd);
00191     if (version && version->version_minor >= 14) {
00192         surf_man->hw_info.allow_2d = 1;
00193     }
00194     drmFreeVersion(version);
00195 
00196     switch ((tiling_config & 0xe) >> 1) {
00197     case 0:
00198         surf_man->hw_info.num_pipes = 1;
00199         break;
00200     case 1:
00201         surf_man->hw_info.num_pipes = 2;
00202         break;
00203     case 2:
00204         surf_man->hw_info.num_pipes = 4;
00205         break;
00206     case 3:
00207         surf_man->hw_info.num_pipes = 8;
00208         break;
00209     default:
00210         surf_man->hw_info.num_pipes = 8;
00211         surf_man->hw_info.allow_2d = 0;
00212         break;
00213     }
00214 
00215     switch ((tiling_config & 0x30) >> 4) {
00216     case 0:
00217         surf_man->hw_info.num_banks = 4;
00218         break;
00219     case 1:
00220         surf_man->hw_info.num_banks = 8;
00221         break;
00222     default:
00223         surf_man->hw_info.num_banks = 8;
00224         surf_man->hw_info.allow_2d = 0;
00225         break;
00226     }
00227 
00228     switch ((tiling_config & 0xc0) >> 6) {
00229     case 0:
00230         surf_man->hw_info.group_bytes = 256;
00231         break;
00232     case 1:
00233         surf_man->hw_info.group_bytes = 512;
00234         break;
00235     default:
00236         surf_man->hw_info.group_bytes = 256;
00237         surf_man->hw_info.allow_2d = 0;
00238         break;
00239     }
00240     return 0;
00241 }
00242 
00243 static int r6_surface_init_linear(struct radeon_surface_manager *surf_man,
00244                                   struct radeon_surface *surf,
00245                                   uint64_t offset, unsigned start_level)
00246 {
00247     uint32_t xalign, yalign, zalign;
00248     unsigned i;
00249 
00250     /* compute alignment */
00251     if (!start_level) {
00252         surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
00253     }
00254     /* the 32 alignment is for scanout, cb or db but to allow texture to be
00255      * easily bound as such we force this alignment to all surface
00256      */
00257     xalign = MAX2(1, surf_man->hw_info.group_bytes / surf->bpe);
00258     yalign = 1;
00259     zalign = 1;
00260     if (surf->flags & RADEON_SURF_SCANOUT) {
00261         xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
00262     }
00263 
00264     /* build mipmap tree */
00265     for (i = start_level; i <= surf->last_level; i++) {
00266         surf->level[i].mode = RADEON_SURF_MODE_LINEAR;
00267         surf_minify(surf, i, xalign, yalign, zalign, offset);
00268         /* level0 and first mipmap need to have alignment */
00269         offset = surf->bo_size;
00270         if ((i == 0)) {
00271             offset = ALIGN(offset, surf->bo_alignment);
00272         }
00273     }
00274     return 0;
00275 }
00276 
00277 static int r6_surface_init_linear_aligned(struct radeon_surface_manager *surf_man,
00278                                           struct radeon_surface *surf,
00279                                           uint64_t offset, unsigned start_level)
00280 {
00281     uint32_t xalign, yalign, zalign;
00282     unsigned i;
00283 
00284     /* compute alignment */
00285     if (!start_level) {
00286         surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
00287     }
00288     xalign = MAX2(64, surf_man->hw_info.group_bytes / surf->bpe);
00289     yalign = 1;
00290     zalign = 1;
00291 
00292     /* build mipmap tree */
00293     for (i = start_level; i <= surf->last_level; i++) {
00294         surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
00295         surf_minify(surf, i, xalign, yalign, zalign, offset);
00296         /* level0 and first mipmap need to have alignment */
00297         offset = surf->bo_size;
00298         if ((i == 0)) {
00299             offset = ALIGN(offset, surf->bo_alignment);
00300         }
00301     }
00302     return 0;
00303 }
00304 
00305 static int r6_surface_init_1d(struct radeon_surface_manager *surf_man,
00306                               struct radeon_surface *surf,
00307                               uint64_t offset, unsigned start_level)
00308 {
00309     uint32_t xalign, yalign, zalign, tilew;
00310     unsigned i;
00311 
00312     /* compute alignment */
00313     tilew = 8;
00314     xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples);
00315     xalign = MAX2(tilew, xalign);
00316     yalign = tilew;
00317     zalign = 1;
00318     if (surf->flags & RADEON_SURF_SCANOUT) {
00319         xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
00320     }
00321     if (!start_level) {
00322         surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
00323     }
00324 
00325     /* build mipmap tree */
00326     for (i = start_level; i <= surf->last_level; i++) {
00327         surf->level[i].mode = RADEON_SURF_MODE_1D;
00328         surf_minify(surf, i, xalign, yalign, zalign, offset);
00329         /* level0 and first mipmap need to have alignment */
00330         offset = surf->bo_size;
00331         if ((i == 0)) {
00332             offset = ALIGN(offset, surf->bo_alignment);
00333         }
00334     }
00335     return 0;
00336 }
00337 
00338 static int r6_surface_init_2d(struct radeon_surface_manager *surf_man,
00339                               struct radeon_surface *surf,
00340                               uint64_t offset, unsigned start_level)
00341 {
00342     uint32_t xalign, yalign, zalign, tilew;
00343     unsigned i;
00344 
00345     /* compute alignment */
00346     tilew = 8;
00347     zalign = 1;
00348     xalign = (surf_man->hw_info.group_bytes * surf_man->hw_info.num_banks) /
00349              (tilew * surf->bpe * surf->nsamples);
00350     xalign = MAX2(tilew * surf_man->hw_info.num_banks, xalign);
00351     yalign = tilew * surf_man->hw_info.num_pipes;
00352     if (surf->flags & RADEON_SURF_SCANOUT) {
00353         xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
00354     }
00355     if (!start_level) {
00356         surf->bo_alignment =
00357             MAX2(surf_man->hw_info.num_pipes *
00358                  surf_man->hw_info.num_banks *
00359                  surf->bpe * 64,
00360                  xalign * yalign * surf->nsamples * surf->bpe);
00361     }
00362 
00363     /* build mipmap tree */
00364     for (i = start_level; i <= surf->last_level; i++) {
00365         surf->level[i].mode = RADEON_SURF_MODE_2D;
00366         surf_minify(surf, i, xalign, yalign, zalign, offset);
00367         if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
00368             return r6_surface_init_1d(surf_man, surf, offset, i);
00369         }
00370         /* level0 and first mipmap need to have alignment */
00371         offset = surf->bo_size;
00372         if ((i == 0)) {
00373             offset = ALIGN(offset, surf->bo_alignment);
00374         }
00375     }
00376     return 0;
00377 }
00378 
00379 static int r6_surface_init(struct radeon_surface_manager *surf_man,
00380                            struct radeon_surface *surf)
00381 {
00382     unsigned mode;
00383     int r;
00384 
00385     /* tiling mode */
00386     mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
00387 
00388     /* always enable z & stencil together */
00389     if (surf->flags & RADEON_SURF_ZBUFFER) {
00390         surf->flags |= RADEON_SURF_SBUFFER;
00391     }
00392     if (surf->flags & RADEON_SURF_SBUFFER) {
00393         surf->flags |= RADEON_SURF_ZBUFFER;
00394     }
00395     if (surf->flags & RADEON_SURF_ZBUFFER) {
00396         /* zbuffer only support 1D or 2D tiled surface */
00397         switch (mode) {
00398         case RADEON_SURF_MODE_1D:
00399         case RADEON_SURF_MODE_2D:
00400             break;
00401         default:
00402             mode = RADEON_SURF_MODE_1D;
00403             surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
00404             surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
00405             break;
00406         }
00407     }
00408 
00409     /* force 1d on kernel that can't do 2d */
00410     if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
00411         mode = RADEON_SURF_MODE_1D;
00412         surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
00413         surf->flags |= RADEON_SURF_SET(mode, MODE);
00414     }
00415 
00416     /* check surface dimension */
00417     if (surf->npix_x > 8192 || surf->npix_y > 8192 || surf->npix_z > 8192) {
00418         return -EINVAL;
00419     }
00420 
00421     /* check mipmap last_level */
00422     if (surf->last_level > 14) {
00423         return -EINVAL;
00424     }
00425 
00426     /* check tiling mode */
00427     switch (mode) {
00428     case RADEON_SURF_MODE_LINEAR:
00429         r = r6_surface_init_linear(surf_man, surf, 0, 0);
00430         break;
00431     case RADEON_SURF_MODE_LINEAR_ALIGNED:
00432         r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
00433         break;
00434     case RADEON_SURF_MODE_1D:
00435         r = r6_surface_init_1d(surf_man, surf, 0, 0);
00436         break;
00437     case RADEON_SURF_MODE_2D:
00438         r = r6_surface_init_2d(surf_man, surf, 0, 0);
00439         break;
00440     default:
00441         return -EINVAL;
00442     }
00443     return r;
00444 }
00445 
00446 static int r6_surface_best(struct radeon_surface_manager *surf_man,
00447                            struct radeon_surface *surf)
00448 {
00449     /* no value to optimize for r6xx/r7xx */
00450     return 0;
00451 }
00452 
00453 
00454 /* ===========================================================================
00455  * evergreen family
00456  */
00457 static int eg_init_hw_info(struct radeon_surface_manager *surf_man)
00458 {
00459     uint32_t tiling_config;
00460     drmVersionPtr version;
00461     int r;
00462 
00463     r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG,
00464                          &tiling_config);
00465     if (r) {
00466         return r;
00467     }
00468 
00469     surf_man->hw_info.allow_2d = 0;
00470     version = drmGetVersion(surf_man->fd);
00471     if (version && version->version_minor >= 16) {
00472         surf_man->hw_info.allow_2d = 1;
00473     }
00474     drmFreeVersion(version);
00475 
00476     switch (tiling_config & 0xf) {
00477     case 0:
00478         surf_man->hw_info.num_pipes = 1;
00479         break;
00480     case 1:
00481         surf_man->hw_info.num_pipes = 2;
00482         break;
00483     case 2:
00484         surf_man->hw_info.num_pipes = 4;
00485         break;
00486     case 3:
00487         surf_man->hw_info.num_pipes = 8;
00488         break;
00489     default:
00490         surf_man->hw_info.num_pipes = 8;
00491         surf_man->hw_info.allow_2d = 0;
00492         break;
00493     }
00494 
00495     switch ((tiling_config & 0xf0) >> 4) {
00496     case 0:
00497         surf_man->hw_info.num_banks = 4;
00498         break;
00499     case 1:
00500         surf_man->hw_info.num_banks = 8;
00501         break;
00502     case 2:
00503         surf_man->hw_info.num_banks = 16;
00504         break;
00505     default:
00506         surf_man->hw_info.num_banks = 8;
00507         surf_man->hw_info.allow_2d = 0;
00508         break;
00509     }
00510 
00511     switch ((tiling_config & 0xf00) >> 8) {
00512     case 0:
00513         surf_man->hw_info.group_bytes = 256;
00514         break;
00515     case 1:
00516         surf_man->hw_info.group_bytes = 512;
00517         break;
00518     default:
00519         surf_man->hw_info.group_bytes = 256;
00520         surf_man->hw_info.allow_2d = 0;
00521         break;
00522     }
00523 
00524     switch ((tiling_config & 0xf000) >> 12) {
00525     case 0:
00526         surf_man->hw_info.row_size = 1024;
00527         break;
00528     case 1:
00529         surf_man->hw_info.row_size = 2048;
00530         break;
00531     case 2:
00532         surf_man->hw_info.row_size = 4096;
00533         break;
00534     default:
00535         surf_man->hw_info.row_size = 4096;
00536         surf_man->hw_info.allow_2d = 0;
00537         break;
00538     }
00539     return 0;
00540 }
00541 
00542 static void eg_surf_minify(struct radeon_surface *surf,
00543                            unsigned level,
00544                            unsigned slice_pt,
00545                            unsigned mtilew,
00546                            unsigned mtileh,
00547                            unsigned mtileb,
00548                            unsigned offset)
00549 {
00550     unsigned mtile_pr, mtile_ps;
00551 
00552     surf->level[level].npix_x = mip_minify(surf->npix_x, level);
00553     surf->level[level].npix_y = mip_minify(surf->npix_y, level);
00554     surf->level[level].npix_z = mip_minify(surf->npix_z, level);
00555     surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w;
00556     surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h;
00557     surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d;
00558     if (surf->level[level].mode == RADEON_SURF_MODE_2D) {
00559         if (surf->level[level].nblk_x < mtilew || surf->level[level].nblk_y < mtileh) {
00560             surf->level[level].mode = RADEON_SURF_MODE_1D;
00561             return;
00562         }
00563     }
00564     surf->level[level].nblk_x  = ALIGN(surf->level[level].nblk_x, mtilew);
00565     surf->level[level].nblk_y  = ALIGN(surf->level[level].nblk_y, mtileh);
00566     surf->level[level].nblk_z  = ALIGN(surf->level[level].nblk_z, 1);
00567 
00568     /* macro tile per row */
00569     mtile_pr = surf->level[level].nblk_x / mtilew;
00570     /* macro tile per slice */
00571     mtile_ps = (mtile_pr * surf->level[level].nblk_y) / mtileh;
00572 
00573     surf->level[level].offset = offset;
00574     surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe * slice_pt;
00575     surf->level[level].slice_size = mtile_ps * mtileb * slice_pt;
00576 
00577     surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size;
00578 }
00579 
00580 static int eg_surface_init_1d(struct radeon_surface_manager *surf_man,
00581                               struct radeon_surface *surf,
00582                               uint64_t offset, unsigned start_level)
00583 {
00584     uint32_t xalign, yalign, zalign, tilew;
00585     unsigned i;
00586 
00587     /* compute alignment */
00588     tilew = 8;
00589     xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples);
00590     if (surf->flags & RADEON_SURF_SBUFFER) {
00591         xalign = surf_man->hw_info.group_bytes / (tilew * surf->nsamples);
00592     }
00593     xalign = MAX2(tilew, xalign);
00594     yalign = tilew;
00595     zalign = 1;
00596     if (surf->flags & RADEON_SURF_SCANOUT) {
00597         xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign);
00598     }
00599     if (!start_level) {
00600         surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
00601     }
00602 
00603     /* build mipmap tree */
00604     for (i = start_level; i <= surf->last_level; i++) {
00605         surf->level[i].mode = RADEON_SURF_MODE_1D;
00606         surf_minify(surf, i, xalign, yalign, zalign, offset);
00607         /* level0 and first mipmap need to have alignment */
00608         offset = surf->bo_size;
00609         if ((i == 0)) {
00610             offset = ALIGN(offset, surf->bo_alignment);
00611         }
00612     }
00613 
00614     if (surf->flags & RADEON_SURF_SBUFFER) {
00615         surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment);
00616         surf->bo_size = surf->stencil_offset + surf->bo_size / 4;
00617     }
00618 
00619     return 0;
00620 }
00621 
00622 static int eg_surface_init_2d(struct radeon_surface_manager *surf_man,
00623                               struct radeon_surface *surf,
00624                               uint64_t offset, unsigned start_level)
00625 {
00626     unsigned tilew, tileh, tileb;
00627     unsigned mtilew, mtileh, mtileb;
00628     unsigned slice_pt;
00629     unsigned i;
00630 
00631     /* compute tile values */
00632     tilew = 8;
00633     tileh = 8;
00634     tileb = tilew * tileh * surf->bpe * surf->nsamples;
00635     /* slices per tile */
00636     slice_pt = 1;
00637     if (tileb > surf->tile_split) {
00638         slice_pt = tileb / surf->tile_split;
00639     }
00640     tileb = tileb / slice_pt;
00641 
00642     /* macro tile width & height */
00643     mtilew = (tilew * surf->bankw * surf_man->hw_info.num_pipes) * surf->mtilea;
00644     mtileh = (tileh * surf->bankh * surf_man->hw_info.num_banks) / surf->mtilea;
00645     /* macro tile bytes */
00646     mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb;
00647 
00648     if (!start_level) {
00649         surf->bo_alignment = MAX2(256, mtileb);
00650     }
00651 
00652     /* build mipmap tree */
00653     for (i = start_level; i <= surf->last_level; i++) {
00654         surf->level[i].mode = RADEON_SURF_MODE_2D;
00655         eg_surf_minify(surf, i, slice_pt, mtilew, mtileh, mtileb, offset);
00656         if (surf->level[i].mode == RADEON_SURF_MODE_1D) {
00657             return eg_surface_init_1d(surf_man, surf, offset, i);
00658         }
00659         /* level0 and first mipmap need to have alignment */
00660         offset = surf->bo_size;
00661         if ((i == 0)) {
00662             offset = ALIGN(offset, surf->bo_alignment);
00663         }
00664     }
00665 
00666     if (surf->flags & RADEON_SURF_SBUFFER) {
00667         surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment);
00668         surf->bo_size = surf->stencil_offset + surf->bo_size / 4;
00669     }
00670 
00671     return 0;
00672 }
00673 
00674 static int eg_surface_sanity(struct radeon_surface_manager *surf_man,
00675                              struct radeon_surface *surf,
00676                              unsigned mode)
00677 {
00678     unsigned tileb;
00679 
00680     /* check surface dimension */
00681     if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) {
00682         return -EINVAL;
00683     }
00684 
00685     /* check mipmap last_level */
00686     if (surf->last_level > 15) {
00687         return -EINVAL;
00688     }
00689 
00690     /* force 1d on kernel that can't do 2d */
00691     if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) {
00692         mode = RADEON_SURF_MODE_1D;
00693         surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
00694         surf->flags |= RADEON_SURF_SET(mode, MODE);
00695     }
00696 
00697     /* check tile split */
00698     if (mode == RADEON_SURF_MODE_2D) {
00699         switch (surf->tile_split) {
00700         case 64:
00701         case 128:
00702         case 256:
00703         case 512:
00704         case 1024:
00705         case 2048:
00706         case 4096:
00707             break;
00708         default:
00709             return -EINVAL;
00710         }
00711         switch (surf->mtilea) {
00712         case 1:
00713         case 2:
00714         case 4:
00715         case 8:
00716             break;
00717         default:
00718             return -EINVAL;
00719         }
00720         /* check aspect ratio */
00721         if (surf_man->hw_info.num_banks < surf->mtilea) {
00722             return -EINVAL;
00723         }
00724         /* check bank width */
00725         switch (surf->bankw) {
00726         case 1:
00727         case 2:
00728         case 4:
00729         case 8:
00730             break;
00731         default:
00732             return -EINVAL;
00733         }
00734         /* check bank height */
00735         switch (surf->bankh) {
00736         case 1:
00737         case 2:
00738         case 4:
00739         case 8:
00740             break;
00741         default:
00742             return -EINVAL;
00743         }
00744         tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
00745         if ((tileb * surf->bankh * surf->bankw) < surf_man->hw_info.group_bytes) {
00746             return -EINVAL;
00747         }
00748     }
00749 
00750     return 0;
00751 }
00752 
00753 static int eg_surface_init(struct radeon_surface_manager *surf_man,
00754                            struct radeon_surface *surf)
00755 {
00756     unsigned mode;
00757     int r;
00758 
00759     /* tiling mode */
00760     mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
00761 
00762     /* for some reason eg need to have room for stencil right after depth */
00763     if (surf->flags & RADEON_SURF_ZBUFFER) {
00764         surf->flags |= RADEON_SURF_SBUFFER;
00765     }
00766     if (surf->flags & RADEON_SURF_SBUFFER) {
00767         surf->flags |= RADEON_SURF_ZBUFFER;
00768     }
00769     if (surf->flags & RADEON_SURF_ZBUFFER) {
00770         /* zbuffer only support 1D or 2D tiled surface */
00771         switch (mode) {
00772         case RADEON_SURF_MODE_1D:
00773         case RADEON_SURF_MODE_2D:
00774             break;
00775         default:
00776             mode = RADEON_SURF_MODE_1D;
00777             surf->flags = RADEON_SURF_CLR(surf->flags, MODE);
00778             surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
00779             break;
00780         }
00781     }
00782 
00783     r = eg_surface_sanity(surf_man, surf, mode);
00784     if (r) {
00785         return r;
00786     }
00787 
00788     surf->stencil_offset = 0;
00789     surf->stencil_tile_split = 0;
00790 
00791     /* check tiling mode */
00792     switch (mode) {
00793     case RADEON_SURF_MODE_LINEAR:
00794         r = r6_surface_init_linear(surf_man, surf, 0, 0);
00795         break;
00796     case RADEON_SURF_MODE_LINEAR_ALIGNED:
00797         r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0);
00798         break;
00799     case RADEON_SURF_MODE_1D:
00800         r = eg_surface_init_1d(surf_man, surf, 0, 0);
00801         break;
00802     case RADEON_SURF_MODE_2D:
00803         r = eg_surface_init_2d(surf_man, surf, 0, 0);
00804         break;
00805     default:
00806         return -EINVAL;
00807     }
00808     return r;
00809 }
00810 
00811 static unsigned log2_int(unsigned x)
00812 {
00813     unsigned l;
00814 
00815     if (x < 2) {
00816         return 0;
00817     }
00818     for (l = 2; ; l++) {
00819         if ((unsigned)(1 << l) > x) {
00820             return l - 1;
00821         }
00822     }
00823     return 0;
00824 }
00825 
00826 /* compute best tile_split, bankw, bankh, mtilea
00827  * depending on surface
00828  */
00829 static int eg_surface_best(struct radeon_surface_manager *surf_man,
00830                            struct radeon_surface *surf)
00831 {
00832     unsigned mode, tileb, h_over_w;
00833     int r;
00834 
00835     /* tiling mode */
00836     mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK;
00837 
00838     /* for some reason eg need to have room for stencil right after depth */
00839     if (surf->flags & RADEON_SURF_ZBUFFER) {
00840         surf->flags |= RADEON_SURF_SBUFFER;
00841     }
00842 
00843     /* set some default value to avoid sanity check choking on them */
00844     surf->tile_split = 1024;
00845     surf->bankw = 1;
00846     surf->bankh = 1;
00847     surf->mtilea = surf_man->hw_info.num_banks;
00848     tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
00849     for (; surf->bankh <= 8; surf->bankh *= 2) {
00850         if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) {
00851             break;
00852         }
00853     }
00854     if (surf->mtilea > 8) {
00855         surf->mtilea = 8;
00856     }
00857 
00858     r = eg_surface_sanity(surf_man, surf, mode);
00859     if (r) {
00860         return r;
00861     }
00862 
00863     if (mode != RADEON_SURF_MODE_2D) {
00864         /* nothing to do for non 2D tiled surface */
00865         return 0;
00866     }
00867 
00868     /* set tile split to row size, optimize latter for multi-sample surface
00869      * tile split >= 256 for render buffer surface. Also depth surface want
00870      * smaller value for optimal performances.
00871      */
00872     surf->tile_split = surf_man->hw_info.row_size;
00873     surf->stencil_tile_split = surf_man->hw_info.row_size / 2;
00874 
00875     /* bankw or bankh greater than 1 increase alignment requirement, not
00876      * sure if it's worth using smaller bankw & bankh to stick with 2D
00877      * tiling on small surface rather than falling back to 1D tiling.
00878      * Use recommanded value based on tile size for now.
00879      *
00880      * fmask buffer has different optimal value figure them out once we
00881      * use it.
00882      */
00883     if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
00884         /* assume 1 bytes for stencil, we optimize for stencil as stencil
00885          * and depth shares surface values
00886          */
00887         tileb = MIN2(surf->tile_split, 64 * surf->nsamples);
00888     } else {
00889         tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples);
00890     }
00891 
00892     /* use bankw of 1 to minimize width alignment, might be interesting to
00893      * increase it for large surface
00894      */
00895     surf->bankw = 1;
00896     switch (tileb) {
00897     case 64:
00898         surf->bankh = 4;
00899         break;
00900     case 128:
00901     case 256:
00902         surf->bankh = 2;
00903         break;
00904     default:
00905         surf->bankh = 1;
00906         break;
00907     }
00908     /* double check the constraint */
00909     for (; surf->bankh <= 8; surf->bankh *= 2) {
00910         if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) {
00911             break;
00912         }
00913     }
00914 
00915     h_over_w = (((surf->bankh * surf_man->hw_info.num_banks) << 16) /
00916                 (surf->bankw * surf_man->hw_info.num_pipes)) >> 16;
00917     surf->mtilea = 1 << (log2_int(h_over_w) >> 1);
00918 
00919     return 0;
00920 }
00921 
00922 
00923 /* ===========================================================================
00924  * public API
00925  */
00926 struct radeon_surface_manager *radeon_surface_manager_new(int fd)
00927 {
00928     struct radeon_surface_manager *surf_man;
00929 
00930     surf_man = calloc(1, sizeof(struct radeon_surface_manager));
00931     if (surf_man == NULL) {
00932         return NULL;
00933     }
00934     surf_man->fd = fd;
00935     if (radeon_get_value(fd, RADEON_INFO_DEVICE_ID, &surf_man->device_id)) {
00936         goto out_err;
00937     }
00938     if (radeon_get_family(surf_man)) {
00939         goto out_err;
00940     }
00941 
00942     if (surf_man->family <= CHIP_RV740) {
00943         if (r6_init_hw_info(surf_man)) {
00944             goto out_err;
00945         }
00946         surf_man->surface_init = &r6_surface_init;
00947         surf_man->surface_best = &r6_surface_best;
00948     } else {
00949         if (eg_init_hw_info(surf_man)) {
00950             goto out_err;
00951         }
00952         surf_man->surface_init = &eg_surface_init;
00953         surf_man->surface_best = &eg_surface_best;
00954     }
00955 
00956     return surf_man;
00957 out_err:
00958     free(surf_man);
00959     return NULL;
00960 }
00961 
00962 void radeon_surface_manager_free(struct radeon_surface_manager *surf_man)
00963 {
00964     free(surf_man);
00965 }
00966 
00967 static int radeon_surface_sanity(struct radeon_surface_manager *surf_man,
00968                                  struct radeon_surface *surf,
00969                                  unsigned type,
00970                                  unsigned mode)
00971 {
00972     if (surf_man == NULL || surf_man->surface_init == NULL || surf == NULL) {
00973         return -EINVAL;
00974     }
00975 
00976     /* all dimension must be at least 1 ! */
00977     if (!surf->npix_x || !surf->npix_y || !surf->npix_z) {
00978         return -EINVAL;
00979     }
00980     if (!surf->blk_w || !surf->blk_h || !surf->blk_d) {
00981         return -EINVAL;
00982     }
00983     if (!surf->array_size) {
00984         return -EINVAL;
00985     }
00986     /* array size must be a power of 2 */
00987     surf->array_size = next_power_of_two(surf->array_size);
00988 
00989     switch (surf->nsamples) {
00990     case 1:
00991     case 2:
00992     case 4:
00993     case 8:
00994         break;
00995     default:
00996         return -EINVAL;
00997     }
00998     /* check type */
00999     switch (type) {
01000     case RADEON_SURF_TYPE_1D:
01001         if (surf->npix_y > 1) {
01002             return -EINVAL;
01003         }
01004     case RADEON_SURF_TYPE_2D:
01005         if (surf->npix_z > 1) {
01006             return -EINVAL;
01007         }
01008         break;
01009     case RADEON_SURF_TYPE_CUBEMAP:
01010         if (surf->npix_z > 1) {
01011             return -EINVAL;
01012         }
01013         /* deal with cubemap as they were texture array */
01014         if (surf_man->family >= CHIP_RV770) {
01015             surf->array_size = 8;
01016         } else {
01017             surf->array_size = 6;
01018         }
01019         break;
01020     case RADEON_SURF_TYPE_3D:
01021         break;
01022     case RADEON_SURF_TYPE_1D_ARRAY:
01023         if (surf->npix_y > 1) {
01024             return -EINVAL;
01025         }
01026     case RADEON_SURF_TYPE_2D_ARRAY:
01027         break;
01028     default:
01029         return -EINVAL;
01030     }
01031     return 0;
01032 }
01033 
01034 int radeon_surface_init(struct radeon_surface_manager *surf_man,
01035                         struct radeon_surface *surf)
01036 {
01037     unsigned mode, type;
01038     int r;
01039 
01040     type = RADEON_SURF_GET(surf->flags, TYPE);
01041     mode = RADEON_SURF_GET(surf->flags, MODE);
01042 
01043     r = radeon_surface_sanity(surf_man, surf, type, mode);
01044     if (r) {
01045         return r;
01046     }
01047     return surf_man->surface_init(surf_man, surf);
01048 }
01049 
01050 int radeon_surface_best(struct radeon_surface_manager *surf_man,
01051                         struct radeon_surface *surf)
01052 {
01053     unsigned mode, type;
01054     int r;
01055 
01056     type = RADEON_SURF_GET(surf->flags, TYPE);
01057     mode = RADEON_SURF_GET(surf->flags, MODE);
01058 
01059     r = radeon_surface_sanity(surf_man, surf, type, mode);
01060     if (r) {
01061         return r;
01062     }
01063     return surf_man->surface_best(surf_man, surf);
01064 }