diff options
Diffstat (limited to 'radeon')
-rw-r--r-- | radeon/Makefile.am | 2 | ||||
-rw-r--r-- | radeon/r600_pci_ids.h | 271 | ||||
-rw-r--r-- | radeon/radeon_surface.c | 995 | ||||
-rw-r--r-- | radeon/radeon_surface.h | 114 |
4 files changed, 1382 insertions, 0 deletions
diff --git a/radeon/Makefile.am b/radeon/Makefile.am index dc94b5f3..e64aff4b 100644 --- a/radeon/Makefile.am +++ b/radeon/Makefile.am @@ -40,6 +40,7 @@ libdrm_radeon_la_SOURCES = \ radeon_cs_space.c \ radeon_bo.c \ radeon_cs.c \ + radeon_surface.c \ bof.c \ bof.h @@ -47,6 +48,7 @@ libdrm_radeonincludedir = ${includedir}/libdrm libdrm_radeoninclude_HEADERS = \ radeon_bo.h \ radeon_cs.h \ + radeon_surface.h \ radeon_bo_gem.h \ radeon_cs_gem.h \ radeon_bo_int.h \ diff --git a/radeon/r600_pci_ids.h b/radeon/r600_pci_ids.h new file mode 100644 index 00000000..0ffb741d --- /dev/null +++ b/radeon/r600_pci_ids.h @@ -0,0 +1,271 @@ +CHIPSET(0x9400, R600_9400, R600) +CHIPSET(0x9401, R600_9401, R600) +CHIPSET(0x9402, R600_9402, R600) +CHIPSET(0x9403, R600_9403, R600) +CHIPSET(0x9405, R600_9405, R600) +CHIPSET(0x940A, R600_940A, R600) +CHIPSET(0x940B, R600_940B, R600) +CHIPSET(0x940F, R600_940F, R600) + +CHIPSET(0x94C0, RV610_94C0, RV610) +CHIPSET(0x94C1, RV610_94C1, RV610) +CHIPSET(0x94C3, RV610_94C3, RV610) +CHIPSET(0x94C4, RV610_94C4, RV610) +CHIPSET(0x94C5, RV610_94C5, RV610) +CHIPSET(0x94C6, RV610_94C6, RV610) +CHIPSET(0x94C7, RV610_94C7, RV610) +CHIPSET(0x94C8, RV610_94C8, RV610) +CHIPSET(0x94C9, RV610_94C9, RV610) +CHIPSET(0x94CB, RV610_94CB, RV610) +CHIPSET(0x94CC, RV610_94CC, RV610) +CHIPSET(0x94CD, RV610_94CD, RV610) + +CHIPSET(0x9580, RV630_9580, RV630) +CHIPSET(0x9581, RV630_9581, RV630) +CHIPSET(0x9583, RV630_9583, RV630) +CHIPSET(0x9586, RV630_9586, RV630) +CHIPSET(0x9587, RV630_9587, RV630) +CHIPSET(0x9588, RV630_9588, RV630) +CHIPSET(0x9589, RV630_9589, RV630) +CHIPSET(0x958A, RV630_958A, RV630) +CHIPSET(0x958B, RV630_958B, RV630) +CHIPSET(0x958C, RV630_958C, RV630) +CHIPSET(0x958D, RV630_958D, RV630) +CHIPSET(0x958E, RV630_958E, RV630) +CHIPSET(0x958F, RV630_958F, RV630) + +CHIPSET(0x9500, RV670_9500, RV670) +CHIPSET(0x9501, RV670_9501, RV670) +CHIPSET(0x9504, RV670_9504, RV670) +CHIPSET(0x9505, RV670_9505, RV670) +CHIPSET(0x9506, RV670_9506, RV670) +CHIPSET(0x9507, RV670_9507, RV670) +CHIPSET(0x9508, RV670_9508, RV670) +CHIPSET(0x9509, RV670_9509, RV670) +CHIPSET(0x950F, RV670_950F, RV670) +CHIPSET(0x9511, RV670_9511, RV670) +CHIPSET(0x9515, RV670_9515, RV670) +CHIPSET(0x9517, RV670_9517, RV670) +CHIPSET(0x9519, RV670_9519, RV670) + +CHIPSET(0x95C0, RV620_95C0, RV620) +CHIPSET(0x95C2, RV620_95C2, RV620) +CHIPSET(0x95C4, RV620_95C4, RV620) +CHIPSET(0x95C5, RV620_95C5, RV620) +CHIPSET(0x95C6, RV620_95C6, RV620) +CHIPSET(0x95C7, RV620_95C7, RV620) +CHIPSET(0x95C9, RV620_95C9, RV620) +CHIPSET(0x95CC, RV620_95CC, RV620) +CHIPSET(0x95CD, RV620_95CD, RV620) +CHIPSET(0x95CE, RV620_95CE, RV620) +CHIPSET(0x95CF, RV620_95CF, RV620) + +CHIPSET(0x9590, RV635_9590, RV635) +CHIPSET(0x9591, RV635_9591, RV635) +CHIPSET(0x9593, RV635_9593, RV635) +CHIPSET(0x9595, RV635_9595, RV635) +CHIPSET(0x9596, RV635_9596, RV635) +CHIPSET(0x9597, RV635_9597, RV635) +CHIPSET(0x9598, RV635_9598, RV635) +CHIPSET(0x9599, RV635_9599, RV635) +CHIPSET(0x959B, RV635_959B, RV635) + +CHIPSET(0x9610, RS780_9610, RS780) +CHIPSET(0x9611, RS780_9611, RS780) +CHIPSET(0x9612, RS780_9612, RS780) +CHIPSET(0x9613, RS780_9613, RS780) +CHIPSET(0x9614, RS780_9614, RS780) +CHIPSET(0x9615, RS780_9615, RS780) +CHIPSET(0x9616, RS780_9616, RS780) + +CHIPSET(0x9710, RS880_9710, RS880) +CHIPSET(0x9711, RS880_9711, RS880) +CHIPSET(0x9712, RS880_9712, RS880) +CHIPSET(0x9713, RS880_9713, RS880) +CHIPSET(0x9714, RS880_9714, RS880) +CHIPSET(0x9715, RS880_9715, RS880) + +CHIPSET(0x9440, RV770_9440, RV770) +CHIPSET(0x9441, RV770_9441, RV770) +CHIPSET(0x9442, RV770_9442, RV770) +CHIPSET(0x9443, RV770_9443, RV770) +CHIPSET(0x9444, RV770_9444, RV770) +CHIPSET(0x9446, RV770_9446, RV770) +CHIPSET(0x944A, RV770_944A, RV770) +CHIPSET(0x944B, RV770_944B, RV770) +CHIPSET(0x944C, RV770_944C, RV770) +CHIPSET(0x944E, RV770_944E, RV770) +CHIPSET(0x9450, RV770_9450, RV770) +CHIPSET(0x9452, RV770_9452, RV770) +CHIPSET(0x9456, RV770_9456, RV770) +CHIPSET(0x945A, RV770_945A, RV770) +CHIPSET(0x945B, RV770_945B, RV770) +CHIPSET(0x945E, RV770_945E, RV770) +CHIPSET(0x9460, RV790_9460, RV770) +CHIPSET(0x9462, RV790_9462, RV770) +CHIPSET(0x946A, RV770_946A, RV770) +CHIPSET(0x946B, RV770_946B, RV770) +CHIPSET(0x947A, RV770_947A, RV770) +CHIPSET(0x947B, RV770_947B, RV770) + +CHIPSET(0x9480, RV730_9480, RV730) +CHIPSET(0x9487, RV730_9487, RV730) +CHIPSET(0x9488, RV730_9488, RV730) +CHIPSET(0x9489, RV730_9489, RV730) +CHIPSET(0x948A, RV730_948A, RV730) +CHIPSET(0x948F, RV730_948F, RV730) +CHIPSET(0x9490, RV730_9490, RV730) +CHIPSET(0x9491, RV730_9491, RV730) +CHIPSET(0x9495, RV730_9495, RV730) +CHIPSET(0x9498, RV730_9498, RV730) +CHIPSET(0x949C, RV730_949C, RV730) +CHIPSET(0x949E, RV730_949E, RV730) +CHIPSET(0x949F, RV730_949F, RV730) + +CHIPSET(0x9540, RV710_9540, RV710) +CHIPSET(0x9541, RV710_9541, RV710) +CHIPSET(0x9542, RV710_9542, RV710) +CHIPSET(0x954E, RV710_954E, RV710) +CHIPSET(0x954F, RV710_954F, RV710) +CHIPSET(0x9552, RV710_9552, RV710) +CHIPSET(0x9553, RV710_9553, RV710) +CHIPSET(0x9555, RV710_9555, RV710) +CHIPSET(0x9557, RV710_9557, RV710) +CHIPSET(0x955F, RV710_955F, RV710) + +CHIPSET(0x94A0, RV740_94A0, RV740) +CHIPSET(0x94A1, RV740_94A1, RV740) +CHIPSET(0x94A3, RV740_94A3, RV740) +CHIPSET(0x94B1, RV740_94B1, RV740) +CHIPSET(0x94B3, RV740_94B3, RV740) +CHIPSET(0x94B4, RV740_94B4, RV740) +CHIPSET(0x94B5, RV740_94B5, RV740) +CHIPSET(0x94B9, RV740_94B9, RV740) + +CHIPSET(0x68E0, CEDAR_68E0, CEDAR) +CHIPSET(0x68E1, CEDAR_68E1, CEDAR) +CHIPSET(0x68E4, CEDAR_68E4, CEDAR) +CHIPSET(0x68E5, CEDAR_68E5, CEDAR) +CHIPSET(0x68E8, CEDAR_68E8, CEDAR) +CHIPSET(0x68E9, CEDAR_68E9, CEDAR) +CHIPSET(0x68F1, CEDAR_68F1, CEDAR) +CHIPSET(0x68F2, CEDAR_68F2, CEDAR) +CHIPSET(0x68F8, CEDAR_68F8, CEDAR) +CHIPSET(0x68F9, CEDAR_68F9, CEDAR) +CHIPSET(0x68FE, CEDAR_68FE, CEDAR) + +CHIPSET(0x68C0, REDWOOD_68C0, REDWOOD) +CHIPSET(0x68C1, REDWOOD_68C1, REDWOOD) +CHIPSET(0x68C8, REDWOOD_68C8, REDWOOD) +CHIPSET(0x68C9, REDWOOD_68C9, REDWOOD) +CHIPSET(0x68D8, REDWOOD_68D8, REDWOOD) +CHIPSET(0x68D9, REDWOOD_68D9, REDWOOD) +CHIPSET(0x68DA, REDWOOD_68DA, REDWOOD) +CHIPSET(0x68DE, REDWOOD_68DE, REDWOOD) + +CHIPSET(0x68A0, JUNIPER_68A0, JUNIPER) +CHIPSET(0x68A1, JUNIPER_68A1, JUNIPER) +CHIPSET(0x68A8, JUNIPER_68A8, JUNIPER) +CHIPSET(0x68A9, JUNIPER_68A9, JUNIPER) +CHIPSET(0x68B0, JUNIPER_68B0, JUNIPER) +CHIPSET(0x68B8, JUNIPER_68B8, JUNIPER) +CHIPSET(0x68B9, JUNIPER_68B9, JUNIPER) +CHIPSET(0x68BA, JUNIPER_68BA, JUNIPER) +CHIPSET(0x68BE, JUNIPER_68BE, JUNIPER) +CHIPSET(0x68BF, JUNIPER_68BF, JUNIPER) + +CHIPSET(0x6880, CYPRESS_6880, CYPRESS) +CHIPSET(0x6888, CYPRESS_6888, CYPRESS) +CHIPSET(0x6889, CYPRESS_6889, CYPRESS) +CHIPSET(0x688A, CYPRESS_688A, CYPRESS) +CHIPSET(0x6898, CYPRESS_6898, CYPRESS) +CHIPSET(0x6899, CYPRESS_6899, CYPRESS) +CHIPSET(0x689B, CYPRESS_689B, CYPRESS) +CHIPSET(0x689E, CYPRESS_689E, CYPRESS) + +CHIPSET(0x689C, HEMLOCK_689C, HEMLOCK) +CHIPSET(0x689D, HEMLOCK_689D, HEMLOCK) + +CHIPSET(0x9802, PALM_9802, PALM) +CHIPSET(0x9803, PALM_9803, PALM) +CHIPSET(0x9804, PALM_9804, PALM) +CHIPSET(0x9805, PALM_9805, PALM) +CHIPSET(0x9806, PALM_9806, PALM) +CHIPSET(0x9807, PALM_9807, PALM) + +CHIPSET(0x9640, SUMO_9640, SUMO) +CHIPSET(0x9641, SUMO_9641, SUMO) +CHIPSET(0x9642, SUMO2_9642, SUMO2) +CHIPSET(0x9643, SUMO2_9643, SUMO2) +CHIPSET(0x9644, SUMO2_9644, SUMO2) +CHIPSET(0x9645, SUMO2_9645, SUMO2) +CHIPSET(0x9647, SUMO_9647, SUMO) +CHIPSET(0x9648, SUMO_9648, SUMO) +CHIPSET(0x964a, SUMO_964A, SUMO) +CHIPSET(0x964e, SUMO_964E, SUMO) +CHIPSET(0x964f, SUMO_964F, SUMO) + +CHIPSET(0x6700, CAYMAN_6700, CAYMAN) +CHIPSET(0x6701, CAYMAN_6701, CAYMAN) +CHIPSET(0x6702, CAYMAN_6702, CAYMAN) +CHIPSET(0x6703, CAYMAN_6703, CAYMAN) +CHIPSET(0x6704, CAYMAN_6704, CAYMAN) +CHIPSET(0x6705, CAYMAN_6705, CAYMAN) +CHIPSET(0x6706, CAYMAN_6706, CAYMAN) +CHIPSET(0x6707, CAYMAN_6707, CAYMAN) +CHIPSET(0x6708, CAYMAN_6708, CAYMAN) +CHIPSET(0x6709, CAYMAN_6709, CAYMAN) +CHIPSET(0x6718, CAYMAN_6718, CAYMAN) +CHIPSET(0x6719, CAYMAN_6719, CAYMAN) +CHIPSET(0x671C, CAYMAN_671C, CAYMAN) +CHIPSET(0x671D, CAYMAN_671D, CAYMAN) +CHIPSET(0x671F, CAYMAN_671F, CAYMAN) + +CHIPSET(0x6720, BARTS_6720, BARTS) +CHIPSET(0x6721, BARTS_6721, BARTS) +CHIPSET(0x6722, BARTS_6722, BARTS) +CHIPSET(0x6723, BARTS_6723, BARTS) +CHIPSET(0x6724, BARTS_6724, BARTS) +CHIPSET(0x6725, BARTS_6725, BARTS) +CHIPSET(0x6726, BARTS_6726, BARTS) +CHIPSET(0x6727, BARTS_6727, BARTS) +CHIPSET(0x6728, BARTS_6728, BARTS) +CHIPSET(0x6729, BARTS_6729, BARTS) +CHIPSET(0x6738, BARTS_6738, BARTS) +CHIPSET(0x6739, BARTS_6739, BARTS) +CHIPSET(0x673E, BARTS_673E, BARTS) +CHIPSET(0x6740, TURKS_6740, TURKS) +CHIPSET(0x6741, TURKS_6741, TURKS) +CHIPSET(0x6742, TURKS_6742, TURKS) +CHIPSET(0x6743, TURKS_6743, TURKS) +CHIPSET(0x6744, TURKS_6744, TURKS) +CHIPSET(0x6745, TURKS_6745, TURKS) +CHIPSET(0x6746, TURKS_6746, TURKS) +CHIPSET(0x6747, TURKS_6747, TURKS) +CHIPSET(0x6748, TURKS_6748, TURKS) +CHIPSET(0x6749, TURKS_6749, TURKS) +CHIPSET(0x6750, TURKS_6750, TURKS) +CHIPSET(0x6758, TURKS_6758, TURKS) +CHIPSET(0x6759, TURKS_6759, TURKS) +CHIPSET(0x675F, TURKS_675F, TURKS) +CHIPSET(0x6840, TURKS_6840, TURKS) +CHIPSET(0x6841, TURKS_6841, TURKS) +CHIPSET(0x6842, TURKS_6842, TURKS) +CHIPSET(0x6843, TURKS_6843, TURKS) +CHIPSET(0x6849, TURKS_6849, TURKS) +CHIPSET(0x6850, TURKS_6850, TURKS) +CHIPSET(0x6858, TURKS_6858, TURKS) +CHIPSET(0x6859, TURKS_6859, TURKS) + +CHIPSET(0x6760, CAICOS_6760, CAICOS) +CHIPSET(0x6761, CAICOS_6761, CAICOS) +CHIPSET(0x6762, CAICOS_6762, CAICOS) +CHIPSET(0x6763, CAICOS_6763, CAICOS) +CHIPSET(0x6764, CAICOS_6764, CAICOS) +CHIPSET(0x6765, CAICOS_6765, CAICOS) +CHIPSET(0x6766, CAICOS_6766, CAICOS) +CHIPSET(0x6767, CAICOS_6767, CAICOS) +CHIPSET(0x6768, CAICOS_6768, CAICOS) +CHIPSET(0x6770, CAICOS_6770, CAICOS) +CHIPSET(0x6778, CAICOS_6778, CAICOS) +CHIPSET(0x6779, CAICOS_6779, CAICOS) diff --git a/radeon/radeon_surface.c b/radeon/radeon_surface.c new file mode 100644 index 00000000..0f01e2ed --- /dev/null +++ b/radeon/radeon_surface.c @@ -0,0 +1,995 @@ +/* + * Copyright © 2011 Red Hat All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS + * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Jérôme Glisse <jglisse@redhat.com> + */ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include "drm.h" +#include "xf86drm.h" +#include "radeon_drm.h" +#include "radeon_surface.h" + +#define ALIGN(value, alignment) (((value) + alignment - 1) & ~(alignment - 1)) +#define MAX2(A, B) ((A) > (B) ? (A) : (B)) +#define MIN2(A, B) ((A) < (B) ? (A) : (B)) + +/* keep this private */ +enum radeon_family { + CHIP_UNKNOWN, + CHIP_R600, + CHIP_RV610, + CHIP_RV630, + CHIP_RV670, + CHIP_RV620, + CHIP_RV635, + CHIP_RS780, + CHIP_RS880, + CHIP_RV770, + CHIP_RV730, + CHIP_RV710, + CHIP_RV740, + CHIP_CEDAR, + CHIP_REDWOOD, + CHIP_JUNIPER, + CHIP_CYPRESS, + CHIP_HEMLOCK, + CHIP_PALM, + CHIP_SUMO, + CHIP_SUMO2, + CHIP_BARTS, + CHIP_TURKS, + CHIP_CAICOS, + CHIP_CAYMAN, + CHIP_LAST, +}; + +typedef int (*hw_init_surface_t)(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf); +typedef int (*hw_best_surface_t)(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf); + +struct radeon_hw_info { + /* apply to r6, eg */ + uint32_t group_bytes; + uint32_t num_banks; + uint32_t num_pipes; + /* apply to eg */ + uint32_t row_size; + unsigned allow_2d; +}; + +struct radeon_surface_manager { + int fd; + uint32_t device_id; + struct radeon_hw_info hw_info; + unsigned family; + hw_init_surface_t surface_init; + hw_best_surface_t surface_best; +}; + +/* helper */ +static int radeon_get_value(int fd, unsigned req, uint32_t *value) +{ + struct drm_radeon_info info = {}; + int r; + + *value = 0; + info.request = req; + info.value = (uintptr_t)value; + r = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, + sizeof(struct drm_radeon_info)); + return r; +} + +static int radeon_get_family(struct radeon_surface_manager *surf_man) +{ + switch (surf_man->device_id) { +#define CHIPSET(pci_id, name, fam) case pci_id: surf_man->family = CHIP_##fam; break; +#include "r600_pci_ids.h" +#undef CHIPSET + default: + return -EINVAL; + } + return 0; +} + +static unsigned next_power_of_two(unsigned x) +{ + if (x <= 1) + return 1; + + return (1 << ((sizeof(unsigned) * 8) - __builtin_clz(x - 1))); +} + +static unsigned mip_minify(unsigned size, unsigned level) +{ + unsigned val; + + val = MAX2(1, size >> level); + if (level > 0) + val = next_power_of_two(val); + return val; +} + +static void surf_minify(struct radeon_surface *surf, + unsigned level, + uint32_t xalign, uint32_t yalign, uint32_t zalign, + unsigned offset) +{ + surf->level[level].nblk_x = mip_minify(surf->nblk_x, level); + surf->level[level].nblk_y = mip_minify(surf->nblk_y, level); + surf->level[level].nblk_z = mip_minify(surf->nblk_z, level); + surf->level[level].npix_x = mip_minify(surf->npix_x, level); + surf->level[level].npix_y = mip_minify(surf->npix_y, level); + surf->level[level].npix_z = mip_minify(surf->npix_z, level); + if (surf->level[level].mode == RADEON_SURF_MODE_2D) { + if (surf->level[level].nblk_x < xalign || surf->level[level].nblk_y < yalign) { + surf->level[level].mode = RADEON_SURF_MODE_1D; + return; + } + } + surf->level[level].nblk_x = ALIGN(surf->level[level].nblk_x, xalign); + surf->level[level].nblk_y = ALIGN(surf->level[level].nblk_y, yalign); + surf->level[level].nblk_z = ALIGN(surf->level[level].nblk_z, zalign); + + surf->level[level].offset = offset; + surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe; + surf->level[level].slice_size = surf->level[level].pitch_bytes * surf->level[level].nblk_y; + + surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size; +} + +/* =========================================================================== + * r600/r700 family + */ +static int r6_init_hw_info(struct radeon_surface_manager *surf_man) +{ + uint32_t tiling_config; + int r; + + r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG, + &tiling_config); + if (r) { + return r; + } + + switch ((tiling_config & 0xe) >> 1) { + case 0: + surf_man->hw_info.num_pipes = 1; + break; + case 1: + surf_man->hw_info.num_pipes = 2; + break; + case 2: + surf_man->hw_info.num_pipes = 4; + break; + case 3: + surf_man->hw_info.num_pipes = 8; + break; + default: + return -EINVAL; + } + + switch ((tiling_config & 0x30) >> 4) { + case 0: + surf_man->hw_info.num_banks = 4; + break; + case 1: + surf_man->hw_info.num_banks = 8; + break; + default: + return -EINVAL; + } + + switch ((tiling_config & 0xc0) >> 6) { + case 0: + surf_man->hw_info.group_bytes = 256; + break; + case 1: + surf_man->hw_info.group_bytes = 512; + break; + default: + return -EINVAL; + } + return 0; +} + +static int r6_surface_init_linear(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign; + unsigned i; + + /* compute alignment */ + if (!start_level) { + surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes); + } + /* the 32 alignment is for scanout, cb or db but to allow texture to be + * easily bound as such we force this alignment to all surface + */ + xalign = MAX2(32, surf_man->hw_info.group_bytes / surf->bpe); + yalign = 1; + zalign = 1; + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_LINEAR; + surf_minify(surf, i, xalign, yalign, zalign, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if ((i == 0)) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int r6_surface_init_linear_aligned(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign; + unsigned i; + + /* compute alignment */ + if (!start_level) { + surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes); + } + xalign = MAX2(64, surf_man->hw_info.group_bytes / surf->bpe); + yalign = 1; + zalign = 1; + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED; + surf_minify(surf, i, xalign, yalign, zalign, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if ((i == 0)) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int r6_surface_init_1d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign, tilew; + unsigned i; + + /* compute alignment */ + tilew = 8; + xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples); + xalign = MAX2(tilew, xalign); + yalign = tilew; + zalign = 1; + if (!start_level) { + surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes); + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_1D; + surf_minify(surf, i, xalign, yalign, zalign, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if ((i == 0)) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int r6_surface_init_2d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign, tilew; + unsigned i; + + /* compute alignment */ + tilew = 8; + zalign = 1; + xalign = (surf_man->hw_info.group_bytes * surf_man->hw_info.num_banks) / + (tilew * surf->bpe * surf->nsamples); + xalign = MAX2(tilew * surf_man->hw_info.num_banks, xalign); + yalign = tilew * surf_man->hw_info.num_pipes; + if (!start_level) { + surf->bo_alignment = + MAX2(surf_man->hw_info.num_pipes * + surf_man->hw_info.num_banks * + surf->bpe * 64, + xalign * yalign * surf->nsamples * surf->bpe); + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_2D; + surf_minify(surf, i, xalign, yalign, zalign, offset); + if (surf->level[i].mode == RADEON_SURF_MODE_1D) { + return r6_surface_init_1d(surf_man, surf, offset, i); + } + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if ((i == 0)) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int r6_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode; + int r; + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + /* check surface dimension */ + if (surf->npix_x > 8192 || surf->npix_y > 8192 || surf->npix_z > 8192) { + return -EINVAL; + } + + /* check mipmap last_level */ + if (surf->last_level > 14) { + return -EINVAL; + } + + /* check tiling mode */ + switch (mode) { + case RADEON_SURF_MODE_LINEAR: + r = r6_surface_init_linear(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_LINEAR_ALIGNED: + r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_1D: + r = r6_surface_init_1d(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_2D: + r = r6_surface_init_2d(surf_man, surf, 0, 0); + break; + default: + return -EINVAL; + } + return r; +} + +static int r6_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + /* no value to optimize for r6xx/r7xx */ + return 0; +} + + +/* =========================================================================== + * evergreen family + */ +static int eg_init_hw_info(struct radeon_surface_manager *surf_man) +{ + uint32_t tiling_config; + drmVersionPtr version; + int r; + + r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG, + &tiling_config); + if (r) { + return r; + } + + surf_man->hw_info.allow_2d = 0; + version = drmGetVersion(surf_man->fd); + if (version && version->version_minor >= 14) { + surf_man->hw_info.allow_2d = 1; + } + + switch (tiling_config & 0xf) { + case 0: + surf_man->hw_info.num_pipes = 1; + break; + case 1: + surf_man->hw_info.num_pipes = 2; + break; + case 2: + surf_man->hw_info.num_pipes = 4; + break; + case 3: + surf_man->hw_info.num_pipes = 8; + break; + default: + return -EINVAL; + } + + switch ((tiling_config & 0xf0) >> 4) { + case 0: + surf_man->hw_info.num_banks = 4; + break; + case 1: + surf_man->hw_info.num_banks = 8; + break; + case 2: + surf_man->hw_info.num_banks = 16; + break; + default: + return -EINVAL; + } + + switch ((tiling_config & 0xf00) >> 8) { + case 0: + surf_man->hw_info.group_bytes = 256; + break; + case 1: + surf_man->hw_info.group_bytes = 512; + break; + default: + return -EINVAL; + } + + switch ((tiling_config & 0xf000) >> 12) { + case 0: + surf_man->hw_info.row_size = 1024; + break; + case 1: + surf_man->hw_info.row_size = 2048; + break; + case 2: + surf_man->hw_info.row_size = 4096; + break; + default: + return -EINVAL; + } + return 0; +} + +static void eg_surf_minify(struct radeon_surface *surf, + unsigned level, + unsigned slice_pt, + unsigned mtilew, + unsigned mtileh, + unsigned mtileb, + unsigned offset) +{ + unsigned mtile_pr, mtile_ps; + + surf->level[level].nblk_x = mip_minify(surf->nblk_x, level); + surf->level[level].nblk_y = mip_minify(surf->nblk_y, level); + surf->level[level].nblk_z = mip_minify(surf->nblk_z, level); + surf->level[level].npix_x = mip_minify(surf->npix_x, level); + surf->level[level].npix_y = mip_minify(surf->npix_y, level); + surf->level[level].npix_z = mip_minify(surf->npix_z, level); + if (surf->level[level].mode == RADEON_SURF_MODE_2D) { + if (surf->level[level].nblk_x < mtilew || surf->level[level].nblk_y < mtileh) { + surf->level[level].mode = RADEON_SURF_MODE_1D; + return; + } + } + surf->level[level].nblk_x = ALIGN(surf->level[level].nblk_x, mtilew); + surf->level[level].nblk_y = ALIGN(surf->level[level].nblk_y, mtileh); + surf->level[level].nblk_z = ALIGN(surf->level[level].nblk_z, 1); + + /* macro tile per row */ + mtile_pr = surf->level[level].nblk_x / mtilew; + /* macro tile per slice */ + mtile_ps = (mtile_pr * surf->level[level].nblk_y) / mtileh; + + surf->level[level].offset = offset; + surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe * slice_pt; + surf->level[level].slice_size = mtile_ps * mtileb * slice_pt; + + surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size; +} + +static int eg_surface_init_1d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign, tilew; + unsigned i; + + /* compute alignment */ + tilew = 8; + xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples); + if (surf->flags & RADEON_SURF_SBUFFER) { + surf->stencil_offset = 0; + surf->stencil_tile_split = 0; + xalign = surf_man->hw_info.group_bytes / (tilew * surf->nsamples); + } + xalign = MAX2(tilew, xalign); + yalign = tilew; + zalign = 1; + if (!start_level) { + surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes); + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_1D; + surf_minify(surf, i, xalign, yalign, zalign, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if ((i == 0)) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + + if (surf->flags & RADEON_SURF_SBUFFER) { + surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment); + surf->bo_size = surf->stencil_offset + surf->bo_size / 4; + } + + return 0; +} + +static int eg_surface_init_2d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + unsigned tilew, tileh, tileb; + unsigned mtilew, mtileh, mtileb; + unsigned slice_pt; + unsigned i; + + surf->stencil_offset = 0; + /* compute tile values */ + tilew = 8; + tileh = 8; + tileb = tilew * tileh * surf->bpe * surf->nsamples; + /* slices per tile */ + slice_pt = 1; + if (tileb > surf->tile_split) { + slice_pt = tileb / surf->tile_split; + } + tileb = tileb / slice_pt; + + /* macro tile width & height */ + mtilew = (tilew * surf->bankw * surf_man->hw_info.num_pipes) * surf->mtilea; + mtileh = (tileh * surf->bankh * surf_man->hw_info.num_banks) / surf->mtilea; + /* macro tile bytes */ + mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb; + + /* check if surface is big enought */ + if (surf->nblk_x < mtilew || surf->nblk_y < mtileh) { + surf->level[start_level].mode = RADEON_SURF_MODE_1D; + return eg_surface_init_1d(surf_man, surf, offset, start_level); + } + + if (!start_level) { + surf->bo_alignment = MAX2(256, mtileb); + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_2D; + eg_surf_minify(surf, i, slice_pt, mtilew, mtileh, mtileb, offset); + if (surf->level[i].mode == RADEON_SURF_MODE_1D) { + return r6_surface_init_1d(surf_man, surf, offset, i); + } + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if ((i == 0)) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + + if (surf->flags & RADEON_SURF_SBUFFER) { + surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment); + surf->bo_size = surf->stencil_offset + surf->bo_size / 4; + } + + return 0; +} + +static int eg_surface_sanity(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + unsigned mode) +{ + unsigned tileb; + + /* check surface dimension */ + if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) { + return -EINVAL; + } + + /* check mipmap last_level */ + if (surf->last_level > 15) { + return -EINVAL; + } + + /* check tile split */ + switch (surf->tile_split) { + case 0: + if (mode == RADEON_SURF_MODE_2D) { + return -EINVAL; + } + case 64: + case 128: + case 256: + case 512: + case 1024: + case 2048: + case 4096: + break; + default: + return -EINVAL; + } + switch (surf->mtilea) { + case 0: + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + /* check aspect ratio */ + if (surf_man->hw_info.num_banks < surf->mtilea) { + return -EINVAL; + } + /* check bank width */ + switch (surf->bankw) { + case 0: + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + /* check bank height */ + switch (surf->bankh) { + case 0: + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples); + if ((tileb * surf->bankh * surf->bankw) < surf_man->hw_info.group_bytes) { + if (mode == RADEON_SURF_MODE_2D) { + return -EINVAL; + } + } + + /* force 1d on kernel that can't do 2d */ + if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) { + mode = RADEON_SURF_MODE_1D; + } + + return 0; +} + +static int eg_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode; + int r; + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + /* for some reason eg need to have room for stencil right after depth */ + if (surf->flags & RADEON_SURF_ZBUFFER) { + surf->flags |= RADEON_SURF_SBUFFER; + } + + r = eg_surface_sanity(surf_man, surf, mode); + if (r) { + return r; + } + + /* check tiling mode */ + switch (mode) { + case RADEON_SURF_MODE_LINEAR: + r = r6_surface_init_linear(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_LINEAR_ALIGNED: + r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_1D: + r = eg_surface_init_1d(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_2D: + r = eg_surface_init_2d(surf_man, surf, 0, 0); + break; + default: + return -EINVAL; + } + return r; +} + +static unsigned log2_int(unsigned x) +{ + unsigned l; + + if (x < 2) { + return 0; + } + for (l = 2; ; l++) { + if ((unsigned)(1 << l) > x) { + return l - 1; + } + } + return 0; +} + +/* compute best tile_split, bankw, bankh, mtilea + * depending on surface + */ +static int eg_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, tileb, h_over_w; + int r; + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + /* for some reason eg need to have room for stencil right after depth */ + if (surf->flags & RADEON_SURF_ZBUFFER) { + surf->flags |= RADEON_SURF_SBUFFER; + } + + /* set some default value to avoid sanity check choking on them */ + surf->tile_split = 1024; + surf->bankw = 1; + surf->bankh = 1; + surf->mtilea = surf_man->hw_info.num_banks; + tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples); + for (; surf->bankh <= 8; surf->bankh *= 2) { + if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) { + break; + } + } + if (surf->mtilea > 8) { + surf->mtilea = 8; + } + + r = eg_surface_sanity(surf_man, surf, mode); + if (r) { + return r; + } + + if (mode != RADEON_SURF_MODE_2D) { + /* nothing to do for non 2D tiled surface */ + return 0; + } + + /* set tile split to row size, optimize latter for multi-sample surface + * tile split >= 256 for render buffer surface. Also depth surface want + * smaller value for optimal performances. + */ + surf->tile_split = surf_man->hw_info.row_size; + surf->stencil_tile_split = surf_man->hw_info.row_size / 2; + + /* bankw or bankh greater than 1 increase alignment requirement, not + * sure if it's worth using smaller bankw & bankh to stick with 2D + * tiling on small surface rather than falling back to 1D tiling. + * Use recommanded value based on tile size for now. + * + * fmask buffer has different optimal value figure them out once we + * use it. + */ + if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) { + /* assume 1 bytes for stencil, we optimize for stencil as stencil + * and depth shares surface values + */ + tileb = MIN2(surf->tile_split, 64 * surf->nsamples); + } else { + tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples); + } + + /* use bankw of 1 to minimize width alignment, might be interesting to + * increase it for large surface + */ + surf->bankw = 1; + switch (tileb) { + case 64: + surf->bankh = 4; + break; + case 128: + case 256: + surf->bankh = 2; + break; + default: + surf->bankh = 1; + break; + } + /* double check the constraint */ + for (; surf->bankh <= 8; surf->bankh *= 2) { + if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) { + break; + } + } + + h_over_w = (((surf->bankh * surf_man->hw_info.num_banks) << 16) / + (surf->bankw * surf_man->hw_info.num_pipes)) >> 16; + surf->mtilea = 1 << (log2_int(h_over_w) >> 1); + + return 0; +} + + +/* =========================================================================== + * public API + */ +struct radeon_surface_manager *radeon_surface_manager_new(int fd) +{ + struct radeon_surface_manager *surf_man; + + surf_man = calloc(1, sizeof(struct radeon_surface_manager)); + if (surf_man == NULL) { + return NULL; + } + surf_man->fd = fd; + if (radeon_get_value(fd, RADEON_INFO_DEVICE_ID, &surf_man->device_id)) { + goto out_err; + } + if (radeon_get_family(surf_man)) { + goto out_err; + } + + if (surf_man->family <= CHIP_RV740) { + if (r6_init_hw_info(surf_man)) { + goto out_err; + } + surf_man->surface_init = &r6_surface_init; + surf_man->surface_best = &r6_surface_best; + } else { + if (eg_init_hw_info(surf_man)) { + goto out_err; + } + surf_man->surface_init = &eg_surface_init; + surf_man->surface_best = &eg_surface_best; + } + + return surf_man; +out_err: + free(surf_man); + return NULL; +} + +void radeon_surface_manager_free(struct radeon_surface_manager *surf_man) +{ + free(surf_man); +} + +static int radeon_surface_sanity(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + unsigned type, + unsigned mode) +{ + if (surf_man == NULL || surf_man->surface_init == NULL || surf == NULL) { + return -EINVAL; + } + + /* all dimension must be at least 1 ! */ + if (!surf->npix_x || !surf->npix_y || !surf->npix_z) { + return -EINVAL; + } + if (!surf->nblk_x || !surf->nblk_y || !surf->nblk_z) { + return -EINVAL; + } + if (surf->npix_x < surf->nblk_x || surf->npix_y < surf->nblk_y || surf->npix_z < surf->nblk_z) { + return -EINVAL; + } + if (!surf->array_size) { + return -EINVAL; + } + /* array size must be a power of 2 */ + surf->array_size = next_power_of_two(surf->array_size); + + switch (surf->nsamples) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + /* check type */ + switch (type) { + case RADEON_SURF_TYPE_1D: + if (surf->npix_y > 1) { + return -EINVAL; + } + case RADEON_SURF_TYPE_2D: + if (surf->npix_z > 1) { + return -EINVAL; + } + break; + case RADEON_SURF_TYPE_CUBEMAP: + if (surf->npix_z > 1) { + return -EINVAL; + } + /* deal with cubemap as they were texture array */ + if (surf_man->family >= CHIP_RV770) { + surf->array_size = 8; + } else { + surf->array_size = 6; + } + break; + case RADEON_SURF_TYPE_3D: + break; + case RADEON_SURF_TYPE_1D_ARRAY: + if (surf->npix_y > 1) { + return -EINVAL; + } + case RADEON_SURF_TYPE_2D_ARRAY: + break; + default: + return -EINVAL; + } + return 0; +} + +int radeon_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, type; + int r; + + type = RADEON_SURF_GET(surf->flags, TYPE); + mode = RADEON_SURF_GET(surf->flags, MODE); + + r = radeon_surface_sanity(surf_man, surf, type, mode); + if (r) { + return r; + } + return surf_man->surface_init(surf_man, surf); +} + +int radeon_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, type; + int r; + + type = RADEON_SURF_GET(surf->flags, TYPE); + mode = RADEON_SURF_GET(surf->flags, MODE); + + r = radeon_surface_sanity(surf_man, surf, type, mode); + if (r) { + return r; + } + return surf_man->surface_best(surf_man, surf); +} diff --git a/radeon/radeon_surface.h b/radeon/radeon_surface.h new file mode 100644 index 00000000..3e5fbedc --- /dev/null +++ b/radeon/radeon_surface.h @@ -0,0 +1,114 @@ +/* + * Copyright © 2011 Red Hat All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS + * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Jérôme Glisse <jglisse@redhat.com> + */ +#ifndef RADEON_SURFACE_H +#define RADEON_SURFACE_H + +/* Note : + * + * For texture array, the n layer are stored one after the other within each + * mipmap level. 0 value for field than can be hint is always valid. + */ + +#define RADEON_SURF_MAX_LEVEL 32 + +#define RADEON_SURF_TYPE_MASK 0xFF +#define RADEON_SURF_TYPE_SHIFT 0 +#define RADEON_SURF_TYPE_1D 0 +#define RADEON_SURF_TYPE_2D 1 +#define RADEON_SURF_TYPE_3D 2 +#define RADEON_SURF_TYPE_CUBEMAP 3 +#define RADEON_SURF_TYPE_1D_ARRAY 4 +#define RADEON_SURF_TYPE_2D_ARRAY 5 +#define RADEON_SURF_MODE_MASK 0xFF +#define RADEON_SURF_MODE_SHIFT 8 +#define RADEON_SURF_MODE_LINEAR 0 +#define RADEON_SURF_MODE_LINEAR_ALIGNED 1 +#define RADEON_SURF_MODE_1D 2 +#define RADEON_SURF_MODE_2D 3 +#define RADEON_SURF_SCANOUT (1 << 16) +#define RADEON_SURF_ZBUFFER (1 << 17) +#define RADEON_SURF_SBUFFER (1 << 18) + +#define RADEON_SURF_GET(v, field) (((v) >> RADEON_SURF_ ## field ## _SHIFT) & RADEON_SURF_ ## field ## _MASK) +#define RADEON_SURF_SET(v, field) (((v) & RADEON_SURF_ ## field ## _MASK) << RADEON_SURF_ ## field ## _SHIFT) +#define RADEON_SURF_CLR(v, field) ((v) & ~(RADEON_SURF_ ## field ## _MASK << RADEON_SURF_ ## field ## _SHIFT)) + +/* first field up to mode need to match r6 struct so that we can reuse + * same function for linear & linear aligned + */ +struct radeon_surface_level { + uint64_t offset; + uint64_t slice_size; + uint32_t npix_x; + uint32_t npix_y; + uint32_t npix_z; + uint32_t nblk_x; + uint32_t nblk_y; + uint32_t nblk_z; + uint32_t pitch_bytes; + uint32_t mode; +}; + +struct radeon_surface { + uint32_t npix_x; + uint32_t npix_y; + uint32_t npix_z; + uint32_t nblk_x; + uint32_t nblk_y; + uint32_t nblk_z; + uint32_t array_size; + uint32_t last_level; + uint32_t bpe; + uint32_t nsamples; + uint32_t flags; + /* Following is updated/fill by the allocator. It's allowed to + * set some of the value but they are use as hint and can be + * overridden (things lile bankw/bankh on evergreen for + * instance). + */ + uint64_t bo_size; + uint64_t bo_alignment; + /* apply to eg */ + uint32_t bankw; + uint32_t bankh; + uint32_t mtilea; + uint32_t tile_split; + uint32_t stencil_tile_split; + uint64_t stencil_offset; + struct radeon_surface_level level[RADEON_SURF_MAX_LEVEL]; +}; + +struct radeon_surface_manager *radeon_surface_manager_new(int fd); +void radeon_surface_manager_free(struct radeon_surface_manager *surf_man); +int radeon_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf); +int radeon_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf); + +#endif |