From 2ec32d4f949f04d0006fff50065c904626c2e581 Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Sun, 12 Jun 2011 16:21:30 +0800 Subject: initial commit --- gralloc_drm_radeon.c | 366 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 gralloc_drm_radeon.c (limited to 'gralloc_drm_radeon.c') diff --git a/gralloc_drm_radeon.c b/gralloc_drm_radeon.c new file mode 100644 index 0000000..59fb782 --- /dev/null +++ b/gralloc_drm_radeon.c @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2010-2011 Chia-I Wu + * Copyright (C) 2010-2011 LunarG Inc. + * + * Based on xf86-video-ati, which has + * + * Copyright © 2009 Red Hat, 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 AUTHORS OR COPYRIGHT HOLDERS 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. + */ + +/* XXX This driver assumes evergreen. */ + +#define LOG_TAG "GRALLOC-RADEON" + +#include +#include +#include +#include +#include +#include +#include + +#include "gralloc_drm.h" +#include "gralloc_drm_priv.h" + +#define RADEON_GPU_PAGE_SIZE 4096 + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1)) + +struct radeon_info { + struct gralloc_drm_drv_t base; + + int fd; + struct radeon_bo_manager *bufmgr; + + uint32_t tile_config; + int num_channels; + int num_banks; + int group_bytes; + /* r6xx+ tile config */ + int have_tiling_info; + int allow_color_tiling; +}; + +struct radeon_buffer { + struct gralloc_drm_bo_t base; + + struct radeon_bo *rbo; +}; + +static int eg_init_tile_config(struct radeon_info *info) +{ + struct drm_radeon_info ginfo; + uint32_t val; + int ret; + + memset(&ginfo, 0, sizeof(ginfo)); + ginfo.request = RADEON_INFO_TILING_CONFIG; + ginfo.value = (long) &val; + ret = drmCommandWriteRead(info->fd, DRM_RADEON_INFO, + &ginfo, sizeof(ginfo)); + if (ret) + return ret; + + info->tile_config = val; + + switch (info->tile_config & 0xf) { + case 0: + info->num_channels = 1; + break; + case 1: + info->num_channels = 2; + break; + case 2: + info->num_channels = 4; + break; + case 3: + info->num_channels = 8; + break; + default: + return -EINVAL; + break; + } + + info->num_banks = (info->tile_config & 0xf0) >> 4; + + switch ((info->tile_config & 0xf00) >> 8) { + case 0: + info->group_bytes = 256; + break; + case 1: + info->group_bytes = 512; + break; + default: + return -EINVAL; + break; + } + + info->have_tiling_info = 1; + info->allow_color_tiling = 0; + + return 0; +} + +/* returns pitch alignment in pixels */ +static int eg_get_pitch_align(struct radeon_info *info, int bpe, uint32_t tiling) +{ + int pitch_align = 1; + + if (tiling & RADEON_TILING_MACRO) { + /* general surface requirements */ + pitch_align = (((info->group_bytes / 8) / bpe) * + info->num_banks) * 8; + /* further restrictions for scanout */ + pitch_align = MAX(info->num_banks * 8, pitch_align); + } else if (tiling & RADEON_TILING_MICRO) { + /* general surface requirements */ + pitch_align = MAX(8, (info->group_bytes / (8 * bpe))); + /* further restrictions for scanout */ + pitch_align = MAX(info->group_bytes / bpe, pitch_align); + } else { + if (info->have_tiling_info) + /* linear aligned requirements */ + pitch_align = MAX(64, info->group_bytes / bpe); + else + /* default to 512 elements if we don't know the real + * group size otherwise the kernel may reject the CS + * if the group sizes don't match as the pitch won't + * be aligned properly. + */ + pitch_align = 512; + } + + return pitch_align; +} + +/* returns height alignment in pixels */ +static int eg_get_height_align(struct radeon_info *info, uint32_t tiling) +{ + int height_align = 1; + + if (tiling & RADEON_TILING_MACRO) + height_align = info->num_channels * 8; + else if (tiling & RADEON_TILING_MICRO) + height_align = 8; + else + height_align = 8; + + return height_align; +} + +/* returns base alignment in bytes */ +static int eg_get_base_align(struct radeon_info *info, + int bpe, uint32_t tiling) +{ + int pixel_align = eg_get_pitch_align(info, bpe, tiling); + int height_align = eg_get_height_align(info, tiling); + int base_align = RADEON_GPU_PAGE_SIZE; + + if (tiling & RADEON_TILING_MACRO) { + base_align = + MAX(info->num_banks * info->num_channels * 8 * 8 * bpe, + pixel_align * bpe * height_align); + } + else { + if (info->have_tiling_info) + base_align = info->group_bytes; + else + /* default to 512 if we don't know the real + * group size otherwise the kernel may reject the CS + * if the group sizes don't match as the base won't + * be aligned properly. + */ + base_align = 512; + } + + return base_align; +} + +static uint32_t drm_gem_get_tiling(const struct gralloc_drm_handle_t *handle) +{ + return 0; +} + +static struct gralloc_drm_bo_t * +drm_gem_radeon_alloc(struct gralloc_drm_drv_t *drv, struct gralloc_drm_handle_t *handle) +{ + struct radeon_info *info = (struct radeon_info *) drv; + struct radeon_buffer *rbuf; + uint32_t tiling, domain; + int cpp; + + tiling = drm_gem_get_tiling(handle); + domain = RADEON_GEM_DOMAIN_VRAM; + cpp = gralloc_drm_get_bpp(handle->format); + if (!cpp) { + LOGE("unrecognized format 0x%x", handle->format); + return NULL; + } + + rbuf = calloc(1, sizeof(*rbuf)); + if (!rbuf) + return NULL; + + + if (handle->name) { + rbuf->rbo = radeon_bo_open(info->bufmgr, handle->name, + 0, 0, domain, 0); + if (!rbuf->rbo) { + LOGE("failed to create rbo from name %u", + handle->name); + free(rbuf); + return NULL; + } + } + else { + int aligned_width, aligned_height; + int pitch, size, base_align; + + if (handle->usage & (GRALLOC_USAGE_HW_FB | + GRALLOC_USAGE_HW_TEXTURE)) { + aligned_width = ALIGN(handle->width, + eg_get_pitch_align(info, cpp, tiling)); + aligned_height = ALIGN(handle->height, + eg_get_height_align(info, tiling)); + } + else { + aligned_width = handle->width; + aligned_height = handle->height; + } + + if (!(handle->usage & (GRALLOC_USAGE_HW_FB | + GRALLOC_USAGE_HW_RENDER)) && + (handle->usage & GRALLOC_USAGE_SW_READ_OFTEN)) + domain = RADEON_GEM_DOMAIN_GTT; + + pitch = aligned_width * cpp; + size = ALIGN(aligned_height * pitch, RADEON_GPU_PAGE_SIZE); + base_align = eg_get_base_align(info, cpp, tiling); + + rbuf->rbo = radeon_bo_open(info->bufmgr, 0, + size, base_align, domain, 0); + if (!rbuf->rbo) { + LOGE("failed to allocate rbo %dx%dx%d", + handle->width, handle->height, cpp); + free(rbuf); + return NULL; + } + + if (tiling) + radeon_bo_set_tiling(rbuf->rbo, tiling, pitch); + + if (radeon_gem_get_kernel_name(rbuf->rbo, + (uint32_t *) &handle->name)) { + LOGE("failed to flink rbo"); + radeon_bo_unref(rbuf->rbo); + free(rbuf); + return NULL; + } + + handle->stride = pitch; + } + + if (handle->usage & GRALLOC_USAGE_HW_FB) + rbuf->base.fb_handle = rbuf->rbo->handle; + + rbuf->base.handle = handle; + + return &rbuf->base; +} + +static void drm_gem_radeon_free(struct gralloc_drm_drv_t *drv, + struct gralloc_drm_bo_t *bo) +{ + struct radeon_buffer *rbuf = (struct radeon_buffer *) bo; + radeon_bo_unref(rbuf->rbo); +} + +static int drm_gem_radeon_map(struct gralloc_drm_drv_t *drv, + struct gralloc_drm_bo_t *bo, int x, int y, int w, int h, + int enable_write, void **addr) +{ + struct radeon_buffer *rbuf = (struct radeon_buffer *) bo; + int err; + + err = radeon_bo_map(rbuf->rbo, enable_write); + if (!err) + *addr = rbuf->rbo->ptr; + + return err; +} + +static void drm_gem_radeon_unmap(struct gralloc_drm_drv_t *drv, + struct gralloc_drm_bo_t *bo) +{ + struct radeon_buffer *rbuf = (struct radeon_buffer *) bo; + radeon_bo_unmap(rbuf->rbo); +} + +static void drm_gem_radeon_init_kms_features(struct gralloc_drm_drv_t *drv, + struct gralloc_drm_t *drm) +{ + drm->mode_dirty_fb = 0; + drm->swap_mode = DRM_SWAP_FLIP; + drm->mode_sync_flip = 1; + drm->swap_interval = 1; + drm->vblank_secondary = 0; +} + +static void drm_gem_radeon_destroy(struct gralloc_drm_drv_t *drv) +{ + struct radeon_info *info = (struct radeon_info *) drv; + + radeon_bo_manager_gem_dtor(info->bufmgr); + free(info); +} + +struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_radeon(int fd) +{ + struct radeon_info *info; + + info = calloc(1, sizeof(*info)); + if (!info) + return NULL; + + info->fd = fd; + info->bufmgr = radeon_bo_manager_gem_ctor(info->fd); + if (!info->bufmgr) { + LOGE("failed to create buffer manager"); + free(info); + return NULL; + } + + if (eg_init_tile_config(info)) { + radeon_bo_manager_gem_dtor(info->bufmgr); + free(info); + return NULL; + } + + info->base.destroy = drm_gem_radeon_destroy; + info->base.init_kms_features = drm_gem_radeon_init_kms_features; + info->base.alloc = drm_gem_radeon_alloc; + info->base.free = drm_gem_radeon_free; + info->base.map = drm_gem_radeon_map; + info->base.unmap = drm_gem_radeon_unmap; + + return &info->base; +} -- cgit v1.1