[PATCH] radeon: add surface allocator helper

Jerome Glisse jglisse at redhat.com
Fri Dec 9 18:07:15 PST 2011


The surface allocator is able to build complete miptree when allocating
surface for r600/r700/evergreen/northern islands GPU family. It also
compute bo size and alignment for render buffer, depth buffer and
scanout buffer.

Signed-off-by: Jerome Glisse <jglisse at redhat.com>
---
 include/drm/radeon_drm.h |   20 +-
 radeon/Makefile.am       |    2 +
 radeon/r600_pci_ids.h    |  271 +++++++++++++
 radeon/radeon_surface.c  | 1010 ++++++++++++++++++++++++++++++++++++++++++++++
 radeon/radeon_surface.h  |  108 +++++
 5 files changed, 1404 insertions(+), 7 deletions(-)
 create mode 100644 radeon/r600_pci_ids.h
 create mode 100644 radeon/radeon_surface.c
 create mode 100644 radeon/radeon_surface.h

diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h
index 67b5622..158f6df 100644
--- a/include/drm/radeon_drm.h
+++ b/include/drm/radeon_drm.h
@@ -804,13 +804,19 @@ struct drm_radeon_gem_create {
 	uint32_t	flags;
 };
 
-#define RADEON_TILING_MACRO       0x1
-#define RADEON_TILING_MICRO       0x2
-#define RADEON_TILING_SWAP_16BIT  0x4
-#define RADEON_TILING_SWAP_32BIT  0x8
-#define RADEON_TILING_SURFACE     0x10 /* this object requires a surface
-					* when mapped - i.e. front buffer */
-#define RADEON_TILING_MICRO_SQUARE 0x20
+#define RADEON_TILING_MACRO				0x1
+#define RADEON_TILING_MICRO				0x2
+#define RADEON_TILING_SWAP_16BIT			0x4
+#define RADEON_TILING_SWAP_32BIT			0x8
+/* this object requires a surface when mapped - i.e. front buffer */
+#define RADEON_TILING_SURFACE				0x10
+#define RADEON_TILING_MICRO_SQUARE			0x20
+#define RADEON_TILING_EG_BANKW_SHIFT			8
+#define RADEON_TILING_EG_BANKW_MASK			0xf
+#define RADEON_TILING_EG_BANKH_SHIFT			12
+#define RADEON_TILING_EG_BANKH_MASK			0xf
+#define RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT	16
+#define RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK		0xf
 
 struct drm_radeon_gem_set_tiling {
 	uint32_t	handle;
diff --git a/radeon/Makefile.am b/radeon/Makefile.am
index dc94b5f..e64aff4 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 0000000..0ffb741
--- /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 0000000..d236b08
--- /dev/null
+++ b/radeon/radeon_surface.c
@@ -0,0 +1,1010 @@
+/*
+ * 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 at 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);
+
+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;
+};
+
+/* 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 walign, uint32_t halign, uint32_t dalign,
+                        uint32_t *w, uint32_t *h, uint32_t *d,
+                        uint32_t *wa, uint32_t *ha, uint32_t *da)
+{
+    unsigned type;
+
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+    switch (type) {
+    case RADEON_SURF_TYPE_1D:
+        *wa = ALIGN(mip_minify(surf->width, level), walign);
+        *ha = 1;
+        *da = 1;
+        *w = mip_minify(surf->width, level);
+        *h = 1;
+        *d = 1;
+        break;
+    case RADEON_SURF_TYPE_2D:
+    case RADEON_SURF_TYPE_CUBEMAP:
+        *wa = ALIGN(mip_minify(surf->width, level), walign);
+        *ha = ALIGN(mip_minify(surf->height, level), halign);
+        *da = 1;
+        *w = mip_minify(surf->width, level);
+        *h = mip_minify(surf->height, level);
+        *d = 1;
+        break;
+    case RADEON_SURF_TYPE_3D:
+        *wa = ALIGN(mip_minify(surf->width, level), walign);
+        *ha = ALIGN(mip_minify(surf->height, level), halign);
+        *da = ALIGN(mip_minify(surf->depth, level), dalign);
+        *w = mip_minify(surf->width, level);
+        *h = mip_minify(surf->height, level);
+        *d = mip_minify(surf->depth, level);
+        break;
+    case RADEON_SURF_TYPE_1D_ARRAY:
+        *wa = ALIGN(mip_minify(surf->width, level), walign);
+        *ha = 1;
+        *da = surf->depth;
+        *w = mip_minify(surf->width, level);
+        *h = 1;
+        *d = surf->depth;
+        break;
+    case RADEON_SURF_TYPE_2D_ARRAY:
+        *wa = ALIGN(mip_minify(surf->width, level), walign);
+        *ha = ALIGN(mip_minify(surf->height, level), halign);
+        *da = surf->depth;
+        *w = mip_minify(surf->width, level);
+        *h = mip_minify(surf->height, level);
+        *d = surf->depth;
+        break;
+    default:
+        *wa = 0;
+        *ha = 0;
+        *da = 0;
+        *w = 0;
+        *h = 0;
+        *d = 0;
+        break;
+    }
+}
+
+/* ===========================================================================
+ * 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 wa, ha, da, w, h, d, walign, halign, dalign;
+    unsigned i, type;
+
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+    /* 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
+     */
+    walign = MAX2(32, surf_man->hw_info.group_bytes / surf->element_bytes);
+    halign = 1;
+    dalign = 1;
+
+    /* build mipmap tree */
+    for (i = start_level; i <= surf->last_level; i++) {
+        surf_minify(surf, i, walign, halign, dalign, &w, &h, &d, &wa, &ha, &da);
+        surf->level[i].offset = offset;
+        surf->level[i].width = w;
+        surf->level[i].height = h;
+        surf->level[i].depth = d;
+        surf->level[i].height_aligned = ha;
+        surf->level[i].pitch = wa;
+        surf->level[i].pitch_bytes = wa * surf->element_bytes;
+        surf->level[i].layer_size = surf->level[i].pitch_bytes * ha;
+        surf->level[i].mode = RADEON_SURF_MODE_LINEAR;
+        /* compute next offset */
+        if (type == RADEON_SURF_TYPE_CUBEMAP) {
+            if (surf_man->family >= CHIP_RV770) {
+                offset += surf->level[i].layer_size * da * 8;
+            } else {
+                offset += surf->level[i].layer_size * da * 6;
+            }
+        } else {
+            offset += surf->level[i].layer_size * da;
+        }
+        /* level0 and first mipmap need to have alignment */
+        if ((i == 0)) {
+            offset = ALIGN(offset, surf->bo_alignment);
+        }
+    }
+    surf->bo_size = offset;
+    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 wa, ha, da, w, h, d, walign, halign, dalign;
+    unsigned i, type;
+
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+    /* compute alignment */
+    if (!start_level) {
+        surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes);
+    }
+    walign = MAX2(64, surf_man->hw_info.group_bytes / surf->element_bytes);
+    halign = 1;
+    dalign = 1;
+
+    /* build mipmap tree */
+    for (i = start_level; i <= surf->last_level; i++) {
+        surf_minify(surf, i, walign, halign, dalign, &w, &h, &d, &wa, &ha, &da);
+        surf->level[i].offset = offset;
+        surf->level[i].width = w;
+        surf->level[i].height = h;
+        surf->level[i].depth = d;
+        surf->level[i].height_aligned = ha;
+        surf->level[i].pitch = wa;
+        surf->level[i].pitch_bytes = wa * surf->element_bytes;
+        surf->level[i].layer_size = surf->level[i].pitch_bytes * ha;
+        surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
+        /* compute next offset */
+        if (type == RADEON_SURF_TYPE_CUBEMAP) {
+            if (surf_man->family >= CHIP_RV770) {
+                offset += surf->level[i].layer_size * da * 8;
+            } else {
+                offset += surf->level[i].layer_size * da * 6;
+            }
+        } else {
+            offset += surf->level[i].layer_size * da;
+        }
+        /* level0 and first mipmap need to have alignment */
+        if ((i == 0)) {
+            offset = ALIGN(offset, surf->bo_alignment);
+        }
+    }
+    surf->bo_size = offset;
+    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 wa, ha, da, w, h, d, walign, halign, dalign, tilew;
+    unsigned i, type;
+
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+    /* check thin factor */
+    switch (surf->thin_factor) {
+    case 0:
+    case 1:
+        surf->thin_factor = 1;
+        break;
+    case 2:
+    case 4:
+        if (surf->tile_thickness > 1) {
+            return -EINVAL;
+        }
+        break;
+    default:
+        return -EINVAL;
+    }
+    /* check tile thickness */
+    switch (surf->tile_thickness) {
+    case 0:
+    case 1:
+        surf->tile_thickness = 1;
+        dalign = 1;
+        break;
+    case 4:
+        if (type != RADEON_SURF_TYPE_3D) {
+            /* don't think it's forbidden but it's useless so refuse it */
+            return -EINVAL;
+        }
+        dalign = 4;
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    /* compute alignment */
+    tilew = surf->thin_factor * 8;
+    walign = surf_man->hw_info.group_bytes /
+             (tilew * surf->tile_thickness * surf->element_bytes *
+             surf->nsamples);
+    walign = MAX2(tilew, walign);
+    halign = tilew;
+    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_minify(surf, i, walign, halign, dalign, &w, &h, &d, &wa, &ha, &da);
+        surf->level[i].offset = offset;
+        surf->level[i].width = w;
+        surf->level[i].height = h;
+        surf->level[i].depth = d;
+        surf->level[i].height_aligned = ha;
+        surf->level[i].pitch = wa;
+        surf->level[i].pitch_bytes = wa * surf->element_bytes;
+        surf->level[i].layer_size = surf->level[i].pitch_bytes * ha;
+        surf->level[i].mode = RADEON_SURF_MODE_1D;
+        /* compute next offset */
+        if (type == RADEON_SURF_TYPE_CUBEMAP) {
+            if (surf_man->family >= CHIP_RV770) {
+                offset += surf->level[i].layer_size * da * 8;
+            } else {
+                offset += surf->level[i].layer_size * da * 6;
+            }
+        } else {
+            offset += surf->level[i].layer_size * da;
+        }
+        /* level0 and first mipmap need to have alignment */
+        if ((i == 0)) {
+            offset = ALIGN(offset, surf->bo_alignment);
+        }
+    }
+    surf->bo_size = offset;
+    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 wa, ha, da, w, h, d, walign, halign, dalign, tilew;
+    unsigned i, type;
+
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+    /* check thin factor */
+    switch (surf->thin_factor) {
+    case 0:
+    case 1:
+        surf->thin_factor = 1;
+        break;
+    case 2:
+    case 4:
+        if (surf->tile_thickness > 1) {
+            return -EINVAL;
+        }
+        break;
+    default:
+        return -EINVAL;
+    }
+    /* check tile thickness */
+    switch (surf->tile_thickness) {
+    case 0:
+    case 1:
+        surf->tile_thickness = 1;
+        dalign = 1;
+        break;
+    case 4:
+        if (type != RADEON_SURF_TYPE_3D) {
+            /* don't think it's forbidden but it's useless so refuse it */
+            return -EINVAL;
+        }
+        dalign = 4;
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    /* compute alignment */
+    tilew = surf->thin_factor * 8;
+    walign = (surf_man->hw_info.group_bytes * surf_man->hw_info.num_banks) /
+             (tilew * surf->element_bytes * surf->nsamples);
+    walign = MAX2(surf_man->hw_info.num_banks / surf->thin_factor,
+                  walign) * tilew;
+    halign = tilew * surf->thin_factor * 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->element_bytes * 64,
+                 walign * halign * surf->nsamples * surf->element_bytes);
+    }
+
+    /* build mipmap tree */
+    for (i = start_level; i <= surf->last_level; i++) {
+        /* if level is smaller than tile block we need to switch to 1D tile */
+        surf_minify(surf, i, walign, halign, dalign, &w, &h, &d, &wa, &ha, &da);
+        if (w < walign || h < halign) {
+            surf->level[i].mode = RADEON_SURF_MODE_1D;
+            return r6_surface_init_1d(surf_man, surf, offset, i);
+        }
+        surf->level[i].offset = offset;
+        surf->level[i].width = w;
+        surf->level[i].height = h;
+        surf->level[i].depth = d;
+        surf->level[i].height_aligned = ha;
+        surf->level[i].pitch = wa;
+        surf->level[i].pitch_bytes = wa * surf->element_bytes;
+        surf->level[i].layer_size = surf->level[i].pitch_bytes * ha;
+        surf->level[i].mode = RADEON_SURF_MODE_2D;
+        /* compute next offset */
+        if (type == RADEON_SURF_TYPE_CUBEMAP) {
+            if (surf_man->family >= CHIP_RV770) {
+                offset += surf->level[i].layer_size * da * 8;
+            } else {
+                offset += surf->level[i].layer_size * da * 6;
+            }
+        } else {
+            offset += surf->level[i].layer_size * da;
+        }
+        /* level0 and first mipmap need to have alignment */
+        if ((i == 0)) {
+            offset = ALIGN(offset, surf->bo_alignment);
+        }
+    }
+    surf->bo_size = offset;
+    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->width > 8192 || surf->height > 8192 || surf->depth > 8192) {
+        return -EINVAL;
+    }
+
+    /* zbuffer must be tiled */
+    if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
+        if (mode != RADEON_SURF_MODE_2D) {
+            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;
+}
+
+
+/* ===========================================================================
+ * 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 unsigned eg_adjust_bankh(unsigned group_bytes,
+                                unsigned tileb,
+                                unsigned bankw, unsigned bankh)
+{
+    for (; bankh <= 8; bankh *= 2) {
+        if ((tileb * bankw * bankh) >= group_bytes) {
+            return bankh;
+        }
+    }
+    return 0;
+}
+
+static unsigned eg_adjust_tilea(unsigned group_bytes,
+                                unsigned num_pipes,
+                                unsigned tileb,
+                                unsigned tilea,
+                                unsigned bankw)
+{
+    for (; tilea <= 8; tilea *= 2) {
+        if ((tileb * bankw * tilea * num_pipes) >= group_bytes) {
+            return tilea;
+        }
+    }
+    return 0;
+}
+
+static int eg_surface_init_2d(struct radeon_surface_manager *surf_man,
+                              struct radeon_surface *surf,
+                              uint64_t offset, unsigned start_level)
+{
+    uint32_t wa, ha, da, w, h, d, walign, halign, dalign, bankw, bankh;
+    uint32_t tilew, tileh, tileb, tilea, slices_per_tile;
+    unsigned i, type, slice_bytes;
+    unsigned macro_tile_bytes, macro_tiles_per_row, macro_tiles_per_slice;
+
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+    /* check thin factor */
+    switch (surf->thin_factor) {
+    case 0:
+    case 1:
+        surf->thin_factor = 1;
+        break;
+    default:
+        return -EINVAL;
+    }
+    /* check tile thickness */
+    switch (surf->tile_thickness) {
+    case 0:
+    case 1:
+        surf->tile_thickness = 1;
+        dalign = 1;
+        break;
+    case 4:
+        if (type != RADEON_SURF_TYPE_3D) {
+            /* don't think it's forbidden but it's useless so refuse it */
+            return -EINVAL;
+        }
+        dalign = 4;
+        break;
+    default:
+        return -EINVAL;
+    }
+    /* check aspect ratio */
+    if (surf->macro_tile_aspect > surf_man->hw_info.num_banks) {
+        /* as num_banks/2 <= 8 which is the max tile aspect ratio */
+        surf->macro_tile_aspect = surf_man->hw_info.num_banks / 2;
+    }
+    switch (surf->macro_tile_aspect) {
+    case 0:
+    case 1:
+        surf->macro_tile_aspect = 1;
+        break;
+    case 2:
+    case 4:
+    case 8:
+        break;
+    default:
+        return -EINVAL;
+    }
+    /* check bank width */
+    switch (surf->bank_width) {
+    case 0:
+    case 1:
+        surf->bank_width = 1;
+        break;
+    case 2:
+    case 4:
+    case 8:
+        break;
+    default:
+        return -EINVAL;
+    }
+    /* check bank height */
+    switch (surf->bank_height) {
+    case 0:
+    case 1:
+        surf->bank_height = 1;
+        break;
+    case 2:
+    case 4:
+    case 8:
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    /* compute alignment */
+    tilew = 8;
+    tileh = 8;
+    tilea = surf->macro_tile_aspect;
+    bankw = surf->bank_width;
+    bankh = surf->bank_height;
+    tileb = tilew * tileh * surf->element_bytes * surf->nsamples;
+    slices_per_tile = 1;
+    if (tileb > surf->tile_split) {
+        slices_per_tile = tileb / surf->tile_split;
+    }
+    tileb = MIN2(surf->tile_split, tileb);
+
+    bankh = eg_adjust_bankh(surf_man->hw_info.group_bytes,
+                            tileb, bankw, bankh);
+    if (!bankh) {
+        surf->level[start_level].mode = RADEON_SURF_MODE_1D;
+        return r6_surface_init_1d(surf_man, surf, offset, start_level);
+    }
+    tilea = eg_adjust_tilea(surf_man->hw_info.group_bytes,
+                            surf_man->hw_info.num_pipes,
+                            tileb, tilea, bankw);
+    /* should we lower the aspect ratio when tilea > num_banks ?? */
+    if (!tilea || tilea > surf_man->hw_info.num_banks) {
+        surf->level[start_level].mode = RADEON_SURF_MODE_1D;
+        return r6_surface_init_1d(surf_man, surf, offset, start_level);
+    }
+
+    surf->macro_tile_aspect = tilea;
+    surf->bank_height = bankh;
+
+    walign = surf_man->hw_info.num_pipes * bankw * tilew * tilea;
+    halign = (surf_man->hw_info.num_banks * bankh * tileh) / tilea;
+    /* macro tile value needed for layer computation */
+    macro_tile_bytes = (walign / tilew) * (halign / tileh) * tileb;
+    if (!start_level) {
+        surf->bo_alignment = MAX2(256, macro_tile_bytes);
+    }
+
+    /* build mipmap tree */
+    for (i = start_level; i <= surf->last_level; i++) {
+        surf_minify(surf, i, walign, halign, dalign, &w, &h, &d, &wa, &ha, &da);
+        if (w < walign || h < halign) {
+            surf->level[i].mode = RADEON_SURF_MODE_1D;
+            return r6_surface_init_1d(surf_man, surf, offset, i);
+        }
+        macro_tiles_per_row = wa / walign;
+        macro_tiles_per_slice = macro_tiles_per_row * (ha / halign);
+        slice_bytes = macro_tiles_per_slice * macro_tile_bytes;
+        surf->level[i].offset = offset;
+        surf->level[i].width = w;
+        surf->level[i].height = h;
+        surf->level[i].depth = d;
+        surf->level[i].height_aligned = ha;
+        surf->level[i].pitch = wa;
+        surf->level[i].pitch_bytes = wa * surf->element_bytes;
+        surf->level[i].layer_size = slice_bytes * slices_per_tile;
+        surf->level[i].mode = RADEON_SURF_MODE_2D;
+        /* compute next offset */
+        if (type == RADEON_SURF_TYPE_CUBEMAP) {
+            offset += surf->level[i].layer_size * da * 8;
+        } else {
+            offset += surf->level[i].layer_size * da;
+        }
+        /* level0 and first mipmap need to have alignment */
+        if ((i == 0)) {
+            offset = ALIGN(offset, surf->bo_alignment);
+        }
+    }
+    surf->bo_size = offset;
+    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;
+
+    /* check surface dimension */
+    if (surf->width > 16384 || surf->height > 16384 || surf->depth > 16384) {
+        return -EINVAL;
+    }
+
+    /* zbuffer must be tiled */
+    if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) {
+        if (mode != RADEON_SURF_MODE_2D) {
+            return -EINVAL;
+        }
+    }
+
+    /* check mipmap last_level */
+    if (surf->last_level > 15) {
+        return -EINVAL;
+    }
+
+    /* check thin factor */
+    switch (surf->thin_factor) {
+    case 0:
+    case 1:
+        surf->thin_factor = 1;
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    /* check tile split */
+    switch (surf->tile_split) {
+    case 0:
+        /* use row size so we match kernel ... i hate this */
+        switch (surf_man->hw_info.row_size) {
+        default:
+        case 1024:
+            surf->tile_split = 1024;
+            break;
+        case 2048:
+            surf->tile_split = 2048;
+            break;
+        case 4096:
+            surf->tile_split = 4096;
+            break;
+        }
+        break;
+    case 64:
+    case 128:
+    case 256:
+    case 512:
+    case 1024:
+    case 2048:
+    case 4096:
+        break;
+    default:
+        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;
+    }
+
+    /* 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 = eg_surface_init_2d(surf_man, surf, 0, 0);
+        break;
+    default:
+        return -EINVAL;
+    }
+    return r;
+}
+
+
+/* ===========================================================================
+ * 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;
+    } else {
+        if (eg_init_hw_info(surf_man)) {
+            goto out_err;
+        }
+        surf_man->surface_init = &eg_surface_init;
+    }
+
+    return surf_man;
+out_err:
+    free(surf_man);
+    return NULL;
+}
+
+void radeon_surface_manager_free(struct radeon_surface_manager *surf_man)
+{
+    free(surf_man);
+}
+
+int radeon_surface_init(struct radeon_surface_manager *surf_man,
+                        struct radeon_surface *surf)
+{
+    unsigned type;
+
+    if (surf_man == NULL || surf_man->surface_init == NULL || surf == NULL) {
+        return -EINVAL;
+    }
+    /* all dimension must be at least 1 ! */
+    if (!surf->width || !surf->height || !surf->depth) {
+        return -EINVAL;
+    }
+    switch (surf->nsamples) {
+    case 1:
+    case 2:
+    case 4:
+    case 8:
+        break;
+    default:
+        return -EINVAL;
+    }
+    /* check type */
+    type = RADEON_SURF_GET(surf->flags, TYPE);
+    switch (type) {
+    case RADEON_SURF_TYPE_1D:
+        if (surf->height > 1) {
+            return -EINVAL;
+        }
+    case RADEON_SURF_TYPE_2D:
+    case RADEON_SURF_TYPE_CUBEMAP:
+        if (surf->depth > 1) {
+            return -EINVAL;
+        }
+    case RADEON_SURF_TYPE_3D:
+        break;
+    case RADEON_SURF_TYPE_1D_ARRAY:
+        if (surf->height > 1) {
+            return -EINVAL;
+        }
+    case RADEON_SURF_TYPE_2D_ARRAY:
+        break;
+    default:
+        return -EINVAL;
+    }
+    return surf_man->surface_init(surf_man, surf);
+}
diff --git a/radeon/radeon_surface.h b/radeon/radeon_surface.h
new file mode 100644
index 0000000..de4bd76
--- /dev/null
+++ b/radeon/radeon_surface.h
@@ -0,0 +1,108 @@
+/*
+ * 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 at 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                    layer_size;
+    uint32_t                    width;
+    uint32_t                    height;
+    uint32_t                    height_aligned;
+    uint32_t                    depth;
+    uint32_t                    pitch;
+    uint32_t                    pitch_bytes;
+    uint32_t                    mode;
+};
+
+struct radeon_surface {
+    uint32_t                    width;
+    uint32_t                    height;
+    uint32_t                    depth;
+    uint32_t                    last_level;
+    uint32_t                    element_bytes;
+    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 bank_width/height on evergreen for
+     * instance).
+     */
+    uint64_t                    bo_size;
+    uint64_t                    bo_alignment;
+    /* apply to r6,eg */
+    uint32_t                    tile_thickness;
+    uint32_t                    thin_factor;
+    /* apply to eg */
+    uint32_t                    bank_width;
+    uint32_t                    bank_height;
+    uint32_t                    macro_tile_aspect;
+    uint32_t                    tile_split;
+    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);
+
+#endif
-- 
1.7.7.1


--IJpNTDwzlM2Ie8A6--


More information about the mesa-dev mailing list