[PATCH 1/3] EXA: Factor out pixmap BO allocation into a helper function.

Michel Dänzer michel at daenzer.net
Tue Jul 10 04:03:09 PDT 2012


From: Michel Dänzer <michel.daenzer at amd.com>


Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/Makefile.am        |    4 +-
 src/radeon.h           |   20 ++++++
 src/radeon_bo_helper.c |  177 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/radeon_bo_helper.h |   31 +++++++++
 src/radeon_exa.c       |  160 ++-----------------------------------------
 5 files changed, 237 insertions(+), 155 deletions(-)
 create mode 100644 src/radeon_bo_helper.c
 create mode 100644 src/radeon_bo_helper.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 5c09554..e857f21 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,7 +28,8 @@
 
 radeon_drv_la_LIBADD = $(LIBDRM_RADEON_LIBS)
 
-RADEON_KMS_SRCS=radeon_dri2.c radeon_kms.c drmmode_display.c radeon_vbo.c
+RADEON_KMS_SRCS=radeon_dri2.c radeon_kms.c drmmode_display.c radeon_vbo.c \
+	radeon_bo_helper.c
 
 RADEON_EXA_SOURCES = radeon_exa.c r600_exa.c r6xx_accel.c r600_textured_videofuncs.c r600_shader.c radeon_exa_shared.c \
 	evergreen_exa.c evergreen_accel.c evergreen_shader.c evergreen_textured_videofuncs.c cayman_accel.c cayman_shader.c
@@ -82,6 +83,7 @@ EXTRA_DIST = \
 	ati.h \
 	ativersion.h \
 	bicubic_table.h \
+	radeon_bo_helper.h \
 	radeon_drm.h \
 	radeon_exa_render.c \
 	radeon_exa_funcs.c \
diff --git a/src/radeon.h b/src/radeon.h
index 742a6f8..d357dc1 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -665,4 +665,24 @@ enum {
     RADEON_CREATE_PIXMAP_SZBUFFER = 0x80000000, /* for eg */
 };
 
+
+/* Compute log base 2 of val. */
+static __inline__ int
+RADEONLog2(int val)
+{
+	int bits;
+#if (defined __i386__ || defined __x86_64__) && (defined __GNUC__)
+	__asm volatile("bsrl	%1, %0"
+		: "=r" (bits)
+		: "c" (val)
+	);
+	return bits;
+#else
+	for (bits = 0; val != 0; val >>= 1, ++bits)
+		;
+	return bits - 1;
+#endif
+}
+
+
 #endif /* _RADEON_H_ */
diff --git a/src/radeon_bo_helper.c b/src/radeon_bo_helper.c
new file mode 100644
index 0000000..ccdf7eb
--- /dev/null
+++ b/src/radeon_bo_helper.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2012  Advanced Micro Devices, Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "radeon.h"
+
+
+static const unsigned MicroBlockTable[5][3][2] = {
+    /*linear  tiled   square-tiled */
+    {{32, 1}, {8, 4}, {0, 0}}, /*   8 bits per pixel */
+    {{16, 1}, {8, 2}, {4, 4}}, /*  16 bits per pixel */
+    {{ 8, 1}, {4, 2}, {0, 0}}, /*  32 bits per pixel */
+    {{ 4, 1}, {0, 0}, {2, 2}}, /*  64 bits per pixel */
+    {{ 2, 1}, {0, 0}, {0, 0}}  /* 128 bits per pixel */
+};
+
+/* Return true if macrotiling can be enabled */
+static Bool RADEONMacroSwitch(int width, int height, int bpp,
+                              uint32_t flags, Bool rv350_mode)
+{
+    unsigned tilew, tileh, microtiled, logbpp;
+
+    logbpp = RADEONLog2(bpp / 8);
+    if (logbpp > 4)
+        return 0;
+
+    microtiled = !!(flags & RADEON_TILING_MICRO);
+    tilew = MicroBlockTable[logbpp][microtiled][0] * 8;
+    tileh = MicroBlockTable[logbpp][microtiled][1] * 8;
+
+    /* See TX_FILTER1_n.MACRO_SWITCH. */
+    if (rv350_mode) {
+        return width >= tilew && height >= tileh;
+    } else {
+        return width > tilew && height > tileh;
+    }
+}
+
+/* Calculate appropriate tiling and pitch for a pixmap and allocate a BO that
+ * can hold it.
+ */
+struct radeon_bo*
+radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth,
+		       int usage_hint, int bitsPerPixel, int *new_pitch,
+		       struct radeon_surface *new_surface, uint32_t *new_tiling)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    int pitch, base_align;
+    uint32_t size, heighta;
+    int cpp = bitsPerPixel / 8;
+    uint32_t tiling = 0;
+    struct radeon_surface surface;
+    struct radeon_bo *bo;
+
+    if (usage_hint) {
+	if (info->allowColorTiling) {
+	    if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MACRO)
+		tiling |= RADEON_TILING_MACRO;
+	    if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MICRO)
+                tiling |= RADEON_TILING_MICRO;
+	}
+	if (usage_hint & RADEON_CREATE_PIXMAP_DEPTH)
+		tiling |= RADEON_TILING_MACRO | RADEON_TILING_MICRO;
+
+    }
+
+    /* Small pixmaps must not be macrotiled on R300, hw cannot sample them
+     * correctly because samplers automatically switch to macrolinear. */
+    if (info->ChipFamily >= CHIP_FAMILY_R300 &&
+        info->ChipFamily <= CHIP_FAMILY_RS740 &&
+        (tiling & RADEON_TILING_MACRO) &&
+        !RADEONMacroSwitch(width, height, bitsPerPixel, tiling,
+                           info->ChipFamily >= CHIP_FAMILY_RV350)) {
+        tiling &= ~RADEON_TILING_MACRO;
+    }
+
+    heighta = RADEON_ALIGN(height, drmmode_get_height_align(pScrn, tiling));
+    pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, cpp, tiling)) * cpp;
+    base_align = drmmode_get_base_align(pScrn, cpp, tiling);
+    size = RADEON_ALIGN(heighta * pitch, RADEON_GPU_PAGE_SIZE);
+    memset(&surface, 0, sizeof(struct radeon_surface));
+
+    if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) {
+		if (width) {
+			surface.npix_x = width;
+			/* need to align height to 8 for old kernel */
+			surface.npix_y = RADEON_ALIGN(height, 8);
+			surface.npix_z = 1;
+			surface.blk_w = 1;
+			surface.blk_h = 1;
+			surface.blk_d = 1;
+			surface.array_size = 1;
+			surface.last_level = 0;
+			surface.bpe = cpp;
+			surface.nsamples = 1;
+			if (height < 64) {
+				/* disable 2d tiling for small surface to work around
+				 * the fact that ddx align height to 8 pixel for old
+				 * obscure reason i can't remember
+				 */
+				tiling &= ~RADEON_TILING_MACRO;
+			}
+			surface.flags = RADEON_SURF_SCANOUT;
+			surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
+			surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE);
+			if ((tiling & RADEON_TILING_MICRO)) {
+				surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
+				surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
+			}
+			if ((tiling & RADEON_TILING_MACRO)) {
+				surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
+				surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
+			}
+			if (usage_hint & RADEON_CREATE_PIXMAP_SZBUFFER) {
+				surface.flags |= RADEON_SURF_ZBUFFER;
+				surface.flags |= RADEON_SURF_SBUFFER;
+			}
+			if (radeon_surface_best(info->surf_man, &surface)) {
+				return NULL;
+			}
+			if (radeon_surface_init(info->surf_man, &surface)) {
+				return NULL;
+			}
+			size = surface.bo_size;
+			base_align = surface.bo_alignment;
+			pitch = surface.level[0].pitch_bytes;
+			tiling = 0;
+			switch (surface.level[0].mode) {
+			case RADEON_SURF_MODE_2D:
+				tiling |= RADEON_TILING_MACRO;
+				tiling |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT;
+				tiling |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT;
+				tiling |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT;
+				tiling |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT;
+				tiling |= eg_tile_split(surface.stencil_tile_split) << RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT;
+				break;
+			case RADEON_SURF_MODE_1D:
+				tiling |= RADEON_TILING_MICRO;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+
+    bo = radeon_bo_open(info->bufmgr, 0, size, base_align,
+			RADEON_GEM_DOMAIN_VRAM, 0);
+
+    if (bo && tiling && radeon_bo_set_tiling(bo, tiling, pitch) == 0)
+	*new_tiling = tiling;
+
+    *new_surface = surface;
+    *new_pitch = pitch;
+    return bo;
+}
diff --git a/src/radeon_bo_helper.h b/src/radeon_bo_helper.h
new file mode 100644
index 0000000..0f6fffb
--- /dev/null
+++ b/src/radeon_bo_helper.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012  Advanced Micro Devices, Inc.
+ *
+ * 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, sublicense,
+ * 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 above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ */
+
+#ifndef RADEON_BO_HELPER_H
+#define RADEON_BO_HELPER_H 1
+
+extern struct radeon_bo*
+radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth,
+		       int usage_hint, int bitsPerPixel, int *new_pitch,
+		       struct radeon_surface *new_surface, uint32_t *new_tiling);
+
+#endif /* RADEON_BO_HELPER_H */
diff --git a/src/radeon_exa.c b/src/radeon_exa.c
index 99dc453..d80c7e4 100644
--- a/src/radeon_exa.c
+++ b/src/radeon_exa.c
@@ -37,6 +37,7 @@
 #include "radeon_reg.h"
 #include "r600_reg.h"
 #include "radeon_drm.h"
+#include "radeon_bo_helper.h"
 #include "radeon_probe.h"
 #include "radeon_version.h"
 #include "radeon_exa_shared.h"
@@ -70,24 +71,6 @@ static struct {
     { RADEON_ROP3_ONE,  RADEON_ROP3_ONE  }  /* GXset          */
 };
 
-/* Compute log base 2 of val. */
-static __inline__ int
-RADEONLog2(int val)
-{
-	int bits;
-#if (defined __i386__ || defined __x86_64__) && (defined __GNUC__)
-	__asm volatile("bsrl	%1, %0"
-		: "=r" (bits)
-		: "c" (val)
-	);
-	return bits;
-#else
-	for (bits = 0; val != 0; val >>= 1, ++bits)
-		;
-	return bits - 1;
-#endif
-}
-
 static __inline__ uint32_t F_TO_DW(float val)
 {
     union {
@@ -292,37 +275,6 @@ void *RADEONEXACreatePixmap(ScreenPtr pScreen, int size, int align)
 
 }
 
-static const unsigned MicroBlockTable[5][3][2] = {
-    /*linear  tiled   square-tiled */
-    {{32, 1}, {8, 4}, {0, 0}}, /*   8 bits per pixel */
-    {{16, 1}, {8, 2}, {4, 4}}, /*  16 bits per pixel */
-    {{ 8, 1}, {4, 2}, {0, 0}}, /*  32 bits per pixel */
-    {{ 4, 1}, {0, 0}, {2, 2}}, /*  64 bits per pixel */
-    {{ 2, 1}, {0, 0}, {0, 0}}  /* 128 bits per pixel */
-};
-
-/* Return true if macrotiling can be enabled */
-static Bool RADEONMacroSwitch(int width, int height, int bpp,
-                              uint32_t flags, Bool rv350_mode)
-{
-    unsigned tilew, tileh, microtiled, logbpp;
-
-    logbpp = RADEONLog2(bpp / 8);
-    if (logbpp > 4)
-        return 0;
-
-    microtiled = !!(flags & RADEON_TILING_MICRO);
-    tilew = MicroBlockTable[logbpp][microtiled][0] * 8;
-    tileh = MicroBlockTable[logbpp][microtiled][1] * 8;
-
-    /* See TX_FILTER1_n.MACRO_SWITCH. */
-    if (rv350_mode) {
-        return width >= tilew && height >= tileh;
-    } else {
-        return width > tilew && height > tileh;
-    }
-}
-
 void *RADEONEXACreatePixmap2(ScreenPtr pScreen, int width, int height,
 			     int depth, int usage_hint, int bitsPerPixel,
 			     int *new_pitch)
@@ -330,11 +282,6 @@ void *RADEONEXACreatePixmap2(ScreenPtr pScreen, int width, int height,
     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
     RADEONInfoPtr info = RADEONPTR(pScrn);
     struct radeon_exa_pixmap_priv *new_priv;
-    int pitch, base_align;
-    uint32_t size, heighta;
-    uint32_t tiling = 0;
-    int cpp = bitsPerPixel / 8;
-    struct radeon_surface surface;
 
 #ifdef EXA_MIXED_PIXMAPS
     if (info->accel_state->exa->flags & EXA_MIXED_PIXMAPS) {
@@ -344,120 +291,25 @@ void *RADEONEXACreatePixmap2(ScreenPtr pScreen, int width, int height,
     }
 #endif
 
-    if (usage_hint) {
-	if (info->allowColorTiling) {
-    	    if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MACRO)
- 	   	tiling |= RADEON_TILING_MACRO;
-    	    if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MICRO)
-                tiling |= RADEON_TILING_MICRO;
-	}
-	if (usage_hint & RADEON_CREATE_PIXMAP_DEPTH)
- 	   	tiling |= RADEON_TILING_MACRO | RADEON_TILING_MICRO;
-		
-    }
-
-    /* Small pixmaps must not be macrotiled on R300, hw cannot sample them
-     * correctly because samplers automatically switch to macrolinear. */
-    if (info->ChipFamily >= CHIP_FAMILY_R300 &&
-        info->ChipFamily <= CHIP_FAMILY_RS740 &&
-        (tiling & RADEON_TILING_MACRO) &&
-        !RADEONMacroSwitch(width, height, bitsPerPixel, tiling,
-                           info->ChipFamily >= CHIP_FAMILY_RV350)) {
-        tiling &= ~RADEON_TILING_MACRO;
-    }
-
-    heighta = RADEON_ALIGN(height, drmmode_get_height_align(pScrn, tiling));
-    pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, cpp, tiling)) * cpp;
-    base_align = drmmode_get_base_align(pScrn, cpp, tiling);
-    size = RADEON_ALIGN(heighta * pitch, RADEON_GPU_PAGE_SIZE);
-    memset(&surface, 0, sizeof(struct radeon_surface));
-
-    if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) {
-		if (width) {
-			surface.npix_x = width;
-			/* need to align height to 8 for old kernel */
-			surface.npix_y = RADEON_ALIGN(height, 8);
-			surface.npix_z = 1;
-			surface.blk_w = 1;
-			surface.blk_h = 1;
-			surface.blk_d = 1;
-			surface.array_size = 1;
-			surface.last_level = 0;
-			surface.bpe = cpp;
-			surface.nsamples = 1;
-			if (height < 64) {
-				/* disable 2d tiling for small surface to work around
-				 * the fact that ddx align height to 8 pixel for old
-				 * obscure reason i can't remember
-				 */
-				tiling &= ~RADEON_TILING_MACRO;
-			}
-			surface.flags = RADEON_SURF_SCANOUT;
-			surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
-			surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE);
-			if ((tiling & RADEON_TILING_MICRO)) {
-				surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
-				surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
-			}
-			if ((tiling & RADEON_TILING_MACRO)) {
-				surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
-				surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
-			}
-			if (usage_hint & RADEON_CREATE_PIXMAP_SZBUFFER) {
-				surface.flags |= RADEON_SURF_ZBUFFER;
-				surface.flags |= RADEON_SURF_SBUFFER;
-			}
-			if (radeon_surface_best(info->surf_man, &surface)) {
-				return NULL;
-			}
-			if (radeon_surface_init(info->surf_man, &surface)) {
-				return NULL;
-			}
-			size = surface.bo_size;
-			base_align = surface.bo_alignment;
-			pitch = surface.level[0].pitch_bytes;
-			tiling = 0;
-			switch (surface.level[0].mode) {
-			case RADEON_SURF_MODE_2D:
-				tiling |= RADEON_TILING_MACRO;
-				tiling |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT;
-				tiling |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT;
-				tiling |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT;
-				tiling |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT;
-				tiling |= eg_tile_split(surface.stencil_tile_split) << RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT;
-				break;
-			case RADEON_SURF_MODE_1D:
-				tiling |= RADEON_TILING_MICRO;
-				break;
-			default:
-				break;
-			}
-		}
-	}
-
     new_priv = calloc(1, sizeof(struct radeon_exa_pixmap_priv));
     if (!new_priv) {
 	return NULL;
     }
 
-    if (size == 0) {
+    if (width == 0 || height == 0) {
 	return new_priv;
     }
 
-    *new_pitch = pitch;
-
-    new_priv->bo = radeon_bo_open(info->bufmgr, 0, size, base_align,
-				  RADEON_GEM_DOMAIN_VRAM, 0);
+    new_priv->bo = radeon_alloc_pixmap_bo(pScrn, width, height, depth,
+					  usage_hint, bitsPerPixel, new_pitch,
+					  &new_priv->surface,
+					  &new_priv->tiling_flags);
     if (!new_priv->bo) {
 	free(new_priv);
 	ErrorF("Failed to alloc memory\n");
 	return NULL;
     }
 
-    if (tiling && !radeon_bo_set_tiling(new_priv->bo, tiling, *new_pitch))
-	new_priv->tiling_flags = tiling;
-
-    new_priv->surface = surface;
     return new_priv;
 }
 
-- 
1.7.10.4




More information about the xorg-driver-ati mailing list