diff options
Diffstat (limited to 'src/gralloc')
-rw-r--r-- | src/gralloc/Android.mk | 71 | ||||
-rw-r--r-- | src/gralloc/gralloc_gem.c | 67 | ||||
-rw-r--r-- | src/gralloc/gralloc_gem.h | 52 | ||||
-rw-r--r-- | src/gralloc/gralloc_gem_intel.c (renamed from src/gralloc/gralloc_gem_i915.c) | 52 | ||||
-rw-r--r-- | src/gralloc/gralloc_gem_pipe.c | 54 | ||||
-rw-r--r-- | src/gralloc/gralloc_gem_radeon.c | 362 | ||||
-rw-r--r-- | src/gralloc/gralloc_kms.c | 38 | ||||
-rw-r--r-- | src/gralloc/gralloc_mod.c | 10 | ||||
-rw-r--r-- | src/gralloc/gralloc_mod.h | 3 |
9 files changed, 594 insertions, 115 deletions
diff --git a/src/gralloc/Android.mk b/src/gralloc/Android.mk index 4125548735..d440a99308 100644 --- a/src/gralloc/Android.mk +++ b/src/gralloc/Android.mk @@ -1,54 +1,47 @@ +# Android.mk for gralloc + LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) -common_SRC_FILES := \ +LOCAL_SRC_FILES := \ gralloc_gem.c \ gralloc_kms.c \ gralloc_mod.c -common_C_INCLUDES := \ +LOCAL_C_INCLUDES := \ external/drm \ external/drm/include/drm -common_SHARED_LIBRARIES := \ +LOCAL_SHARED_LIBRARIES := \ libdrm \ liblog \ - libcutils - -ifeq ($(strip $(MESA_BUILD_I915)),true) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - $(common_SRC_FILES) \ - gralloc_gem_i915.c - -LOCAL_C_INCLUDES := \ - $(common_C_INCLUDES) \ - external/drm/intel - -LOCAL_SHARED_LIBRARIES := \ - $(common_SHARED_LIBRARIES) \ - libdrm_intel \ - libEGL - -LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw -LOCAL_MODULE := gralloc.i915 - -include $(BUILD_SHARED_LIBRARY) -endif # MESA_BUILD_I915 - -ifeq ($(strip $(MESA_BUILD_GALLIUM)),true) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - $(common_SRC_FILES) \ - gralloc_gem_pipe.c - -LOCAL_C_INCLUDES := \ - $(common_C_INCLUDES) \ + libcutils \ + libGLESv1_CM + +ifeq ($(strip $(MESA_BUILD_INTEL)),true) +LOCAL_SRC_FILES += gralloc_gem_intel.c +LOCAL_C_INCLUDES += external/drm/intel +LOCAL_CFLAGS += -DENABLE_INTEL +LOCAL_SHARED_LIBRARIES += libdrm_intel +endif # MESA_BUILD_INTEL + +ifeq ($(strip $(MESA_BUILD_RADEON)),true) +LOCAL_SRC_FILES += gralloc_gem_radeon.c +LOCAL_C_INCLUDES += external/drm/radeon +LOCAL_CFLAGS += -DENABLE_RADEON +LOCAL_SHARED_LIBRARIES += libdrm_radeon +endif # MESA_BUILD_INTEL + +# this is broken +ifeq ($(strip $(MESA_BUILD_VMWGFX)),true) +LOCAL_SRC_FILES += gralloc_gem_pipe.c +LOCAL_C_INCLUDES += \ external/mesa/src/gallium/include \ external/mesa/src/gallium/auxiliary +LOCAL_CFLAGS += -DENABLE_VMWGFX +endif # MESA_BUILD_VMWGFX -LOCAL_MODULE := libmesa_st_gralloc +LOCAL_MODULE := gralloc.mesa +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw -include $(BUILD_STATIC_LIBRARY) -endif # MESA_BUILD_GALLIUM +include $(BUILD_SHARED_LIBRARY) diff --git a/src/gralloc/gralloc_gem.c b/src/gralloc/gralloc_gem.c index a3df97f89b..be1a77c60b 100644 --- a/src/gralloc/gralloc_gem.c +++ b/src/gralloc/gralloc_gem.c @@ -117,3 +117,70 @@ drm_gem_validate(buffer_handle_t handle) return bo; } + +static const struct drm_gem_drv * +get_drv_from_fd(int fd) +{ + const struct drm_gem_drv *drv = NULL; + drmVersionPtr version; + + version = drmGetVersion(fd); + if (!version) { + LOGE("invalid DRM fd"); + return NULL; + } + + if (version->name) { +#ifdef ENABLE_INTEL + if (!drv && !strcmp(version->name, "i915")) + drv = &drm_gem_drv_intel; +#endif +#ifdef ENABLE_RADEON + if (!drv && !strcmp(version->name, "radeon")) + drv = &drm_gem_drv_radeon; +#endif +#ifdef ENABLE_VMWGFX + if (!drv && !strcmp(version->name, "vmwgfx")) + drv = &drm_gem_drv_pipe; +#endif + } + + if (!drv) + LOGE("unknown driver: %s", (version->name) ? version->name : "NULL"); + + drmFreeVersion(version); + + return drv; +} + +static int +drm_gem_drv_init_locked(struct drm_module_t *drm) +{ + const struct drm_gem_drv *drv; + int ret; + + if (drm->gem) + return 0; + + drv = get_drv_from_fd(drm->fd); + if (!drv) + return -EINVAL; + + ret = drv->init(drm); + if (!ret) + drm->drv = (void *) drv; + + return ret; +} + +int +drm_gem_drv_init(struct drm_module_t *drm) +{ + int ret; + + pthread_mutex_lock(&drm->mutex); + ret = drm_gem_drv_init_locked(drm); + pthread_mutex_unlock(&drm->mutex); + + return ret; +} diff --git a/src/gralloc/gralloc_gem.h b/src/gralloc/gralloc_gem.h index e6ef176efa..f8fa1e069d 100644 --- a/src/gralloc/gralloc_gem.h +++ b/src/gralloc/gralloc_gem.h @@ -56,22 +56,56 @@ drm_gem_validate(buffer_handle_t handle); struct drm_bo_t * drm_gem_create_bo(int width, int height, int format, int usage); - int drm_gem_drv_init(struct drm_module_t *drm); -struct drm_bo_t * + +struct drm_gem_drv { + int (*init)(struct drm_module_t *drm); + + struct drm_bo_t *(*alloc)(struct drm_module_t *drm, int width, int height, + int format, int usage, int *stride); + + void (*free)(struct drm_module_t *drm, struct drm_bo_t *bo); + + int (*map)(struct drm_module_t *drm, struct drm_bo_t *bo, + int x, int y, int w, int h, int enable_write, void **addr); + + void (*unmap)(struct drm_module_t *drm, struct drm_bo_t *bo); +}; + +extern const struct drm_gem_drv drm_gem_drv_intel; +extern const struct drm_gem_drv drm_gem_drv_radeon; +extern const struct drm_gem_drv drm_gem_drv_pipe; + +static inline struct drm_bo_t * drm_gem_drv_alloc(struct drm_module_t *drm, int width, int height, - int format, int usage, int *stride); + int format, int usage, int *stride) +{ + const struct drm_gem_drv *drv = (const struct drm_gem_drv *) drm->drv; + return drv->alloc(drm, width, height, format, usage, stride); +} -void -drm_gem_drv_free(struct drm_module_t *drm, struct drm_bo_t *bo); +static inline void +drm_gem_drv_free(struct drm_module_t *drm, struct drm_bo_t *bo) +{ + const struct drm_gem_drv *drv = (const struct drm_gem_drv *) drm->drv; + drv->free(drm, bo); +} -int +static inline int drm_gem_drv_map(struct drm_module_t *drm, struct drm_bo_t *bo, - int x, int y, int w, int h, int enable_write, void **addr); + int x, int y, int w, int h, int enable_write, void **addr) +{ + const struct drm_gem_drv *drv = (const struct drm_gem_drv *) drm->drv; + return drv->map(drm, bo, x, y, w, h, enable_write, addr); +} -void -drm_gem_drv_unmap(struct drm_module_t *drm, struct drm_bo_t *bo); +static inline void +drm_gem_drv_unmap(struct drm_module_t *drm, struct drm_bo_t *bo) +{ + const struct drm_gem_drv *drv = (const struct drm_gem_drv *) drm->drv; + drv->unmap(drm, bo); +} #endif /* _GRALLOC_GEM_H_ */ diff --git a/src/gralloc/gralloc_gem_i915.c b/src/gralloc/gralloc_gem_intel.c index 2822fe5c12..5cd765b562 100644 --- a/src/gralloc/gralloc_gem_i915.c +++ b/src/gralloc/gralloc_gem_intel.c @@ -11,7 +11,7 @@ #include "gralloc_gem.h" static void -drm_gem_drv_init_features_locked(struct drm_module_t *drm) +drm_gem_intel_init_features(struct drm_module_t *drm) { struct drm_i915_getparam gp; @@ -27,6 +27,8 @@ drm_gem_drv_init_features_locked(struct drm_module_t *drm) else drm->mode_page_flip = 0; + drm->mode_page_flip_blocking = 0; + if (drm->resources) { int pipe; @@ -40,38 +42,22 @@ drm_gem_drv_init_features_locked(struct drm_module_t *drm) /* XXX there is a bug in the kernel module */ drm->mode_page_flip = 0; - } static int -drm_gem_drv_init_locked(struct drm_module_t *drm) +drm_gem_intel_init(struct drm_module_t *drm) { - if (drm->gem) - return 0; - drm->gem = (void *) drm_intel_bufmgr_gem_init(drm->fd, 16 * 1024); if (!drm->gem) { LOGE("failed to create buffer manager"); return -ENOMEM; } - drm_gem_drv_init_features_locked(drm); + drm_gem_intel_init_features(drm); return 0; } -int -drm_gem_drv_init(struct drm_module_t *drm) -{ - int ret; - - pthread_mutex_lock(&drm->mutex); - ret = drm_gem_drv_init_locked(drm); - pthread_mutex_unlock(&drm->mutex); - - return ret; -} - static uint32_t drm_gem_get_tiling(struct drm_bo_t *bo) { @@ -89,9 +75,9 @@ drm_gem_get_tiling(struct drm_bo_t *bo) return tiling; } -struct drm_bo_t * -drm_gem_drv_alloc(struct drm_module_t *drm, int width, int height, - int format, int usage, int *stride) +static struct drm_bo_t * +drm_gem_intel_alloc(struct drm_module_t *drm, int width, int height, + int format, int usage, int *stride) { drm_intel_bufmgr *bufmgr = (drm_intel_bufmgr *) drm->gem; struct drm_bo_t *bo; @@ -161,16 +147,16 @@ drm_gem_drv_alloc(struct drm_module_t *drm, int width, int height, return bo; } -void -drm_gem_drv_free(struct drm_module_t *drm, struct drm_bo_t *bo) +static void +drm_gem_intel_free(struct drm_module_t *drm, struct drm_bo_t *bo) { drm_intel_bo_unreference((drm_intel_bo *) bo->data); free(bo); } -int -drm_gem_drv_map(struct drm_module_t *drm, struct drm_bo_t *bo, - int x, int y, int w, int h, int enable_write, void **addr) +static int +drm_gem_intel_map(struct drm_module_t *drm, struct drm_bo_t *bo, + int x, int y, int w, int h, int enable_write, void **addr) { drm_intel_bo *ibo = (drm_intel_bo *) bo->data; int err; @@ -198,8 +184,8 @@ drm_gem_drv_map(struct drm_module_t *drm, struct drm_bo_t *bo, return err; } -void -drm_gem_drv_unmap(struct drm_module_t *drm, struct drm_bo_t *bo) +static void +drm_gem_intel_unmap(struct drm_module_t *drm, struct drm_bo_t *bo) { drm_intel_bo *ibo = (drm_intel_bo *) bo->data; @@ -209,3 +195,11 @@ drm_gem_drv_unmap(struct drm_module_t *drm, struct drm_bo_t *bo) else drm_intel_bo_unmap(ibo); } + +const struct drm_gem_drv drm_gem_drv_intel = { + .init = drm_gem_intel_init, + .alloc = drm_gem_intel_alloc, + .free = drm_gem_intel_free, + .map = drm_gem_intel_map, + .unmap = drm_gem_intel_unmap, +}; diff --git a/src/gralloc/gralloc_gem_pipe.c b/src/gralloc/gralloc_gem_pipe.c index 99a8461627..74b35d0537 100644 --- a/src/gralloc/gralloc_gem_pipe.c +++ b/src/gralloc/gralloc_gem_pipe.c @@ -26,10 +26,11 @@ struct drm_pipe_buffer { }; static void -drm_gem_drv_init_features_locked(struct drm_module_t *drm) +drm_gem_pipe_init_features(struct drm_module_t *drm) { drm->mode_dirty_fb = 0; drm->mode_page_flip = 0; + drm->mode_page_flip_blocking = 0; if (strcmp(driver_descriptor.driver_name, "vmwgfx") == 0) drm->mode_dirty_fb = 1; @@ -38,13 +39,10 @@ drm_gem_drv_init_features_locked(struct drm_module_t *drm) } static int -drm_gem_drv_init_locked(struct drm_module_t *drm) +drm_gem_pipe_init(struct drm_module_t *drm) { struct drm_pipe_manager *pm; - if (drm->gem) - return 0; - pm = CALLOC(1, sizeof(*pm)); if (!pm) return -ENOMEM; @@ -60,23 +58,11 @@ drm_gem_drv_init_locked(struct drm_module_t *drm) drm->gem = (void *) pm; - drm_gem_drv_init_features_locked(drm); + drm_gem_pipe_init_features(drm); return 0; } -int -drm_gem_drv_init(struct drm_module_t *drm) -{ - int ret; - - pthread_mutex_lock(&drm->mutex); - ret = drm_gem_drv_init_locked(drm); - pthread_mutex_unlock(&drm->mutex); - - return ret; -} - static enum pipe_format get_pipe_format(int format) { @@ -144,7 +130,7 @@ get_pipe_buffer(struct drm_pipe_manager *pm, int width, int height, if (templ.format == PIPE_FORMAT_NONE || !pm->screen->is_format_supported(pm->screen, templ.format, - templ.target, 0, templ.bind, 0)) { + templ.target, 0, templ.bind)) { LOGE("unsupported format 0x%x", format); return NULL; } @@ -198,9 +184,9 @@ fail: return NULL; } -struct drm_bo_t * -drm_gem_drv_alloc(struct drm_module_t *drm, int width, int height, - int format, int usage, int *stride) +static struct drm_bo_t * +drm_gem_pipe_alloc(struct drm_module_t *drm, int width, int height, + int format, int usage, int *stride) { struct drm_pipe_manager *pm = (struct drm_pipe_manager *) drm->gem; struct drm_pipe_buffer *buf; @@ -232,8 +218,8 @@ drm_gem_drv_alloc(struct drm_module_t *drm, int width, int height, return bo; } -void -drm_gem_drv_free(struct drm_module_t *drm, struct drm_bo_t *bo) +static void +drm_gem_pipe_free(struct drm_module_t *drm, struct drm_bo_t *bo) { struct drm_pipe_manager *pm = (struct drm_pipe_manager *) drm->gem; struct drm_pipe_buffer *buf = (struct drm_pipe_buffer *) bo->data; @@ -250,9 +236,9 @@ drm_gem_drv_free(struct drm_module_t *drm, struct drm_bo_t *bo) free(bo); } -int -drm_gem_drv_map(struct drm_module_t *drm, struct drm_bo_t *bo, - int x, int y, int w, int h, int enable_write, void **addr) +static int +drm_gem_pipe_map(struct drm_module_t *drm, struct drm_bo_t *bo, + int x, int y, int w, int h, int enable_write, void **addr) { struct drm_pipe_manager *pm = (struct drm_pipe_manager *) drm->gem; struct drm_pipe_buffer *buf = (struct drm_pipe_buffer *) bo->data; @@ -313,8 +299,8 @@ drm_gem_drv_map(struct drm_module_t *drm, struct drm_bo_t *bo, return ret; } -void -drm_gem_drv_unmap(struct drm_module_t *drm, struct drm_bo_t *bo) +static void +drm_gem_pipe_unmap(struct drm_module_t *drm, struct drm_bo_t *bo) { struct drm_pipe_manager *pm = (struct drm_pipe_manager *) drm->gem; struct drm_pipe_buffer *buf = (struct drm_pipe_buffer *) bo->data; @@ -327,7 +313,15 @@ drm_gem_drv_unmap(struct drm_module_t *drm, struct drm_bo_t *bo) pipe_transfer_destroy(pm->context, buf->transfer); buf->transfer = NULL; - pm->context->flush(pm->context, PIPE_FLUSH_RENDER_CACHE, NULL); + pm->context->flush(pm->context, NULL); pthread_mutex_unlock(&pm->mutex); } + +const struct drm_gem_drv drm_gem_drv_pipe = { + .init = drm_gem_pipe_init, + .alloc = drm_gem_pipe_alloc, + .free = drm_gem_pipe_free, + .map = drm_gem_pipe_map, + .unmap = drm_gem_pipe_unmap, +}; diff --git a/src/gralloc/gralloc_gem_radeon.c b/src/gralloc/gralloc_gem_radeon.c new file mode 100644 index 0000000000..469a1488a0 --- /dev/null +++ b/src/gralloc/gralloc_gem_radeon.c @@ -0,0 +1,362 @@ +/* + * Based on xf86-video-ati, which is + * + * 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 (including the next + * paragraph) 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. + * + * Authors: + * Dave Airlie <airlied@redhat.com> + */ + +/* + * XXX This driver assumes evergreen. It works, but is slow and has sync + * issues. + */ + +#define LOG_TAG "GRALLOC-RADEON" + +#include <cutils/log.h> +#include <stdlib.h> +#include <errno.h> +#include <drm.h> +#include <radeon_drm.h> +#include <radeon_bo_gem.h> +#include <radeon_bo.h> + +#include "gralloc_mod.h" +#include "gralloc_gem.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 drm_module_t *drm; + 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; +}; + +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->drm->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 = MAX(info->num_banks, + (((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 void +drm_gem_radeon_init_features(struct drm_module_t *drm) +{ + drm->mode_dirty_fb = 0; + drm->mode_page_flip = 1; + drm->mode_page_flip_blocking = 1; + drm->swap_interval = 1; + drm->vblank_secondary = 0; +} + +static int +drm_gem_radeon_init(struct drm_module_t *drm) +{ + struct radeon_info *info; + int ret; + + info = calloc(1, sizeof(*info)); + if (!info) + return -ENOMEM; + + info->drm = drm; + info->bufmgr = radeon_bo_manager_gem_ctor(info->drm->fd); + if (!info->bufmgr) { + LOGE("failed to create buffer manager"); + free(info); + return -ENOMEM; + } + + + drm->gem = (void *) info; + + ret = eg_init_tile_config(info); + if (ret) { + radeon_bo_manager_gem_dtor(info->bufmgr); + free(info); + return ret; + } + + drm_gem_radeon_init_features(drm); + + return 0; +} + +static uint32_t +drm_gem_get_tiling(struct drm_bo_t *bo) +{ + return 0; +} + +static struct drm_bo_t * +drm_gem_radeon_alloc(struct drm_module_t *drm, int width, int height, + int format, int usage, int *stride) +{ + struct radeon_info *info = (struct radeon_info *) drm->gem; + struct drm_bo_t *bo; + struct radeon_bo *rbo; + int aligned_width, aligned_height, cpp; + int pitch, size, base_align; + uint32_t tiling, domain; + + bo = drm_gem_create_bo(width, height, format, usage); + if (!bo) + return NULL; + + cpp = drm_mod_get_bpp(format); + if (!cpp) { + LOGE("unrecognized format 0x%x", format); + free(bo); + return NULL; + } + + tiling = drm_gem_get_tiling(bo); + domain = RADEON_GEM_DOMAIN_VRAM; + + if (usage & (GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_TEXTURE)) { + aligned_width = ALIGN(width, eg_get_pitch_align(info, cpp, tiling)); + aligned_height = ALIGN(height, eg_get_height_align(info, tiling)); + } + else { + aligned_width = width; + aligned_height = height; + } + + if (!(usage & (GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER)) && + (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); + + rbo = radeon_bo_open(info->bufmgr, 0, size, base_align, domain, 0); + if (!rbo) { + LOGE("failed to allocate rbo %dx%dx%d", width, height, cpp); + free(bo); + return NULL; + } + + if (tiling) + radeon_bo_set_tiling(rbo, tiling, pitch); + + if (bo->usage & GRALLOC_USAGE_HW_FB) { + bo->stride = pitch; + bo->fb_handle = rbo->handle; + } + + if (radeon_gem_get_kernel_name(rbo, (uint32_t *) &bo->name)) { + LOGE("failed to flink rbo"); + radeon_bo_unref(rbo); + free(bo); + return NULL; + } + + bo->data = (int) rbo; + + *stride = pitch; + + return bo; +} + +static void +drm_gem_radeon_free(struct drm_module_t *drm, struct drm_bo_t *bo) +{ + radeon_bo_unref((struct radeon_bo *) bo->data); + free(bo); +} + +static int +drm_gem_radeon_map(struct drm_module_t *drm, struct drm_bo_t *bo, + int x, int y, int w, int h, int enable_write, void **addr) +{ + struct radeon_bo *rbo = (struct radeon_bo *) bo->data; + int err; + + if (!rbo) { + struct radeon_info *info = (struct radeon_info *) drm->gem; + + rbo = radeon_bo_open(info->bufmgr, bo->name, 0, 0, RADEON_GEM_DOMAIN_VRAM, 0); + if (!rbo) { + LOGE("failed to create rbo from name %u", bo->name); + return -EINVAL; + } + + bo->data = (int) rbo; + } + + err = radeon_bo_map(rbo, enable_write); + if (!err) + *addr = rbo->ptr; + + return err; +} + +static void +drm_gem_radeon_unmap(struct drm_module_t *drm, struct drm_bo_t *bo) +{ + struct radeon_bo *rbo = (struct radeon_bo *) bo->data; + + radeon_bo_unmap(rbo); +} + +const struct drm_gem_drv drm_gem_drv_radeon = { + .init = drm_gem_radeon_init, + .alloc = drm_gem_radeon_alloc, + .free = drm_gem_radeon_free, + .map = drm_gem_radeon_map, + .unmap = drm_gem_radeon_unmap, +}; diff --git a/src/gralloc/gralloc_kms.c b/src/gralloc/gralloc_kms.c index 6ae9446244..7bc65b3438 100644 --- a/src/gralloc/gralloc_kms.c +++ b/src/gralloc/gralloc_kms.c @@ -63,28 +63,52 @@ drm_kms_set_crtc(struct drm_module_t *drm, struct drm_bo_t *bo) return ret; } +static void page_flip_handler(int fd, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, + void *user_data) +{ + struct drm_module_t *drm = (struct drm_module_t *) user_data; + + drm->flip_pending = 0; +} + static int drm_kms_page_flip(struct drm_module_t *drm, struct drm_bo_t *bo) { - int waits = 3, ret; + int retries = 3, ret; if (drm->swap_interval > 1) drm_kms_wait_vblank(drm, drm->swap_interval - 1); - while (waits) { - ret = drmModePageFlip(drm->fd, drm->crtc_id, bo->fb_id, 0x0, NULL); - if (ret && errno == -EBUSY) { + /* TODO throttle page flip instead of retrying here */ + while (retries) { + ret = drmModePageFlip(drm->fd, drm->crtc_id, bo->fb_id, + DRM_MODE_PAGE_FLIP_EVENT, (void *) drm); + if (ret && errno == EBUSY) { if (drm->swap_interval) drm_kms_wait_vblank(drm, 1); else usleep(5000); - waits--; + retries--; } else { + if (!ret) + drm->flip_pending = 1; break; } } + if (drm->mode_page_flip_blocking && drm->flip_pending) { + drmEventContext ctx; + + memset(&ctx, 0, sizeof(ctx)); + ctx.version = DRM_EVENT_CONTEXT_VERSION; + ctx.page_flip_handler = page_flip_handler; + + while (drm->flip_pending) + drmHandleEvent(drm->fd, &ctx); + } + if (ret) LOGE("failed to perform page flip"); @@ -202,8 +226,10 @@ drm_kms_init_locked(struct drm_module_t *drm) return 0; drm->resources = drmModeGetResources(drm->fd); - if (!drm->resources) + if (!drm->resources) { + LOGE("failed to get modeset resources"); return -EINVAL; + } for (i = 0; i < drm->resources->count_connectors; i++) { drmModeConnectorPtr connector; diff --git a/src/gralloc/gralloc_mod.c b/src/gralloc/gralloc_mod.c index 1296d2af04..bc0786eb3e 100644 --- a/src/gralloc/gralloc_mod.c +++ b/src/gralloc/gralloc_mod.c @@ -222,11 +222,17 @@ drm_mod_post_fb0(struct framebuffer_device_t *fb, buffer_handle_t handle) return drm_kms_post(drm, bo); } -#include <EGL/egl.h> +#include <GLES/gl.h> static int drm_mod_composition_complete_fb0(struct framebuffer_device_t *fb) { - eglWaitClient(); + struct drm_module_t *drm = (struct drm_module_t *) fb->common.module; + + if (drm->mode_page_flip) + glFlush(); + else + glFinish(); + return 0; } diff --git a/src/gralloc/gralloc_mod.h b/src/gralloc/gralloc_mod.h index e06ec864ad..33f6e9a91d 100644 --- a/src/gralloc/gralloc_mod.h +++ b/src/gralloc/gralloc_mod.h @@ -26,13 +26,16 @@ struct drm_module_t { #endif /* initialized by drm_gem_drv_init */ + void *drv; void *gem; int mode_dirty_fb; int mode_page_flip; + int mode_page_flip_blocking; /* page flip should block */ int swap_interval; int vblank_secondary; int first_post; + int flip_pending; }; static inline int |