From e9edd2f5002c642b59f028b3ec076d604ae8ce9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 20 Jun 2012 08:40:07 +0200 Subject: Initial glamor support. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable at build time with --enable-glamor and runtime with Option "AccelMethod" "glamor" The most notable lack of functionality is XVideo. Use something like VDPAU for now. Signed-off-by: Michel Dänzer --- configure.ac | 14 +++ man/radeon.man | 39 +++++--- src/Makefile.am | 8 ++ src/drmmode_display.c | 8 +- src/radeon.h | 105 +++++++++++++++++++- src/radeon_accel.c | 7 +- src/radeon_dri2.c | 240 +++++++++++++++++++++++++++++--------------- src/radeon_exa.c | 32 ------ src/radeon_glamor.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/radeon_glamor.h | 93 +++++++++++++++++ src/radeon_kms.c | 39 +++++--- 11 files changed, 711 insertions(+), 143 deletions(-) create mode 100644 src/radeon_glamor.c create mode 100644 src/radeon_glamor.h diff --git a/configure.ac b/configure.ac index a73dd4eb..86199f22 100644 --- a/configure.ac +++ b/configure.ac @@ -91,6 +91,20 @@ AM_CONDITIONAL(LIBUDEV, test x$LIBUDEV = xyes) SAVE_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $XORG_CFLAGS" +AC_MSG_CHECKING([whether to include GLAMOR support]) +AC_ARG_ENABLE(glamor, + AS_HELP_STRING([--enable-glamor], + [Enable glamor, a new GL-based acceleration [default=no]]), + [GLAMOR="$enableval"], + [GLAMOR=no]) +AC_MSG_RESULT([$GLAMOR]) +AM_CONDITIONAL(GLAMOR, test x$GLAMOR != xno) +if test "x$GLAMOR" != "xno"; then + PKG_CHECK_MODULES(LIBGLAMOR, [glamor >= 0.3.1]) + PKG_CHECK_MODULES(LIBGLAMOR_EGL, [glamor-egl]) + AC_DEFINE(USE_GLAMOR, 1, [Enable glamor acceleration]) +fi + AC_CHECK_DECL(xf86ModeBandwidth, [AC_DEFINE(HAVE_XF86MODEBANDWIDTH, 1, [Have xf86ModeBandwidth prototype])], [], diff --git a/man/radeon.man b/man/radeon.man index da0c1ccc..be503141 100644 --- a/man/radeon.man +++ b/man/radeon.man @@ -211,13 +211,6 @@ For example: Option \*qZaphodHeads\*q \*qLVDS,VGA-0\*q will assign xrandr outputs LVDS and VGA-0 to this instance of the driver. .TP -.BI "Option \*qEXAVSync\*q \*q" boolean \*q -This option attempts to avoid tearing by stalling the engine until the display -controller has passed the destination region. It reduces tearing at the cost -of performance and has been known to cause instability on some chips. -The default is -.B off. -.TP .BI "Option \*qColorTiling\*q \*q" "boolean" \*q The framebuffer can be addressed either in linear or tiled mode. Tiled mode can provide significant performance benefits with 3D applications. Tiling will be disabled if the drm @@ -241,6 +234,33 @@ The default value is .B off for R/RV6XX, R/RV7XX, RS780, RS880, EVERGREEN, and CAYMAN. .TP +.BI "Option \*qEnablePageFlip\*q \*q" boolean \*q +Enable DRI2 page flipping. The default is +.B on. +Pageflipping is supported on all radeon hardware. +.TP +.BI "Option \*qAccelMethod\*q \*q" "string" \*q +Chooses between available acceleration architectures. Valid values are +.B EXA +and +.B glamor. +The default is +.B EXA. + +.PP +The following driver +.B Options +are supported for +.B EXA +: +.TP +.BI "Option \*qEXAVSync\*q \*q" boolean \*q +This option attempts to avoid tearing by stalling the engine until the display +controller has passed the destination region. It reduces tearing at the cost +of performance and has been known to cause instability on some chips. +The default is +.B off. +.TP .BI "Option \*qEXAPixmaps\*q \*q" boolean \*q Under KMS, to avoid thrashing pixmaps in/out of VRAM on low memory cards, we use a heuristic based on VRAM amount to determine whether to allow EXA @@ -259,11 +279,6 @@ the framerate of applications that render frames at less than refresh rate. .IP The default value is .B on. -.TP -.BI "Option \*qEnablePageFlip\*q \*q" boolean \*q -Enable DRI2 page flipping. The default is -.B on. -Pageflipping is supported on all radeon hardware. .SH TEXTURED VIDEO ATTRIBUTES The driver supports the following X11 Xv attributes for Textured Video. diff --git a/src/Makefile.am b/src/Makefile.am index e857f21a..da94927f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,6 +64,13 @@ radeon_drv_la_SOURCES = \ $(RADEON_EXA_SOURCES) \ $(RADEON_KMS_SRCS) +if GLAMOR +AM_CFLAGS += @LIBGLAMOR_CFLAGS@ +radeon_drv_la_LIBADD += @LIBGLAMOR_LIBS@ +radeon_drv_la_SOURCES += \ + radeon_glamor.c +endif + EXTRA_DIST = \ radeon_textured_videofuncs.c \ r600_reg.h \ @@ -88,6 +95,7 @@ EXTRA_DIST = \ radeon_exa_render.c \ radeon_exa_funcs.c \ radeon_exa_shared.h \ + radeon_glamor.h \ radeon.h \ radeon_probe.h \ radeon_reg.h \ diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 27569e51..6a357283 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -101,7 +101,8 @@ static PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, return NULL; } - exaMoveInPixmap(pixmap); + if (!info->use_glamor) + exaMoveInPixmap(pixmap); radeon_set_pixmap_bo(pixmap, bo); if (info->ChipFamily >= CHIP_FAMILY_R600) { surface = radeon_get_pixmap_surface(pixmap); @@ -278,7 +279,7 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) uint32_t tiling_flags = 0; Bool ret; - if (info->accelOn == FALSE) + if (info->accelOn == FALSE || info->use_glamor) goto fallback; for (i = 0; i < xf86_config->num_crtc; i++) { @@ -1442,6 +1443,9 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) crtc->rotation, crtc->x, crtc->y); } + if (info->use_glamor) + radeon_glamor_create_screen_resources(scrn->pScreen); + if (old_fb_id) drmModeRmFB(drmmode->fd, old_fb_id); if (old_front) diff --git a/src/radeon.h b/src/radeon.h index d357dc13..2f05249e 100644 --- a/src/radeon.h +++ b/src/radeon.h @@ -51,6 +51,7 @@ #include "exa.h" +#include "radeon_glamor.h" /* Exa and Cursor Support */ #include "xf86Cursor.h" @@ -429,6 +430,7 @@ typedef struct { Bool allowColorTiling2D; struct radeon_accel_state *accel_state; Bool accelOn; + Bool use_glamor; Bool exa_pixmaps; Bool exa_force_create; XF86ModReqInfo exaReq; @@ -522,11 +524,107 @@ extern void radeon_ddx_cs_start(ScrnInfoPtr pScrn, int num, const char *file, const char *func, int line); void radeon_kms_update_vram_limit(ScrnInfoPtr pScrn, int new_fb_size); -struct radeon_surface *radeon_get_pixmap_surface(PixmapPtr pPix); -struct radeon_bo *radeon_get_pixmap_bo(PixmapPtr pPix); -void radeon_set_pixmap_bo(PixmapPtr pPix, struct radeon_bo *bo); + +static inline struct radeon_surface *radeon_get_pixmap_surface(PixmapPtr pPix) +{ +#ifdef USE_GLAMOR + RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pPix->drawable.pScreen)); + + if (info->use_glamor) { + struct radeon_pixmap *priv; + priv = radeon_get_pixmap_private(pPix); + return priv ? &priv->surface : NULL; + } else +#endif + { + struct radeon_exa_pixmap_priv *driver_priv; + driver_priv = exaGetPixmapDriverPrivate(pPix); + return &driver_priv->surface; + } + + return NULL; +} + uint32_t radeon_get_pixmap_tiling(PixmapPtr pPix); +static inline void radeon_set_pixmap_bo(PixmapPtr pPix, struct radeon_bo *bo) +{ +#ifdef USE_GLAMOR + RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pPix->drawable.pScreen)); + + if (info->use_glamor) { + struct radeon_pixmap *priv; + + priv = radeon_get_pixmap_private(pPix); + if (priv == NULL && bo == NULL) + return; + + if (priv) { + if (priv->bo == bo) + return; + + if (priv->bo) + radeon_bo_unref(priv->bo); + + free(priv); + priv = NULL; + } + + if (bo) { + uint32_t pitch; + + priv = calloc(1, sizeof (struct radeon_pixmap)); + if (priv == NULL) + goto out; + + radeon_bo_ref(bo); + priv->bo = bo; + + radeon_bo_get_tiling(bo, &priv->tiling_flags, &pitch); + } +out: + radeon_set_pixmap_private(pPix, priv); + } else +#endif /* USE_GLAMOR */ + { + struct radeon_exa_pixmap_priv *driver_priv; + + driver_priv = exaGetPixmapDriverPrivate(pPix); + if (driver_priv) { + uint32_t pitch; + + if (driver_priv->bo) + radeon_bo_unref(driver_priv->bo); + + radeon_bo_ref(bo); + driver_priv->bo = bo; + + radeon_bo_get_tiling(bo, &driver_priv->tiling_flags, &pitch); + } + } +} + +static inline struct radeon_bo *radeon_get_pixmap_bo(PixmapPtr pPix) +{ +#ifdef USE_GLAMOR + RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pPix->drawable.pScreen)); + + if (info->use_glamor) { + struct radeon_pixmap *priv; + priv = radeon_get_pixmap_private(pPix); + return priv ? priv->bo : NULL; + } else +#endif + { + struct radeon_exa_pixmap_priv *driver_priv; + driver_priv = exaGetPixmapDriverPrivate(pPix); + return driver_priv->bo; + } + + return NULL; +} + + #define CP_PACKET0(reg, n) \ (RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2)) #define CP_PACKET1(reg0, reg1) \ @@ -659,6 +757,7 @@ static __inline__ void RADEON_SYNC(RADEONInfoPtr info, ScrnInfoPtr pScrn) } enum { + RADEON_CREATE_PIXMAP_DRI2 = 0x08000000, RADEON_CREATE_PIXMAP_TILING_MACRO = 0x10000000, RADEON_CREATE_PIXMAP_TILING_MICRO = 0x20000000, RADEON_CREATE_PIXMAP_DEPTH = 0x40000000, /* for r200 */ diff --git a/src/radeon_accel.c b/src/radeon_accel.c index 15cf2bd8..8eff5c52 100644 --- a/src/radeon_accel.c +++ b/src/radeon_accel.c @@ -182,7 +182,12 @@ Bool RADEONAccelInit(ScreenPtr pScreen) RADEONInfoPtr info = RADEONPTR(pScrn); if (info->directRenderingEnabled) { - if (info->ChipFamily >= CHIP_FAMILY_CEDAR) { + if (info->use_glamor) { + if (!radeon_glamor_init(pScreen)) { + info->use_glamor = FALSE; + return FALSE; + } + } else if (info->ChipFamily >= CHIP_FAMILY_CEDAR) { if (!EVERGREENDrawInit(pScreen)) return FALSE; } else diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c index 8c24de90..12b198c5 100644 --- a/src/radeon_dri2.c +++ b/src/radeon_dri2.c @@ -73,6 +73,77 @@ struct dri2_buffer_priv { }; +static PixmapPtr get_drawable_pixmap(DrawablePtr drawable) +{ + if (drawable->type == DRAWABLE_PIXMAP) + return (PixmapPtr)drawable; + else + return (*drawable->pScreen->GetWindowPixmap)((WindowPtr)drawable); +} + + +static PixmapPtr fixup_glamor(DrawablePtr drawable, PixmapPtr pixmap) +{ + PixmapPtr old = get_drawable_pixmap(drawable); +#ifdef USE_GLAMOR + ScreenPtr screen = drawable->pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + GCPtr gc; + + /* With a glamor pixmap, 2D pixmaps are created in texture + * and without a static BO attached to it. To support DRI, + * we need to create a new textured-drm pixmap and + * need to copy the original content to this new textured-drm + * pixmap, and then convert the old pixmap to a coherent + * textured-drm pixmap which has a valid BO attached to it + * and also has a valid texture, thus both glamor and DRI2 + * can access it. + * + */ + + /* Copy the current contents of the pixmap to the bo. */ + gc = GetScratchGC(drawable->depth, screen); + if (gc) { + ValidateGC(&pixmap->drawable, gc); + gc->ops->CopyArea(&old->drawable, &pixmap->drawable, + gc, + 0, 0, + old->drawable.width, + old->drawable.height, + 0, 0); + FreeScratchGC(gc); + } + + radeon_set_pixmap_private(pixmap, NULL); + screen->DestroyPixmap(pixmap); + + /* And redirect the pixmap to the new bo (for 3D). */ + radeon_set_pixmap_private(old, priv); + old->refcnt++; + + /* This creating should not fail, as we already created its + * successfully. But if it happens, we put a warning indicator + * here, and the old pixmap will still be a glamor pixmap, and + * latter the pixmap_flink will get a 0 name, then the X server + * will pass a BadAlloc to the client.*/ + if (!radeon_glamor_create_textured_pixmap(old)) + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "Failed to get DRI drawable for glamor pixmap.\n"); + + screen->ModifyPixmapHeader(old, + old->drawable.width, + old->drawable.height, + 0, 0, + priv->stride, + NULL); + +#endif /* USE_GLAMOR*/ + + return old; +} + + #ifndef USE_DRI2_1_1_0 static BufferPtr radeon_dri2_create_buffers(DrawablePtr drawable, @@ -85,13 +156,13 @@ radeon_dri2_create_buffers(DrawablePtr drawable, BufferPtr buffers; struct dri2_buffer_priv *privates; PixmapPtr pixmap, depth_pixmap; - struct radeon_exa_pixmap_priv *driver_priv; + struct radeon_bo *bo; int i, r, need_enlarge = 0; int flags = 0; unsigned front_width; uint32_t tiling = 0; - pixmap = screen->GetScreenPixmap(screen); + pixmap = pScreen->GetScreenPixmap(pScreen); front_width = pixmap->drawable.width; buffers = calloc(count, sizeof *buffers); @@ -106,17 +177,25 @@ radeon_dri2_create_buffers(DrawablePtr drawable, depth_pixmap = NULL; for (i = 0; i < count; i++) { + Bool is_glamor_pixmap = FALSE; + unsigned aligned_width = drawable->width; + unsigned aligned_height = drawable->height; + if (attachments[i] == DRI2BufferFrontLeft) { - if (drawable->type == DRAWABLE_PIXMAP) { - pixmap = (Pixmap*)drawable; - } else { - pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable); - } - pixmap->refcnt++; + pixmap = get_drawable_pixmap(drawable); + if (info->use_glamor && !radeon_get_pixmap_bo(pixmap)) { + is_glamor_pixmap = TRUE; + aligned_width = pixmap->drawable.width; + aligned_height = pixmap->drawable.height; + pixmap = NULL; + } else + pixmap->refcnt++; } else if (attachments[i] == DRI2BufferStencil && depth_pixmap) { pixmap = depth_pixmap; pixmap->refcnt++; - } else { + } + + if (!pixmap) { /* tile the back buffer */ switch(attachments[i]) { case DRI2BufferDepth: @@ -145,6 +224,8 @@ radeon_dri2_create_buffers(DrawablePtr drawable, break; case DRI2BufferBackLeft: case DRI2BufferBackRight: + case DRI2BufferFrontLeft: + case DRI2BufferFrontRight: case DRI2BufferFakeFrontLeft: case DRI2BufferFakeFrontRight: if (info->ChipFamily >= CHIP_FAMILY_R600) @@ -164,14 +245,15 @@ radeon_dri2_create_buffers(DrawablePtr drawable, if (flags & RADEON_CREATE_PIXMAP_TILING_MACRO) tiling |= RADEON_TILING_MACRO; + if (aligned_width == front_width) + aligned_width = pScrn->virtualX; + if (need_enlarge) { /* evergreen uses separate allocations for depth and stencil * so we make an extra large depth buffer to cover stencil * as well. */ - unsigned aligned_width = drawable->width; unsigned width_align = drmmode_get_pitch_align(pScrn, drawable->depth / 8, tiling); - unsigned aligned_height; unsigned height_align = drmmode_get_height_align(pScrn, tiling); unsigned base_align = drmmode_get_base_align(pScrn, drawable->depth / 8, tiling); unsigned pitch_bytes; @@ -181,42 +263,33 @@ radeon_dri2_create_buffers(DrawablePtr drawable, aligned_width = pScrn->virtualX; aligned_width = RADEON_ALIGN(aligned_width, width_align); pitch_bytes = aligned_width * (drawable->depth / 8); - aligned_height = RADEON_ALIGN(drawable->height, height_align); + aligned_height = RADEON_ALIGN(aligned_height, height_align); size = pitch_bytes * aligned_height; size = RADEON_ALIGN(size, base_align); /* add additional size for stencil */ size += aligned_width * aligned_height; aligned_height = RADEON_ALIGN(size / pitch_bytes, height_align); - - pixmap = (*pScreen->CreatePixmap)(pScreen, - aligned_width, - aligned_height, - drawable->depth, - flags); - - } else { - unsigned aligned_width = drawable->width; - - if (aligned_width == front_width) - aligned_width = pScrn->virtualX; - - pixmap = (*pScreen->CreatePixmap)(pScreen, - aligned_width, - drawable->height, - drawable->depth, - flags); } + + pixmap = (*pScreen->CreatePixmap)(pScreen, + aligned_width, + aligned_height, + drawable->depth, + flags | RADEON_CREATE_PIXMAP_DRI2); } if (attachments[i] == DRI2BufferDepth) { depth_pixmap = pixmap; } - info->exa_force_create = TRUE; - exaMoveInPixmap(pixmap); - info->exa_force_create = FALSE; - driver_priv = exaGetPixmapDriverPrivate(pixmap); - if (!driver_priv || - radeon_gem_get_kernel_name(driver_priv->bo, &buffers[i].name) != 0) { + if (!info->use_glamor) { + info->exa_force_create = TRUE; + exaMoveInPixmap(pixmap); + info->exa_force_create = FALSE; + } + if (is_glamor_pixmap) + pixmap = fixup_glamor(drawable, pixmap); + bo = radeon_get_pixmap_bo(pixmap); + if (!bo || radeon_gem_get_kernel_name(bo, &buffers[i].name) != 0) { int j; for (j = 0; j < i; j++) @@ -249,11 +322,13 @@ radeon_dri2_create_buffer(DrawablePtr drawable, BufferPtr buffers; struct dri2_buffer_priv *privates; PixmapPtr pixmap, depth_pixmap; - struct radeon_exa_pixmap_priv *driver_priv; + struct radeon_bo *bo; int flags; unsigned front_width; uint32_t tiling = 0; unsigned aligned_width = drawable->width; + unsigned height = drawable->height; + Bool is_glamor_pixmap = FALSE; pixmap = pScreen->GetScreenPixmap(pScreen); front_width = pixmap->drawable.width; @@ -261,16 +336,20 @@ radeon_dri2_create_buffer(DrawablePtr drawable, pixmap = depth_pixmap = NULL; if (attachment == DRI2BufferFrontLeft) { - if (drawable->type == DRAWABLE_PIXMAP) { - pixmap = (PixmapPtr)drawable; - } else { - pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable); - } - pixmap->refcnt++; + pixmap = get_drawable_pixmap(drawable); + if (info->use_glamor && !radeon_get_pixmap_bo(pixmap)) { + is_glamor_pixmap = TRUE; + aligned_width = pixmap->drawable.width; + height = pixmap->drawable.height; + pixmap = NULL; + } else + pixmap->refcnt++; } else if (attachment == DRI2BufferStencil && depth_pixmap) { pixmap = depth_pixmap; pixmap->refcnt++; - } else { + } + + if (!pixmap) { /* tile the back buffer */ switch(attachment) { case DRI2BufferDepth: @@ -310,6 +389,8 @@ radeon_dri2_create_buffer(DrawablePtr drawable, break; case DRI2BufferBackLeft: case DRI2BufferBackRight: + case DRI2BufferFrontLeft: + case DRI2BufferFrontRight: case DRI2BufferFakeFrontLeft: case DRI2BufferFakeFrontRight: if (info->ChipFamily >= CHIP_FAMILY_R600) { @@ -336,9 +417,9 @@ radeon_dri2_create_buffer(DrawablePtr drawable, pixmap = (*pScreen->CreatePixmap)(pScreen, aligned_width, - drawable->height, + height, (format != 0)?format:drawable->depth, - flags); + flags | RADEON_CREATE_PIXMAP_DRI2); } if (!pixmap) @@ -351,12 +432,15 @@ radeon_dri2_create_buffer(DrawablePtr drawable, if (attachment == DRI2BufferDepth) { depth_pixmap = pixmap; } - info->exa_force_create = TRUE; - exaMoveInPixmap(pixmap); - info->exa_force_create = FALSE; - driver_priv = exaGetPixmapDriverPrivate(pixmap); - if (!driver_priv || - (radeon_gem_get_kernel_name(driver_priv->bo, &buffers->name) != 0)) + if (!info->use_glamor) { + info->exa_force_create = TRUE; + exaMoveInPixmap(pixmap); + info->exa_force_create = FALSE; + } + if (is_glamor_pixmap) + pixmap = fixup_glamor(drawable, pixmap); + bo = radeon_get_pixmap_bo(pixmap); + if (!bo || radeon_gem_get_kernel_name(bo, &buffers->name) != 0) goto error; privates = calloc(1, sizeof(struct dri2_buffer_priv)); @@ -476,11 +560,10 @@ radeon_dri2_copy_region(DrawablePtr drawable, if (extents->x1 == 0 && extents->y1 == 0 && extents->x2 == drawable->width && extents->y2 == drawable->height) { - struct radeon_exa_pixmap_priv *exa_priv = - exaGetPixmapDriverPrivate(dst_private->pixmap); + struct radeon_bo *bo = radeon_get_pixmap_bo(dst_private->pixmap); - if (exa_priv && exa_priv->bo) - radeon_bo_wait(exa_priv->bo); + if (bo) + radeon_bo_wait(bo); } } } @@ -643,7 +726,7 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client, void *data, unsigned int target_msc) { struct dri2_buffer_priv *back_priv; - struct radeon_exa_pixmap_priv *exa_priv; + struct radeon_bo *bo; DRI2FrameEventPtr flip_info; /* Main crtc for this drawable shall finally deliver pageflip event. */ @@ -665,9 +748,9 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client, /* Page flip the full screen buffer */ back_priv = back->driverPrivate; - exa_priv = exaGetPixmapDriverPrivate(back_priv->pixmap); + bo = radeon_get_pixmap_bo(back_priv->pixmap); - return radeon_do_pageflip(scrn, exa_priv->bo, flip_info, ref_crtc_hw_id); + return radeon_do_pageflip(scrn, bo, flip_info, ref_crtc_hw_id); } static Bool @@ -675,19 +758,17 @@ update_front(DrawablePtr draw, DRI2BufferPtr front) { int r; PixmapPtr pixmap; + RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(draw->pScreen)); struct dri2_buffer_priv *priv = front->driverPrivate; - struct radeon_exa_pixmap_priv *driver_priv; - - if (draw->type == DRAWABLE_PIXMAP) - pixmap = (PixmapPtr)draw; - else - pixmap = (*draw->pScreen->GetWindowPixmap)((WindowPtr)draw); + struct radeon_bo *bo; + pixmap = get_drawable_pixmap(draw); pixmap->refcnt++; - exaMoveInPixmap(pixmap); - driver_priv = exaGetPixmapDriverPrivate(pixmap); - r = radeon_gem_get_kernel_name(driver_priv->bo, &front->name); + if (!info->use_glamor) + exaMoveInPixmap(pixmap); + bo = radeon_get_pixmap_bo(pixmap); + r = radeon_gem_get_kernel_name(bo, &front->name); if (r) { (*draw->pScreen->DestroyPixmap)(pixmap); return FALSE; @@ -753,10 +834,9 @@ radeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPt { struct dri2_buffer_priv *front_priv = front->driverPrivate; struct dri2_buffer_priv *back_priv = back->driverPrivate; - struct radeon_exa_pixmap_priv *front_radeon, *back_radeon; + struct radeon_bo *front_bo, *back_bo; ScreenPtr screen; RADEONInfoPtr info; - struct radeon_bo *bo; int tmp; /* Swap BO names so DRI works */ @@ -765,22 +845,22 @@ radeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPt back->name = tmp; /* Swap pixmap bos */ - front_radeon = exaGetPixmapDriverPrivate(front_priv->pixmap); - back_radeon = exaGetPixmapDriverPrivate(back_priv->pixmap); - bo = back_radeon->bo; - back_radeon->bo = front_radeon->bo; - front_radeon->bo = bo; + front_bo = radeon_get_pixmap_bo(front_priv->pixmap); + back_bo = radeon_get_pixmap_bo(back_priv->pixmap); + radeon_set_pixmap_bo(front_priv->pixmap, back_bo); + radeon_set_pixmap_bo(back_priv->pixmap, front_bo); /* Do we need to update the Screen? */ screen = draw->pScreen; info = RADEONPTR(xf86ScreenToScrn(screen)); - if (front_radeon->bo == info->front_bo) { + if (front_bo == info->front_bo) { + radeon_bo_ref(back_bo); radeon_bo_unref(info->front_bo); - info->front_bo = back_radeon->bo; - radeon_bo_ref(info->front_bo); - front_radeon = exaGetPixmapDriverPrivate(screen->GetScreenPixmap(screen)); - front_radeon->bo = bo; + info->front_bo = back_bo; + radeon_set_pixmap_bo(screen->GetScreenPixmap(screen), back_bo); } + + radeon_glamor_exchange_buffers(front_priv->pixmap, back_priv->pixmap); } void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, diff --git a/src/radeon_exa.c b/src/radeon_exa.c index d80c7e4f..5c5d9979 100644 --- a/src/radeon_exa.c +++ b/src/radeon_exa.c @@ -325,20 +325,6 @@ void RADEONEXADestroyPixmap(ScreenPtr pScreen, void *driverPriv) free(driverPriv); } -struct radeon_bo *radeon_get_pixmap_bo(PixmapPtr pPix) -{ - struct radeon_exa_pixmap_priv *driver_priv; - driver_priv = exaGetPixmapDriverPrivate(pPix); - return driver_priv->bo; -} - -struct radeon_surface *radeon_get_pixmap_surface(PixmapPtr pPix) -{ - struct radeon_exa_pixmap_priv *driver_priv; - driver_priv = exaGetPixmapDriverPrivate(pPix); - return &driver_priv->surface; -} - uint32_t radeon_get_pixmap_tiling(PixmapPtr pPix) { struct radeon_exa_pixmap_priv *driver_priv; @@ -346,24 +332,6 @@ uint32_t radeon_get_pixmap_tiling(PixmapPtr pPix) return driver_priv->tiling_flags; } -void radeon_set_pixmap_bo(PixmapPtr pPix, struct radeon_bo *bo) -{ - struct radeon_exa_pixmap_priv *driver_priv; - - driver_priv = exaGetPixmapDriverPrivate(pPix); - if (driver_priv) { - uint32_t pitch; - - if (driver_priv->bo) - radeon_bo_unref(driver_priv->bo); - - radeon_bo_ref(bo); - driver_priv->bo = bo; - - radeon_bo_get_tiling(bo, &driver_priv->tiling_flags, &pitch); - } -} - Bool RADEONEXAPixmapIsOffscreen(PixmapPtr pPix) { struct radeon_exa_pixmap_priv *driver_priv; diff --git a/src/radeon_glamor.c b/src/radeon_glamor.c new file mode 100644 index 00000000..232332e3 --- /dev/null +++ b/src/radeon_glamor.c @@ -0,0 +1,269 @@ +/* + * Copyright © 2011 Intel Corporation. + * 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 (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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#define GLAMOR_FOR_XORG 1 +#include + +#include "radeon.h" +#include "radeon_bo_helper.h" + +#if HAS_DEVPRIVATEKEYREC +DevPrivateKeyRec glamor_pixmap_index; +#else +int glamor_pixmap_index; +#endif + +void +radeon_glamor_exchange_buffers(PixmapPtr src, + PixmapPtr dst) +{ + RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(dst->drawable.pScreen)); + + if (!info->use_glamor) + return; + glamor_egl_exchange_buffers(src, dst); +} + +Bool +radeon_glamor_create_screen_resources(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); + + if (!info->use_glamor) + return TRUE; + + if (!glamor_glyphs_init(screen)) + return FALSE; + + if (!glamor_egl_create_textured_screen_ext(screen, + info->front_bo->handle, + scrn->displayWidth * + info->pixel_bytes, + NULL)) + return FALSE; + + return TRUE; +} + + +Bool +radeon_glamor_pre_init(ScrnInfoPtr scrn) +{ + RADEONInfoPtr info = RADEONPTR(scrn); + pointer glamor_module; + CARD32 version; + const char *s; + + s = xf86GetOptValString(info->Options, OPTION_ACCELMETHOD); + if (s == NULL) + return FALSE; + + if (strcasecmp(s, "glamor") != 0) + return FALSE; + + /* Load glamor module */ + if ((glamor_module = xf86LoadSubModule(scrn, GLAMOR_EGL_MODULE_NAME))) { + version = xf86GetModuleVersion(glamor_module); + if (version < MODULE_VERSION_NUMERIC(0,3,1)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Incompatible glamor version, required >= 0.3.0.\n"); + return FALSE; + } else { + if (glamor_egl_init(scrn, info->dri2.drm_fd)) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "glamor detected, initialising EGL layer.\n"); + } else { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "glamor detected, failed to initialize EGL.\n"); + return FALSE; + } + } + } else { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, "glamor not available\n"); + return FALSE; + } + + info->use_glamor = TRUE; + + return TRUE; +} + +Bool +radeon_glamor_create_textured_pixmap(PixmapPtr pixmap) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen); + RADEONInfoPtr info = RADEONPTR(scrn); + struct radeon_pixmap *priv; + + if ((info->use_glamor) == 0) + return TRUE; + + priv = radeon_get_pixmap_private(pixmap); + if (glamor_egl_create_textured_pixmap(pixmap, priv->bo->handle, + priv->stride)) + return TRUE; + else + return FALSE; +} + +static PixmapPtr +radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth, + unsigned usage) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + struct radeon_pixmap *priv; + PixmapPtr pixmap, new_pixmap = NULL; + + if (!(usage & RADEON_CREATE_PIXMAP_DRI2)) { + pixmap = glamor_create_pixmap(screen, w, h, depth, usage); + if (pixmap) + return pixmap; + } + + if (w > 32767 || h > 32767) + return NullPixmap; + + if (depth == 1) + return fbCreatePixmap(screen, w, h, depth, usage); + + if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 32 && h <= 32) + return fbCreatePixmap(screen, w, h, depth, usage); + + pixmap = fbCreatePixmap(screen, 0, 0, depth, usage); + if (pixmap == NullPixmap) + return pixmap; + + if (w && h) { + priv = calloc(1, sizeof (struct radeon_pixmap)); + if (priv == NULL) + goto fallback_pixmap; + + priv->bo = radeon_alloc_pixmap_bo(scrn, w, h, depth, usage, + pixmap->drawable.bitsPerPixel, + &priv->stride, + &priv->surface, + &priv->tiling_flags); + if (!priv->bo) + goto fallback_priv; + + radeon_set_pixmap_private(pixmap, priv); + + screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, priv->stride, NULL); + + if (!radeon_glamor_create_textured_pixmap(pixmap)) + goto fallback_glamor; + } + + return pixmap; + +fallback_glamor: + if (usage & RADEON_CREATE_PIXMAP_DRI2) { + /* XXX need further work to handle the DRI2 failure case. + * Glamor don't know how to handle a BO only pixmap. Put + * a warning indicator here. + */ + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "Failed to create textured DRI2 pixmap."); + return pixmap; + } + /* Create textured pixmap failed means glamor failed to + * create a texture from current BO for some reasons. We turn + * to create a new glamor pixmap and clean up current one. + * One thing need to be noted, this new pixmap doesn't + * has a priv and bo attached to it. It's glamor's responsbility + * to take care of it. Glamor will mark this new pixmap as a + * texture only pixmap and will never fallback to DDX layer + * afterwards. + */ + new_pixmap = glamor_create_pixmap(screen, w, h, depth, usage); + radeon_bo_unref(priv->bo); +fallback_priv: + free(priv); +fallback_pixmap: + fbDestroyPixmap(pixmap); + if (new_pixmap) + return new_pixmap; + else + return fbCreatePixmap(screen, w, h, depth, usage); +} + +static Bool radeon_glamor_destroy_pixmap(PixmapPtr pixmap) +{ + if (pixmap->refcnt == 1) { + glamor_egl_destroy_textured_pixmap(pixmap); + radeon_set_pixmap_bo(pixmap, NULL); + } + fbDestroyPixmap(pixmap); + return TRUE; +} + +Bool +radeon_glamor_init(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + + if (!glamor_init(screen, GLAMOR_INVERTED_Y_AXIS | GLAMOR_USE_EGL_SCREEN | + GLAMOR_USE_SCREEN | GLAMOR_USE_PICTURE_SCREEN)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to initialize glamor.\n"); + return FALSE; + } + + if (!glamor_egl_init_textured_pixmap(screen)) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to initialize textured pixmap of screen for glamor.\n"); + return FALSE; + } + +#if HAS_DIXREGISTERPRIVATEKEY + if (!dixRegisterPrivateKey(&glamor_pixmap_index, PRIVATE_PIXMAP, 0)) +#else + if (!dixRequestPrivate(&glamor_pixmap_index, 0)) +#endif + return FALSE; + + screen->CreatePixmap = radeon_glamor_create_pixmap; + screen->DestroyPixmap = radeon_glamor_destroy_pixmap; + + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "Use GLAMOR acceleration.\n"); + return TRUE; +} + +void +radeon_glamor_flush(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (info->use_glamor) + glamor_block_handler(pScrn->pScreen); +} diff --git a/src/radeon_glamor.h b/src/radeon_glamor.h new file mode 100644 index 00000000..40c9092b --- /dev/null +++ b/src/radeon_glamor.h @@ -0,0 +1,93 @@ +/* + * Copyright © 2011 Intel Corporation. + * 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 (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. + */ + +#ifndef RADEON_GLAMOR_H +#define RADEON_GLAMOR_H + +#ifdef USE_GLAMOR + +#include "radeon_surface.h" + +Bool radeon_glamor_pre_init(ScrnInfoPtr scrn); +Bool radeon_glamor_init(ScreenPtr screen); +Bool radeon_glamor_create_screen_resources(ScreenPtr screen); +void radeon_glamor_free_screen(int scrnIndex, int flags); + +void radeon_glamor_flush(ScrnInfoPtr pScrn); + +Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap); +void radeon_glamor_exchange_buffers(PixmapPtr src, PixmapPtr dst); + +Bool radeon_glamor_pixmap_is_offscreen(PixmapPtr pixmap); + +struct radeon_pixmap { + struct radeon_surface surface; + struct radeon_bo *bo; + + uint32_t tiling_flags; + int stride; +}; + +#if HAS_DEVPRIVATEKEYREC +extern DevPrivateKeyRec glamor_pixmap_index; +#else +extern int glamor_pixmap_index; +#endif + +static inline struct radeon_pixmap *radeon_get_pixmap_private(PixmapPtr pixmap) +{ +#if HAS_DEVPRIVATEKEYREC + return dixGetPrivate(&pixmap->devPrivates, &glamor_pixmap_index); +#else + return dixLookupPrivate(&pixmap->devPrivates, &glamor_pixmap_index); +#endif +} + +static inline void radeon_set_pixmap_private(PixmapPtr pixmap, struct radeon_pixmap *priv) +{ + dixSetPrivate(&pixmap->devPrivates, &glamor_pixmap_index, priv); +} + +#else + +static inline Bool radeon_glamor_pre_init(ScrnInfoPtr scrn) { return FALSE; } +static inline Bool radeon_glamor_init(ScreenPtr screen) { return FALSE; } +static inline Bool radeon_glamor_create_screen_resources(ScreenPtr screen) { return FALSE; } +static inline void radeon_glamor_free_screen(int scrnIndex, int flags) { } + +static inline void radeon_glamor_flush(ScrnInfoPtr pScrn) { } + +static inline Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap) { return FALSE; } + +static inline void radeon_glamor_exchange_buffers(PixmapPtr src, PixmapPtr dst) {} + +static inline Bool radeon_glamor_pixmap_is_offscreen(PixmapPtr pixmap) { return FALSE; } + +static inline struct radeon_pixmap *radeon_get_pixmap_private(PixmapPtr pixmap) { return NULL; } + +#endif + +#endif /* RADEON_GLAMOR_H */ diff --git a/src/radeon_kms.c b/src/radeon_kms.c index 61d6419b..5d9ccff6 100644 --- a/src/radeon_kms.c +++ b/src/radeon_kms.c @@ -224,7 +224,7 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen) return FALSE; } - if (info->dri2.enabled) { + if (info->dri2.enabled || info->use_glamor) { if (info->front_bo) { PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen); radeon_set_pixmap_bo(pPix, info->front_bo); @@ -234,6 +234,10 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen) } } } + + if (info->use_glamor) + radeon_glamor_create_screen_resources(pScreen); + return TRUE; } @@ -247,6 +251,9 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL) (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS); pScreen->BlockHandler = RADEONBlockHandler_KMS; + if (info->use_glamor) + radeon_glamor_flush(pScrn); + radeon_cs_flush_indirect(pScrn); } @@ -258,6 +265,7 @@ radeon_flush_callback(CallbackListPtr *list, if (pScrn->vtSema) { radeon_cs_flush_indirect(pScrn); + radeon_glamor_flush(pScrn); } } @@ -416,6 +424,9 @@ static Bool RADEONPreInitAccel_KMS(ScrnInfoPtr pScrn) return TRUE; } + if (radeon_glamor_pre_init(pScrn)) + return TRUE; + if (info->ChipFamily == CHIP_FAMILY_PALM) { info->accel_state->allowHWDFS = RADEONIsFusionGARTWorking(pScrn); } else @@ -838,16 +849,18 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags) } } - info->exa_pixmaps = xf86ReturnOptValBool(info->Options, - OPTION_EXA_PIXMAPS, - ((info->vram_size > (32 * 1024 * 1024) && - info->RenderAccel))); - if (info->exa_pixmaps) - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "EXA: Driver will allow EXA pixmaps in VRAM\n"); - else - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "EXA: Driver will not allow EXA pixmaps in VRAM\n"); + if (!info->use_glamor) { + info->exa_pixmaps = xf86ReturnOptValBool(info->Options, + OPTION_EXA_PIXMAPS, + ((info->vram_size > (32 * 1024 * 1024) && + info->RenderAccel))); + if (info->exa_pixmaps) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "EXA: Driver will allow EXA pixmaps in VRAM\n"); + else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "EXA: Driver will not allow EXA pixmaps in VRAM\n"); + } /* no tiled scanout on r6xx+ yet */ if (info->allowColorTiling) { @@ -1186,7 +1199,7 @@ Bool RADEONScreenInit_KMS(SCREEN_INIT_ARGS_DECL) */ /* xf86DiDGAInit(pScreen, info->LinearAddr + pScrn->fbOffset); */ #endif - if (info->r600_shadow_fb == FALSE) { + if (!info->use_glamor && info->r600_shadow_fb == FALSE) { /* Init Xv */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Initializing Xv\n"); @@ -1322,7 +1335,7 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen) xf86DrvMsg(pScreen->myNum, X_ERROR, "Memory map already initialized\n"); return FALSE; } - if (info->r600_shadow_fb == FALSE) { + if (!info->use_glamor && info->r600_shadow_fb == FALSE) { info->accel_state->exa = exaDriverAlloc(); if (info->accel_state->exa == NULL) { xf86DrvMsg(pScreen->myNum, X_ERROR, "exaDriverAlloc failed\n"); -- cgit v1.2.3