[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