diff options
author | Michel Dänzer <michel.daenzer@amd.com> | 2012-06-27 14:48:47 +0200 |
---|---|---|
committer | Michel Dänzer <michel@daenzer.net> | 2012-07-05 19:58:39 +0200 |
commit | 9eac8021f3d33a63156f9f5d43a220e88bb3f8db (patch) | |
tree | f7061124c079b8c48c8832278b33d97bdde39899 | |
parent | 060c7836e7f7777bacca4e23f57c5985beab33bc (diff) |
EXA: Factor out pixmap BO allocation into a helper function.
Signed-off-by: Michel Dänzer <michel.daenzer@amd.com>
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/radeon.h | 20 | ||||
-rw-r--r-- | src/radeon_bo_helper.c | 177 | ||||
-rw-r--r-- | src/radeon_bo_helper.h | 31 | ||||
-rw-r--r-- | src/radeon_exa.c | 160 |
5 files changed, 237 insertions, 155 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 5c095546..e857f21a 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 742a6f85..d357dc13 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 00000000..ccdf7ebe --- /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 00000000..0f6fffbd --- /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 99dc453b..d80c7e4f 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; } |