summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2014-01-22 11:22:35 -0800
committerKeith Packard <keithp@keithp.com>2014-01-22 11:22:35 -0800
commit1d76b02fac79c0360ae201e4d1a8ba0e9a00e810 (patch)
tree274ee5d288b0cc66e7a4a405d48aa1b46df5e696
parent771f390efdf48cb7c44fe20857f06f8ffff3b2ce (diff)
parent4dd62d7807b47efbc9065ae8f17f73e1ec6e9d26 (diff)
Merge remote-tracking branch 'anholt/glamor-external-rebase'
-rw-r--r--glamor/Makefile.am71
-rw-r--r--glamor/compat-api.h107
-rw-r--r--glamor/compiler.h59
-rw-r--r--glamor/glamor.c628
-rw-r--r--glamor/glamor.h432
-rw-r--r--glamor/glamor_addtraps.c65
-rw-r--r--glamor/glamor_compositerects.c278
-rw-r--r--glamor/glamor_copyarea.c676
-rw-r--r--glamor/glamor_copyplane.c72
-rw-r--r--glamor/glamor_copywindow.c58
-rw-r--r--glamor/glamor_core.c612
-rw-r--r--glamor/glamor_debug.h116
-rw-r--r--glamor/glamor_egl.c860
-rw-r--r--glamor/glamor_eglmodule.c52
-rw-r--r--glamor/glamor_fbo.c590
-rw-r--r--glamor/glamor_fill.c364
-rw-r--r--glamor/glamor_fillspans.c113
-rw-r--r--glamor/glamor_getimage.c101
-rw-r--r--glamor/glamor_getspans.c95
-rw-r--r--glamor/glamor_gl_dispatch.c118
-rw-r--r--glamor/glamor_gl_dispatch.h138
-rw-r--r--glamor/glamor_glext.h64
-rw-r--r--glamor/glamor_glyphblt.c118
-rw-r--r--glamor/glamor_glyphs.c1806
-rw-r--r--glamor/glamor_gradient.c1584
-rw-r--r--glamor/glamor_largepixmap.c1324
-rw-r--r--glamor/glamor_picture.c131
-rw-r--r--glamor/glamor_pixmap.c1433
-rw-r--r--glamor/glamor_polyfillrect.c127
-rw-r--r--glamor/glamor_polylines.c135
-rw-r--r--glamor/glamor_polyops.c85
-rw-r--r--glamor/glamor_priv.h1047
-rw-r--r--glamor/glamor_putimage.c363
-rw-r--r--glamor/glamor_render.c2135
-rw-r--r--glamor/glamor_setspans.c111
-rw-r--r--glamor/glamor_tile.c325
-rw-r--r--glamor/glamor_trapezoid.c1819
-rw-r--r--glamor/glamor_triangles.c80
-rw-r--r--glamor/glamor_utils.h1835
-rw-r--r--glamor/glamor_window.c103
-rw-r--r--glamor/glamor_xv.c645
-rw-r--r--glamor/glapi.h121
42 files changed, 20996 insertions, 0 deletions
diff --git a/glamor/Makefile.am b/glamor/Makefile.am
new file mode 100644
index 000000000..2fd521f11
--- /dev/null
+++ b/glamor/Makefile.am
@@ -0,0 +1,71 @@
+lib_LTLIBRARIES = libglamor.la
+
+if GLAMOR_GLES2
+libglamor_la_LIBADD = $(GLESV2_LIBS)
+else
+libglamor_la_LIBADD = $(GL_LIBS)
+endif
+
+AM_CFLAGS = $(CWARNFLAGS) $(XORG_CFLAGS) $(LIBDRM_CFLAGS)
+
+libglamor_la_LDFLAGS = -version-info 0:0:0
+
+libglamor_la_SOURCES = \
+ compat-api.h \
+ compiler.h \
+ glamor.c \
+ glamor_copyarea.c \
+ glamor_copywindow.c \
+ glamor_core.c \
+ glamor_debug.h \
+ glamor_gl_dispatch.h \
+ glamor_fill.c \
+ glamor_fillspans.c \
+ glamor_getspans.c \
+ glamor_glext.h \
+ glamor_glyphs.c \
+ glamor_polyfillrect.c \
+ glamor_polylines.c \
+ glamor_putimage.c \
+ glamor_setspans.c \
+ glamor_render.c \
+ glamor_gradient.c \
+ glamor_trapezoid.c \
+ glamor_tile.c \
+ glamor_triangles.c\
+ glamor_addtraps.c\
+ glamor_getimage.c\
+ glamor_copyplane.c\
+ glamor_glyphblt.c\
+ glamor_polyops.c\
+ glamor_priv.h\
+ glamor_pixmap.c\
+ glamor_largepixmap.c\
+ glamor_picture.c\
+ glamor_window.c\
+ glamor_gl_dispatch.c\
+ glamor_fbo.c\
+ glamor_compositerects.c\
+ glamor_xv.c\
+ glamor_utils.h\
+ glamor.h\
+ glapi.h
+
+sdk_HEADERS = glamor.h
+
+if EGL
+LIBGLAMOREGL = libglamoregl.la
+module_LTLIBRARIES = $(LIBGLAMOREGL)
+libglamoregl_la_DEPENDENCIES = libglamor.la
+libglamoregl_la_LDFLAGS = -avoid-version -module
+libglamoregl_la_LIBADD = $(EGL_LIBS) $(GLX_SYS_LIBS) $(GBM_LIBS) libglamor.la
+libglamoregl_la_SOURCES = glamor_eglmodule.c glamor_egl.c
+libglamoregl_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(GLX_DEFINES) \
+ $(LIBDRM_CFLAGS) \
+ $(EGL_CFLAGS) \
+ $(GBM_CFLAGS)
+endif
+
+
diff --git a/glamor/compat-api.h b/glamor/compat-api.h
new file mode 100644
index 000000000..1608478f8
--- /dev/null
+++ b/glamor/compat-api.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2012 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.
+ *
+ * Author: Dave Airlie <airlied@redhat.com>
+ */
+
+/* this file provides API compat between server post 1.13 and pre it,
+ it should be reused inside as many drivers as possible */
+#ifndef COMPAT_API_H
+#define COMPAT_API_H
+
+#ifndef GLYPH_HAS_GLYPH_PICTURE_ACCESSOR
+#define GetGlyphPicture(g, s) GlyphPicture((g))[(s)->myNum]
+#define SetGlyphPicture(g, s, p) GlyphPicture((g))[(s)->myNum] = p
+#endif
+
+#ifndef XF86_HAS_SCRN_CONV
+#define xf86ScreenToScrn(s) xf86Screens[(s)->myNum]
+#define xf86ScrnToScreen(s) screenInfo.screens[(s)->scrnIndex]
+#endif
+
+#ifndef XF86_SCRN_INTERFACE
+
+#define SCRN_ARG_TYPE int
+#define SCRN_INFO_PTR(arg1) ScrnInfoPtr scrn = xf86Screens[(arg1)]
+
+#define SCREEN_ARG_TYPE int
+#define SCREEN_PTR(arg1) ScreenPtr screen = screenInfo.screens[(arg1)]
+
+#define SCREEN_INIT_ARGS_DECL int scrnIndex, ScreenPtr screen, int argc, char **argv
+
+#define BLOCKHANDLER_ARGS_DECL int arg, pointer blockData, pointer timeout, pointer read_mask
+#define BLOCKHANDLER_ARGS arg, blockData, timeout, read_mask
+
+#define WAKEUPHANDLER_ARGS_DECL int arg, pointer wakeupData, unsigned long result, pointer read_mask
+#define WAKEUPHANDLER_ARGS arg, wakeupData, result, read_mask
+
+#define CLOSE_SCREEN_ARGS_DECL int scrnIndex, ScreenPtr screen
+#define CLOSE_SCREEN_ARGS scrnIndex, screen
+
+#define ADJUST_FRAME_ARGS_DECL int arg, int x, int y, int flags
+#define ADJUST_FRAME_ARGS(arg, x, y) (arg)->scrnIndex, x, y, 0
+
+#define SWITCH_MODE_ARGS_DECL int arg, DisplayModePtr mode, int flags
+#define SWITCH_MODE_ARGS(arg, m) (arg)->scrnIndex, m, 0
+
+#define FREE_SCREEN_ARGS_DECL int arg, int flags
+#define FREE_SCREEN_ARGS arg, flags
+
+#define VT_FUNC_ARGS_DECL int arg, int flags
+#define VT_FUNC_ARGS(flags) scrn->scrnIndex, (flags)
+
+#define XF86_ENABLEDISABLEFB_ARG(x) ((x)->scrnIndex)
+
+#else
+#define SCRN_ARG_TYPE ScrnInfoPtr
+#define SCRN_INFO_PTR(arg1) ScrnInfoPtr scrn = (arg1)
+
+#define SCREEN_ARG_TYPE ScreenPtr
+#define SCREEN_PTR(arg1) ScreenPtr screen = (arg1)
+
+#define SCREEN_INIT_ARGS_DECL ScreenPtr screen, int argc, char **argv
+
+#define BLOCKHANDLER_ARGS_DECL ScreenPtr arg, pointer timeout, pointer read_mask
+#define BLOCKHANDLER_ARGS arg, timeout, read_mask
+
+#define WAKEUPHANDLER_ARGS_DECL ScreenPtr arg, unsigned long result, pointer read_mask
+#define WAKEUPHANDLER_ARGS arg, result, read_mask
+
+#define CLOSE_SCREEN_ARGS_DECL ScreenPtr screen
+#define CLOSE_SCREEN_ARGS screen
+
+#define ADJUST_FRAME_ARGS_DECL ScrnInfoPtr arg, int x, int y
+#define ADJUST_FRAME_ARGS(arg, x, y) arg, x, y
+
+#define SWITCH_MODE_ARGS_DECL ScrnInfoPtr arg, DisplayModePtr mode
+#define SWITCH_MODE_ARGS(arg, m) arg, m
+
+#define FREE_SCREEN_ARGS_DECL ScrnInfoPtr arg
+#define FREE_SCREEN_ARGS arg
+
+#define VT_FUNC_ARGS_DECL ScrnInfoPtr arg
+#define VT_FUNC_ARGS(flags) scrn
+
+#define XF86_ENABLEDISABLEFB_ARG(x) (x)
+
+#endif
+#endif
diff --git a/glamor/compiler.h b/glamor/compiler.h
new file mode 100644
index 000000000..fa2895976
--- /dev/null
+++ b/glamor/compiler.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011 Intel Corporation
+ *
+ * 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:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ * Copied from sna
+ *
+ */
+
+#ifndef _GLAMOR_COMPILER_H_
+#define _GLAMOR_COMPILER_H_
+
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define likely(expr) (__builtin_expect (!!(expr), 1))
+#define unlikely(expr) (__builtin_expect (!!(expr), 0))
+#define noinline __attribute__((noinline))
+#define fastcall __attribute__((regparm(3)))
+#define must_check __attribute__((warn_unused_result))
+#define constant __attribute__((const))
+#else
+#define likely(expr) (expr)
+#define unlikely(expr) (expr)
+#define noinline
+#define fastcall
+#define must_check
+#define constant
+#endif
+
+#ifdef HAVE_VALGRIND
+#define VG(x) x
+#else
+#define VG(x)
+#endif
+
+#define VG_CLEAR(s) VG(memset(&s, 0, sizeof(s)))
+
+#define COMPILE_TIME_ASSERT(E) ((void)sizeof(char[1 - 2*!(E)]))
+
+#endif /* _SNA_COMPILER_H_ */
diff --git a/glamor/glamor.c b/glamor/glamor.c
new file mode 100644
index 000000000..93d3c5e72
--- /dev/null
+++ b/glamor/glamor.c
@@ -0,0 +1,628 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ *
+ */
+
+/** @file glamor.c
+ * This file covers the initialization and teardown of glamor, and has various
+ * functions not responsible for performing rendering.
+ */
+
+#include <stdlib.h>
+
+#include "glamor_priv.h"
+
+static DevPrivateKeyRec glamor_screen_private_key_index;
+DevPrivateKey glamor_screen_private_key = &glamor_screen_private_key_index;
+static DevPrivateKeyRec glamor_pixmap_private_key_index;
+DevPrivateKey glamor_pixmap_private_key = &glamor_pixmap_private_key_index;
+
+/**
+ * glamor_get_drawable_pixmap() returns a backing pixmap for a given drawable.
+ *
+ * @param drawable the drawable being requested.
+ *
+ * This function returns the backing pixmap for a drawable, whether it is a
+ * redirected window, unredirected window, or already a pixmap. Note that
+ * coordinate translation is needed when drawing to the backing pixmap of a
+ * redirected window, and the translation coordinates are provided by calling
+ * exaGetOffscreenPixmap() on the drawable.
+ */
+PixmapPtr
+glamor_get_drawable_pixmap(DrawablePtr drawable)
+{
+ if (drawable->type == DRAWABLE_WINDOW)
+ return drawable->
+ pScreen->GetWindowPixmap((WindowPtr) drawable);
+ else
+ return (PixmapPtr) drawable;
+}
+
+_X_EXPORT void
+glamor_set_pixmap_type(PixmapPtr pixmap, glamor_pixmap_type_t type)
+{
+ glamor_pixmap_private *pixmap_priv;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(pixmap->drawable.pScreen);
+
+ pixmap_priv = dixLookupPrivate(&pixmap->devPrivates,
+ glamor_pixmap_private_key);
+ if (pixmap_priv == NULL) {
+ pixmap_priv = calloc(sizeof(*pixmap_priv), 1);
+ glamor_set_pixmap_private(pixmap, pixmap_priv);
+ pixmap_priv->base.pixmap = pixmap;
+ pixmap_priv->base.glamor_priv = glamor_priv;
+ }
+ pixmap_priv->type = type;
+}
+
+_X_EXPORT void
+glamor_set_pixmap_texture(PixmapPtr pixmap, unsigned int tex)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ glamor_pixmap_private *pixmap_priv;
+ glamor_screen_private *glamor_priv;
+ glamor_pixmap_fbo *fbo;
+ GLenum format;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ if (pixmap_priv->base.fbo) {
+ fbo = glamor_pixmap_detach_fbo(pixmap_priv);
+ glamor_destroy_fbo(fbo);
+ }
+
+ gl_iformat_for_depth(pixmap->drawable.depth, &format);
+ fbo = glamor_create_fbo_from_tex(glamor_priv, pixmap->drawable.width,
+ pixmap->drawable.height,
+ format, tex, 0);
+
+ if (fbo == NULL) {
+ ErrorF("XXX fail to create fbo.\n");
+ return;
+ }
+
+ glamor_pixmap_attach_fbo(pixmap, fbo);
+}
+
+void
+glamor_set_screen_pixmap(PixmapPtr screen_pixmap, PixmapPtr *back_pixmap)
+{
+ glamor_pixmap_private *pixmap_priv;
+ glamor_screen_private *glamor_priv;
+
+ glamor_priv = glamor_get_screen_private(screen_pixmap->drawable.pScreen);
+ pixmap_priv = glamor_get_pixmap_private(screen_pixmap);
+ glamor_priv->screen_fbo = pixmap_priv->base.fbo->fb;
+
+ pixmap_priv->base.fbo->width = screen_pixmap->drawable.width;
+ pixmap_priv->base.fbo->height = screen_pixmap->drawable.height;
+
+ glamor_priv->back_pixmap = back_pixmap;
+}
+
+PixmapPtr
+glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
+ unsigned int usage)
+{
+ PixmapPtr pixmap;
+ glamor_pixmap_type_t type = GLAMOR_TEXTURE_ONLY;
+ glamor_pixmap_private *pixmap_priv;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_pixmap_fbo *fbo;
+ int pitch;
+ GLenum format;
+
+ if (w > 32767 || h > 32767)
+ return NullPixmap;
+
+ if ((usage == GLAMOR_CREATE_PIXMAP_CPU
+ || (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 64 && h <= 64)
+ || (w == 0 && h == 0)
+ || !glamor_check_pixmap_fbo_depth(depth))
+ || (!GLAMOR_TEXTURED_LARGE_PIXMAP &&
+ !glamor_check_fbo_size(glamor_priv, w, h)))
+ return fbCreatePixmap(screen, w, h, depth, usage);
+ else
+ pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
+
+ pixmap_priv = calloc(1, sizeof(*pixmap_priv));
+
+ if (!pixmap_priv) {
+ fbDestroyPixmap(pixmap);
+ return fbCreatePixmap(screen, w, h, depth, usage);
+ }
+ glamor_set_pixmap_private(pixmap, pixmap_priv);
+
+ if (usage == GLAMOR_CREATE_PIXMAP_MAP)
+ type = GLAMOR_MEMORY_MAP;
+
+ pixmap_priv->base.pixmap = pixmap;
+ pixmap_priv->base.glamor_priv = glamor_priv;
+
+ gl_iformat_for_depth(depth, &format);
+
+ pitch = (((w * pixmap->drawable.bitsPerPixel + 7) / 8) + 3) & ~3;
+ screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, pitch, NULL);
+
+ if (type == GLAMOR_MEMORY_MAP || glamor_check_fbo_size(glamor_priv, w, h)) {
+ pixmap_priv->type = type;
+ fbo = glamor_create_fbo(glamor_priv, w, h, format, usage);
+ }
+ else {
+ DEBUGF("Create LARGE pixmap %p width %d height %d\n", pixmap, w, h);
+ pixmap_priv->type = GLAMOR_TEXTURE_LARGE;
+ fbo = glamor_create_fbo_array(glamor_priv, w, h, format, usage,
+ glamor_priv->max_fbo_size,
+ glamor_priv->max_fbo_size,
+ pixmap_priv);
+ }
+
+ if (fbo == NULL) {
+ fbDestroyPixmap(pixmap);
+ free(pixmap_priv);
+ return fbCreatePixmap(screen, w, h, depth, usage);
+ }
+
+ glamor_pixmap_attach_fbo(pixmap, fbo);
+
+ return pixmap;
+}
+
+void
+glamor_destroy_textured_pixmap(PixmapPtr pixmap)
+{
+ if (pixmap->refcnt == 1) {
+ glamor_pixmap_private *pixmap_priv;
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ if (pixmap_priv != NULL)
+ glamor_pixmap_destroy_fbo(pixmap_priv);
+ }
+}
+
+Bool
+glamor_destroy_pixmap(PixmapPtr pixmap)
+{
+ glamor_screen_private
+ *glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
+ if (glamor_priv->dri3_enabled)
+ glamor_egl_destroy_textured_pixmap(pixmap);
+ else
+ glamor_destroy_textured_pixmap(pixmap);
+ return fbDestroyPixmap(pixmap);
+}
+
+void
+glamor_block_handler(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ glamor_priv->tick++;
+ dispatch->glFlush();
+ glamor_fbo_expire(glamor_priv);
+ glamor_put_dispatch(glamor_priv);
+ if (glamor_priv->state == RENDER_STATE
+ && glamor_priv->render_idle_cnt++ > RENDER_IDEL_MAX) {
+ glamor_priv->state = IDLE_STATE;
+ glamor_priv->render_idle_cnt = 0;
+ }
+}
+
+static void
+_glamor_block_handler(void *data, OSTimePtr timeout,
+ void *last_select_mask)
+{
+ glamor_screen_private *glamor_priv = data;
+ glamor_gl_dispatch *dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glFlush();
+ glamor_put_dispatch(glamor_priv);
+}
+
+static void
+_glamor_wakeup_handler(void *data, int result, void *last_select_mask)
+{
+}
+
+static void
+glamor_set_debug_level(int *debug_level)
+{
+ char *debug_level_string;
+ debug_level_string = getenv("GLAMOR_DEBUG");
+ if (debug_level_string
+ && sscanf(debug_level_string, "%d", debug_level) == 1)
+ return;
+ *debug_level = 0;
+}
+
+int glamor_debug_level;
+
+/** Set up glamor for an already-configured GL context. */
+Bool
+glamor_init(ScreenPtr screen, unsigned int flags)
+{
+ glamor_screen_private *glamor_priv;
+ int gl_version;
+
+#ifdef RENDER
+ PictureScreenPtr ps = GetPictureScreenIfSet(screen);
+#endif
+ if (flags & ~GLAMOR_VALID_FLAGS) {
+ ErrorF("glamor_init: Invalid flags %x\n", flags);
+ return FALSE;
+ }
+ glamor_priv = calloc(1, sizeof(*glamor_priv));
+ if (glamor_priv == NULL)
+ return FALSE;
+
+ if (flags & GLAMOR_INVERTED_Y_AXIS) {
+ glamor_priv->yInverted = 1;
+ } else
+ glamor_priv->yInverted = 0;
+
+ if (!dixRegisterPrivateKey
+ (glamor_screen_private_key, PRIVATE_SCREEN, 0)) {
+ LogMessage(X_WARNING,
+ "glamor%d: Failed to allocate screen private\n",
+ screen->myNum);
+ goto fail;
+ }
+
+ glamor_set_screen_private(screen, glamor_priv);
+
+ if (!dixRegisterPrivateKey
+ (glamor_pixmap_private_key, PRIVATE_PIXMAP, 0)) {
+ LogMessage(X_WARNING,
+ "glamor%d: Failed to allocate pixmap private\n",
+ screen->myNum);
+ goto fail;;
+ }
+
+ gl_version = glamor_gl_get_version();
+
+#ifndef GLAMOR_GLES2
+ if (gl_version < GLAMOR_GL_VERSION_ENCODE(1, 3)) {
+ ErrorF("Require OpenGL version 1.3 or latter.\n");
+ goto fail;
+ }
+#else
+ if (gl_version < GLAMOR_GL_VERSION_ENCODE(2, 0)) {
+ ErrorF("Require Open GLES2.0 or latter.\n");
+ goto fail;
+ }
+#endif
+
+ glamor_gl_dispatch_init(screen, &glamor_priv->_dispatch, gl_version);
+
+#ifdef GLAMOR_GLES2
+ if (!glamor_gl_has_extension("GL_EXT_texture_format_BGRA8888")) {
+ ErrorF("GL_EXT_texture_format_BGRA8888 required\n");
+ goto fail;
+ }
+#endif
+
+ glamor_priv->has_pack_invert =
+ glamor_gl_has_extension("GL_MESA_pack_invert");
+ glamor_priv->has_fbo_blit =
+ glamor_gl_has_extension("GL_EXT_framebuffer_blit");
+ glamor_priv->_dispatch.glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE,
+ &glamor_priv->max_fbo_size);
+#ifdef MAX_FBO_SIZE
+ glamor_priv->max_fbo_size = MAX_FBO_SIZE;
+#endif
+
+ glamor_set_debug_level(&glamor_debug_level);
+
+#ifdef GLAMOR_GLES2
+ glamor_priv->gl_flavor = GLAMOR_GL_ES2;
+#else
+ glamor_priv->gl_flavor = GLAMOR_GL_DESKTOP;
+#endif
+ /* If we are using egl screen, call egl screen init to
+ * register correct close screen function. */
+ if (flags & GLAMOR_USE_EGL_SCREEN)
+ glamor_egl_screen_init(screen);
+
+ glamor_priv->saved_procs.close_screen = screen->CloseScreen;
+ screen->CloseScreen = glamor_close_screen;
+
+ if (flags & GLAMOR_USE_SCREEN) {
+ if (!RegisterBlockAndWakeupHandlers(_glamor_block_handler,
+ _glamor_wakeup_handler,
+ glamor_priv)) {
+ goto fail;
+ }
+
+ glamor_priv->saved_procs.create_gc = screen->CreateGC;
+ screen->CreateGC = glamor_create_gc;
+
+ glamor_priv->saved_procs.create_pixmap = screen->CreatePixmap;
+ screen->CreatePixmap = glamor_create_pixmap;
+
+ glamor_priv->saved_procs.destroy_pixmap = screen->DestroyPixmap;
+ screen->DestroyPixmap = glamor_destroy_pixmap;
+
+ glamor_priv->saved_procs.get_spans = screen->GetSpans;
+ screen->GetSpans = glamor_get_spans;
+
+ glamor_priv->saved_procs.get_image = screen->GetImage;
+ screen->GetImage = glamor_get_image;
+
+ glamor_priv->saved_procs.change_window_attributes =
+ screen->ChangeWindowAttributes;
+ screen->ChangeWindowAttributes =
+ glamor_change_window_attributes;
+
+ glamor_priv->saved_procs.copy_window = screen->CopyWindow;
+ screen->CopyWindow = glamor_copy_window;
+
+ glamor_priv->saved_procs.bitmap_to_region =
+ screen->BitmapToRegion;
+ screen->BitmapToRegion = glamor_bitmap_to_region;
+ }
+#ifdef RENDER
+ if (flags & GLAMOR_USE_PICTURE_SCREEN) {
+ glamor_priv->saved_procs.composite = ps->Composite;
+ ps->Composite = glamor_composite;
+
+
+ glamor_priv->saved_procs.trapezoids = ps->Trapezoids;
+ ps->Trapezoids = glamor_trapezoids;
+
+
+ glamor_priv->saved_procs.triangles = ps->Triangles;
+ ps->Triangles = glamor_triangles;
+
+ glamor_priv->saved_procs.addtraps = ps->AddTraps;
+ ps->AddTraps = glamor_add_traps;
+
+ }
+
+ glamor_priv->saved_procs.composite_rects = ps->CompositeRects;
+ ps->CompositeRects = glamor_composite_rectangles;
+
+ glamor_priv->saved_procs.glyphs = ps->Glyphs;
+ ps->Glyphs = glamor_glyphs;
+
+ glamor_priv->saved_procs.unrealize_glyph = ps->UnrealizeGlyph;
+ ps->UnrealizeGlyph = glamor_glyph_unrealize;
+
+ glamor_priv->saved_procs.create_picture = ps->CreatePicture;
+ ps->CreatePicture = glamor_create_picture;
+
+ glamor_priv->saved_procs.set_window_pixmap = screen->SetWindowPixmap;
+ screen->SetWindowPixmap = glamor_set_window_pixmap;
+
+ glamor_priv->saved_procs.destroy_picture = ps->DestroyPicture;
+ ps->DestroyPicture = glamor_destroy_picture;
+ glamor_init_composite_shaders(screen);
+#endif
+ glamor_init_pixmap_fbo(screen);
+ glamor_init_solid_shader(screen);
+ glamor_init_tile_shader(screen);
+#ifdef GLAMOR_TRAPEZOID_SHADER
+ glamor_init_trapezoid_shader(screen);
+#endif
+ glamor_init_putimage_shaders(screen);
+ glamor_init_finish_access_shaders(screen);
+#ifdef GLAMOR_GRADIENT_SHADER
+ glamor_init_gradient_shader(screen);
+#endif
+#ifdef GLAMOR_XV
+ glamor_init_xv_shader(screen);
+#endif
+ glamor_pixmap_init(screen);
+
+ glamor_priv->flags = flags;
+ glamor_priv->screen = screen;
+
+ return TRUE;
+
+ fail:
+ free(glamor_priv);
+ glamor_set_screen_private(screen, NULL);
+ return FALSE;
+}
+
+static void
+glamor_release_screen_priv(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+
+ glamor_priv = glamor_get_screen_private(screen);
+#ifdef GLAMOR_XV
+ glamor_fini_xv_shader(screen);
+#endif
+#ifdef RENDER
+ glamor_fini_composite_shaders(screen);
+#endif
+ glamor_fini_pixmap_fbo(screen);
+ glamor_fini_solid_shader(screen);
+ glamor_fini_tile_shader(screen);
+#ifdef GLAMOR_TRAPEZOID_SHADER
+ glamor_fini_trapezoid_shader(screen);
+#endif
+ glamor_fini_putimage_shaders(screen);
+ glamor_fini_finish_access_shaders(screen);
+#ifdef GLAMOR_GRADIENT_SHADER
+ glamor_fini_gradient_shader(screen);
+#endif
+ glamor_pixmap_fini(screen);
+ free(glamor_priv);
+
+ glamor_set_screen_private(screen, NULL);
+}
+
+_X_EXPORT void
+glamor_set_pixmap_private(PixmapPtr pixmap, glamor_pixmap_private *priv)
+{
+ glamor_pixmap_private *old_priv;
+ glamor_pixmap_fbo *fbo;
+
+ old_priv = dixGetPrivate(&pixmap->devPrivates, glamor_pixmap_private_key);
+
+ if (priv) {
+ assert(old_priv == NULL);
+ } else {
+ if (old_priv == NULL)
+ return;
+ fbo = glamor_pixmap_detach_fbo(old_priv);
+ glamor_purge_fbo(fbo);
+ free(old_priv);
+ }
+
+ dixSetPrivate(&pixmap->devPrivates,
+ glamor_pixmap_private_key,
+ priv);
+}
+
+Bool
+glamor_close_screen(CLOSE_SCREEN_ARGS_DECL)
+{
+ glamor_screen_private *glamor_priv;
+ PixmapPtr screen_pixmap;
+ int flags;
+#ifdef RENDER
+ PictureScreenPtr ps = GetPictureScreenIfSet(screen);
+#endif
+ glamor_priv = glamor_get_screen_private(screen);
+ flags = glamor_priv->flags;
+ glamor_glyphs_fini(screen);
+ screen->CloseScreen = glamor_priv->saved_procs.close_screen;
+ if (flags & GLAMOR_USE_SCREEN) {
+
+ screen->CreateGC = glamor_priv->saved_procs.create_gc;
+ screen->CreatePixmap = glamor_priv->saved_procs.create_pixmap;
+ screen->DestroyPixmap = glamor_priv->saved_procs.destroy_pixmap;
+ screen->GetSpans = glamor_priv->saved_procs.get_spans;
+ screen->ChangeWindowAttributes =
+ glamor_priv->saved_procs.change_window_attributes;
+ screen->CopyWindow = glamor_priv->saved_procs.copy_window;
+ screen->BitmapToRegion = glamor_priv->saved_procs.bitmap_to_region;
+ }
+#ifdef RENDER
+ if (ps && (flags & GLAMOR_USE_PICTURE_SCREEN)) {
+
+ ps->Composite = glamor_priv->saved_procs.composite;
+ ps->Trapezoids = glamor_priv->saved_procs.trapezoids;
+ ps->Triangles = glamor_priv->saved_procs.triangles;
+ ps->CreatePicture = glamor_priv->saved_procs.create_picture;
+ }
+ ps->CompositeRects = glamor_priv->saved_procs.composite_rects;
+ ps->Glyphs = glamor_priv->saved_procs.glyphs;
+ ps->UnrealizeGlyph = glamor_priv->saved_procs.unrealize_glyph;
+ screen->SetWindowPixmap = glamor_priv->saved_procs.set_window_pixmap;
+#endif
+ screen_pixmap = screen->GetScreenPixmap(screen);
+ glamor_set_pixmap_private(screen_pixmap, NULL);
+ if (glamor_priv->back_pixmap && *glamor_priv->back_pixmap)
+ glamor_set_pixmap_private(*glamor_priv->back_pixmap, NULL);
+
+ glamor_release_screen_priv(screen);
+
+ return screen->CloseScreen(CLOSE_SCREEN_ARGS);
+}
+
+
+void
+glamor_fini(ScreenPtr screen)
+{
+ /* Do nothing currently. */
+}
+
+void glamor_enable_dri3(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_priv->dri3_enabled = TRUE;
+}
+
+Bool glamor_is_dri3_support_enabled(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ return glamor_priv->dri3_enabled;
+}
+
+int
+glamor_dri3_fd_from_pixmap (ScreenPtr screen,
+ PixmapPtr pixmap,
+ CARD16 *stride,
+ CARD32 *size)
+{
+ glamor_pixmap_private *pixmap_priv;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(pixmap->drawable.pScreen);
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ if (pixmap_priv == NULL || !glamor_priv->dri3_enabled)
+ return -1;
+ switch (pixmap_priv->type)
+ {
+ case GLAMOR_TEXTURE_DRM:
+ case GLAMOR_TEXTURE_ONLY:
+ glamor_pixmap_ensure_fbo(pixmap, GL_RGBA, 0);
+ return glamor_egl_dri3_fd_name_from_tex(screen,
+ pixmap,
+ pixmap_priv->base.fbo->tex,
+ FALSE,
+ stride,
+ size);
+ default: break;
+ }
+ return -1;
+}
+
+int
+glamor_dri3_name_from_pixmap (PixmapPtr pixmap)
+{
+ glamor_pixmap_private *pixmap_priv;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(pixmap->drawable.pScreen);
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ if (pixmap_priv == NULL || !glamor_priv->dri3_enabled)
+ return -1;
+ switch (pixmap_priv->type)
+ {
+ case GLAMOR_TEXTURE_DRM:
+ case GLAMOR_TEXTURE_ONLY:
+ glamor_pixmap_ensure_fbo(pixmap, GL_RGBA, 0);
+ return glamor_egl_dri3_fd_name_from_tex(pixmap->drawable.pScreen,
+ pixmap,
+ pixmap_priv->base.fbo->tex,
+ TRUE,
+ NULL,
+ NULL);
+ default: break;
+ }
+ return -1;
+}
diff --git a/glamor/glamor.h b/glamor/glamor.h
new file mode 100644
index 000000000..1bb48ed74
--- /dev/null
+++ b/glamor/glamor.h
@@ -0,0 +1,432 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ *
+ */
+
+#ifndef GLAMOR_H
+#define GLAMOR_H
+
+#include <scrnintstr.h>
+#include <xf86.h>
+#include <xf86str.h>
+#include <pixmapstr.h>
+#include <gcstruct.h>
+#include <picturestr.h>
+#include <fb.h>
+#include <fbpict.h>
+#include <xf86xv.h>
+/*
+ * glamor_pixmap_type : glamor pixmap's type.
+ * @MEMORY: pixmap is in memory.
+ * @TEXTURE_DRM: pixmap is in a texture created from a DRM buffer.
+ * @SEPARATE_TEXTURE: The texture is created from a DRM buffer, but
+ * the format is incompatible, so this type of pixmap
+ * will never fallback to DDX layer.
+ * @DRM_ONLY: pixmap is in a external DRM buffer.
+ * @TEXTURE_ONLY: pixmap is in an internal texture.
+ */
+typedef enum glamor_pixmap_type {
+ GLAMOR_MEMORY,
+ GLAMOR_MEMORY_MAP,
+ GLAMOR_TEXTURE_DRM,
+ GLAMOR_SEPARATE_TEXTURE,
+ GLAMOR_DRM_ONLY,
+ GLAMOR_TEXTURE_ONLY,
+ GLAMOR_TEXTURE_LARGE,
+ GLAMOR_TEXTURE_PACK
+} glamor_pixmap_type_t;
+
+#define GLAMOR_EGL_EXTERNAL_BUFFER 3
+#define GLAMOR_INVERTED_Y_AXIS 1
+#define GLAMOR_USE_SCREEN (1 << 1)
+#define GLAMOR_USE_PICTURE_SCREEN (1 << 2)
+#define GLAMOR_USE_EGL_SCREEN (1 << 3)
+#define GLAMOR_VALID_FLAGS (GLAMOR_INVERTED_Y_AXIS \
+ | GLAMOR_USE_SCREEN \
+ | GLAMOR_USE_PICTURE_SCREEN \
+ | GLAMOR_USE_EGL_SCREEN)
+
+/* @glamor_init: Initialize glamor internal data structure.
+ *
+ * @screen: Current screen pointer.
+ * @flags: Please refer the flags description above.
+ *
+ * @GLAMOR_INVERTED_Y_AXIS:
+ * set 1 means the GL env's origin (0,0) is at top-left.
+ * EGL/DRM platform is an example need to set this bit.
+ * glx platform's origin is at bottom-left thus need to
+ * clear this bit.
+ *
+ * @GLAMOR_USE_SCREEN:
+ * If running in an pre-existing X environment, and the
+ * gl context is GLX, then you should set this bit and
+ * let the glamor to handle all the screen related
+ * functions such as GC ops and CreatePixmap/DestroyPixmap.
+ *
+ * @GLAMOR_USE_PICTURE_SCREEN:
+ * If don't use any other underlying DDX driver to handle
+ * the picture related rendering functions, please set this
+ * bit on. Otherwise, clear this bit. And then it is the DDX
+ * driver's responsibility to determine how/when to jump to
+ * glamor's picture compositing path.
+ *
+ * @GLAMOR_USE_EGL_SCREEN:
+ * If you are using EGL layer, then please set this bit
+ * on, otherwise, clear it.
+ *
+ * This function initializes necessary internal data structure
+ * for glamor. And before calling into this function, the OpenGL
+ * environment should be ready. Should be called before any real
+ * glamor rendering or texture allocation functions. And should
+ * be called after the DDX's screen initialization or at the last
+ * step of the DDX's screen initialization.
+ */
+extern _X_EXPORT Bool glamor_init(ScreenPtr screen, unsigned int flags);
+extern _X_EXPORT void glamor_fini(ScreenPtr screen);
+
+/* This function is used to free the glamor private screen's
+ * resources. If the DDX driver is not set GLAMOR_USE_SCREEN,
+ * then, DDX need to call this function at proper stage, if
+ * it is the xorg DDX driver,then it should be called at free
+ * screen stage not the close screen stage. The reason is after
+ * call to this function, the xorg DDX may need to destroy the
+ * screen pixmap which must be a glamor pixmap and requires
+ * the internal data structure still exist at that time.
+ * Otherwise, the glamor internal structure will not be freed.*/
+#ifndef XF86_SCRN_INTERFACE
+extern _X_EXPORT Bool glamor_close_screen(int scrnIndex, ScreenPtr screen);
+#else
+extern _X_EXPORT Bool glamor_close_screen(ScreenPtr screen);
+#endif
+
+
+/* Let glamor to know the screen's fbo. The low level
+ * driver should already assign a tex
+ * to this pixmap through the set_pixmap_texture. */
+extern _X_EXPORT void glamor_set_screen_pixmap(PixmapPtr screen_pixmap, PixmapPtr *back_pixmap);
+
+/* @glamor_glyphs_init: Initialize glyphs internal data structures.
+ *
+ * @pScreen: Current screen pointer.
+ *
+ * This function must be called after the glamor_init and the texture
+ * can be allocated. An example is to call it when create the screen
+ * resources at DDX layer.
+ */
+extern _X_EXPORT Bool glamor_glyphs_init(ScreenPtr pScreen);
+
+extern _X_EXPORT void glamor_set_pixmap_texture(PixmapPtr pixmap,
+ unsigned int tex);
+
+extern _X_EXPORT void glamor_set_pixmap_type(PixmapPtr pixmap, glamor_pixmap_type_t type);
+extern _X_EXPORT void glamor_destroy_textured_pixmap(PixmapPtr pixmap);
+extern _X_EXPORT void glamor_block_handler(ScreenPtr screen);
+extern _X_EXPORT PixmapPtr glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
+ unsigned int usage);
+
+extern _X_EXPORT void glamor_egl_screen_init(ScreenPtr screen);
+
+extern _X_EXPORT void glamor_egl_make_current(ScreenPtr screen);
+extern _X_EXPORT void glamor_egl_restore_context(ScreenPtr screen);
+
+/* @glamor_egl_exchange_buffers: Exchange the underlying buffers(KHR image,fbo).
+ *
+ * @front: front pixmap.
+ * @back: back pixmap.
+ *
+ * Used by the DRI2 page flip. This function will exchange the KHR images and
+ * fbos of the two pixmaps.
+ * */
+extern _X_EXPORT void glamor_egl_exchange_buffers(PixmapPtr front, PixmapPtr back);
+
+extern _X_EXPORT void glamor_pixmap_exchange_fbos(PixmapPtr front, PixmapPtr back);
+
+/* The DDX is not supposed to call these three functions */
+extern _X_EXPORT void glamor_enable_dri3(ScreenPtr screen);
+extern _X_EXPORT unsigned int glamor_egl_create_argb8888_based_texture(ScreenPtr screen, int w, int h);
+extern _X_EXPORT int glamor_egl_dri3_fd_name_from_tex(ScreenPtr, PixmapPtr, unsigned int, Bool, CARD16*, CARD32*);
+
+/* @glamor_is_dri3_support_enabled: Returns if DRI3 support is enabled.
+ *
+ * @screen: Current screen pointer.
+ *
+ * To have DRI3 support enabled, glamor and glamor_egl need to be initialized,
+ * and glamor_egl_init_textured_pixmap need to be called. glamor also
+ * has to be compiled with gbm support.
+ * The EGL layer need to have the following extensions working:
+ * .EGL_KHR_gl_texture_2D_image
+ * .EGL_EXT_image_dma_buf_import
+ * If DRI3 support is not enabled, the following helpers will return an error.
+ * */
+extern _X_EXPORT Bool glamor_is_dri3_support_enabled(ScreenPtr screen);
+
+/* @glamor_dri3_fd_from_pixmap: DRI3 helper to get a dma-buf fd from a pixmap.
+ *
+ * @screen: Current screen pointer.
+ * @pixmap: The pixmap from which we want the fd.
+ * @stride, @size: Pointers to fill the stride and size of the
+ * buffer associated to the fd.
+ *
+ * the pixmap and the buffer associated by the fd will share the same
+ * content.
+ * Returns the fd on success, -1 on error.
+ * */
+extern _X_EXPORT int glamor_dri3_fd_from_pixmap (ScreenPtr screen,
+ PixmapPtr pixmap,
+ CARD16 *stride,
+ CARD32 *size);
+
+/* @glamor_dri3_name_from_pixmap: helper to get an gem name from a pixmap.
+ *
+ * @pixmap: The pixmap from which we want the gem name.
+ *
+ * the pixmap and the buffer associated by the gem name will share the same
+ * content. This function can be used by the DDX to support DRI2, but needs
+ * glamor DRI3 support to be activated.
+ * Returns the name on success, -1 on error.
+ * */
+extern _X_EXPORT int glamor_dri3_name_from_pixmap (PixmapPtr pixmap);
+
+/* @glamor_egl_dri3_pixmap_from_fd: DRI3 helper to get a pixmap from a dma-buf fd.
+ *
+ * @screen: Current screen pointer.
+ * @fd: The dma-buf fd to import.
+ * @width: The width of the buffer.
+ * @height: The height of the buffer.
+ * @stride: The stride of the buffer.
+ * @depth: The depth of the buffer.
+ * @bpp: The number of bpp of the buffer.
+ *
+ * Returns a valid pixmap if the import succeeded, else NULL.
+ * */
+extern _X_EXPORT PixmapPtr glamor_egl_dri3_pixmap_from_fd (ScreenPtr screen,
+ int fd,
+ CARD16 width,
+ CARD16 height,
+ CARD16 stride,
+ CARD8 depth,
+ CARD8 bpp);
+
+#ifdef GLAMOR_FOR_XORG
+
+#define GLAMOR_EGL_MODULE_NAME "glamoregl"
+
+/* @glamor_egl_init: Initialize EGL environment.
+ *
+ * @scrn: Current screen info pointer.
+ * @fd: Current drm fd.
+ *
+ * This function creates and intialize EGL contexts.
+ * Should be called from DDX's preInit function.
+ * Return TRUE if success, otherwise return FALSE.
+ * */
+extern _X_EXPORT Bool glamor_egl_init(ScrnInfoPtr scrn, int fd);
+
+/* @glamor_egl_init_textured_pixmap: Initialization for textured pixmap allocation.
+ *
+ * @screen: Current screen pointer.
+ *
+ * This function must be called before any textured pixmap's creation including
+ * the screen pixmap. Could be called from DDX's screenInit function after the calling
+ * to glamor_init..
+ */
+extern _X_EXPORT Bool glamor_egl_init_textured_pixmap(ScreenPtr screen);
+
+/* @glamor_egl_create_textured_screen: Create textured screen pixmap.
+ *
+ * @screen: screen pointer to be processed.
+ * @handle: screen pixmap's BO handle.
+ * @stride: screen pixmap's stride in bytes.
+ *
+ * This function is similar with the create_textured_pixmap. As the
+ * screen pixmap is a special, we handle it separately in this function.
+ */
+extern _X_EXPORT Bool glamor_egl_create_textured_screen(ScreenPtr screen,
+ int handle,
+ int stride);
+
+/* @glamor_egl_create_textured_screen_ext:
+ *
+ * extent one parameter to track the pointer of the DDX layer's back pixmap.
+ * We need this pointer during the closing screen stage. As before back to
+ * the DDX's close screen, we have to free all the glamor related resources.
+ */
+extern _X_EXPORT Bool glamor_egl_create_textured_screen_ext(ScreenPtr screen,
+ int handle,
+ int stride,
+ PixmapPtr *back_pixmap);
+
+/*
+ * @glamor_egl_create_textured_pixmap: Try to create a textured pixmap from
+ * a BO handle.
+ *
+ * @pixmap: The pixmap need to be processed.
+ * @handle: The BO's handle attached to this pixmap at DDX layer.
+ * @stride: Stride in bytes for this pixmap.
+ *
+ * This function try to create a texture from the handle and attach
+ * the texture to the pixmap , thus glamor can render to this pixmap
+ * as well. Return true if successful, otherwise return FALSE.
+ */
+extern _X_EXPORT Bool glamor_egl_create_textured_pixmap(PixmapPtr pixmap,
+ int handle,
+ int stride);
+
+/*
+ * @glamor_egl_create_textured_pixmap_from_bo: Try to create a textured pixmap
+ * from a gbm_bo.
+ *
+ * @pixmap: The pixmap need to be processed.
+ * @bo: a pointer on a gbm_bo structure attached to this pixmap at DDX layer.
+ *
+ * This function is similar to glamor_egl_create_textured_pixmap.
+ */
+extern _X_EXPORT Bool
+ glamor_egl_create_textured_pixmap_from_gbm_bo(PixmapPtr pixmap,
+ void *bo);
+
+#endif
+
+extern _X_EXPORT void glamor_egl_destroy_textured_pixmap(PixmapPtr pixmap);
+
+extern _X_EXPORT int glamor_create_gc(GCPtr gc);
+
+extern _X_EXPORT void glamor_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable);
+/* Glamor rendering/drawing functions with XXX_nf.
+ * nf means no fallback within glamor internal if possible. If glamor
+ * fail to accelerate the operation, glamor will return a false, and the
+ * caller need to implement fallback method. Return a true means the
+ * rendering request get done successfully. */
+extern _X_EXPORT Bool glamor_fill_spans_nf(DrawablePtr drawable,
+ GCPtr gc,
+ int n, DDXPointPtr points,
+ int *widths, int sorted);
+
+extern _X_EXPORT Bool glamor_poly_fill_rect_nf(DrawablePtr drawable,
+ GCPtr gc,
+ int nrect,
+ xRectangle * prect);
+
+extern _X_EXPORT Bool glamor_put_image_nf(DrawablePtr drawable,
+ GCPtr gc, int depth, int x, int y,
+ int w, int h, int left_pad,
+ int image_format, char *bits);
+
+extern _X_EXPORT Bool glamor_copy_n_to_n_nf(DrawablePtr src,
+ DrawablePtr dst,
+ GCPtr gc,
+ BoxPtr box,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown, Pixel bitplane,
+ void *closure);
+
+extern _X_EXPORT Bool glamor_composite_nf(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ INT16 x_source,
+ INT16 y_source,
+ INT16 x_mask,
+ INT16 y_mask,
+ INT16 x_dest, INT16 y_dest,
+ CARD16 width, CARD16 height);
+
+extern _X_EXPORT Bool glamor_trapezoids_nf(CARD8 op,
+ PicturePtr src, PicturePtr dst,
+ PictFormatPtr mask_format,
+ INT16 x_src, INT16 y_src,
+ int ntrap, xTrapezoid * traps);
+
+extern _X_EXPORT Bool glamor_glyphs_nf(CARD8 op,
+ PicturePtr src,
+ PicturePtr dst,
+ PictFormatPtr mask_format,
+ INT16 x_src,
+ INT16 y_src, int nlist,
+ GlyphListPtr list, GlyphPtr * glyphs);
+
+extern _X_EXPORT Bool glamor_triangles_nf(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc, INT16 ySrc,
+ int ntris, xTriangle * tris);
+
+
+extern _X_EXPORT void glamor_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph);
+
+extern _X_EXPORT Bool glamor_set_spans_nf(DrawablePtr drawable, GCPtr gc, char *src,
+ DDXPointPtr points, int *widths, int n, int sorted);
+
+extern _X_EXPORT Bool glamor_get_spans_nf(DrawablePtr drawable, int wmax,
+ DDXPointPtr points, int *widths, int count, char *dst);
+
+extern _X_EXPORT Bool glamor_composite_rects_nf (CARD8 op,
+ PicturePtr pDst,
+ xRenderColor *color,
+ int nRect,
+ xRectangle *rects);
+
+extern _X_EXPORT Bool glamor_get_image_nf(DrawablePtr pDrawable, int x, int y, int w, int h,
+ unsigned int format, unsigned long planeMask, char *d);
+
+extern _X_EXPORT Bool glamor_add_traps_nf(PicturePtr pPicture,
+ INT16 x_off,
+ INT16 y_off, int ntrap, xTrap * traps);
+
+extern _X_EXPORT Bool glamor_copy_plane_nf(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty,
+ unsigned long bitPlane, RegionPtr *pRegion);
+
+extern _X_EXPORT Bool glamor_image_glyph_blt_nf(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr * ppci, pointer pglyphBase);
+
+extern _X_EXPORT Bool glamor_poly_glyph_blt_nf(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr * ppci, pointer pglyphBase);
+
+extern _X_EXPORT Bool glamor_push_pixels_nf(GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable, int w, int h, int x, int y);
+
+extern _X_EXPORT Bool glamor_poly_point_nf(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt);
+
+extern _X_EXPORT Bool glamor_poly_segment_nf(DrawablePtr pDrawable, GCPtr pGC, int nseg,
+ xSegment *pSeg);
+
+extern _X_EXPORT Bool glamor_poly_line_nf(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt);
+
+extern _X_EXPORT Bool glamor_poly_lines_nf(DrawablePtr drawable, GCPtr gc, int mode, int n,
+ DDXPointPtr points);
+
+extern _X_EXPORT XF86VideoAdaptorPtr glamor_xv_init(ScreenPtr pScreen, int num_texture_ports);
+
+#endif /* GLAMOR_H */
diff --git a/glamor/glamor_addtraps.c b/glamor/glamor_addtraps.c
new file mode 100644
index 000000000..ac852963c
--- /dev/null
+++ b/glamor/glamor_addtraps.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@gmail.com>
+ *
+ */
+
+#include "glamor_priv.h"
+
+static Bool
+_glamor_add_traps(PicturePtr pPicture,
+ INT16 x_off,
+ INT16 y_off, int ntrap, xTrap * traps,
+ Bool fallback)
+{
+ if (!fallback
+ && ( !pPicture->pDrawable
+ || glamor_ddx_fallback_check_pixmap(pPicture->pDrawable)))
+ return FALSE;
+
+ if (glamor_prepare_access_picture(pPicture, GLAMOR_ACCESS_RW)) {
+ fbAddTraps(pPicture, x_off, y_off, ntrap, traps);
+ glamor_finish_access_picture(pPicture, GLAMOR_ACCESS_RW);
+ }
+
+ return TRUE;
+}
+
+void
+glamor_add_traps(PicturePtr pPicture,
+ INT16 x_off,
+ INT16 y_off, int ntrap, xTrap * traps)
+{
+ _glamor_add_traps(pPicture, x_off, y_off, ntrap, traps, TRUE);
+}
+
+Bool
+glamor_add_traps_nf(PicturePtr pPicture,
+ INT16 x_off,
+ INT16 y_off, int ntrap, xTrap * traps)
+{
+ return _glamor_add_traps(pPicture, x_off, y_off, ntrap, traps, FALSE);
+}
+
diff --git a/glamor/glamor_compositerects.c b/glamor/glamor_compositerects.c
new file mode 100644
index 000000000..1a5769958
--- /dev/null
+++ b/glamor/glamor_compositerects.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ *
+ * original author is Chris Wilson at sna.
+ *
+ */
+
+#include "glamor_priv.h"
+#include "mipict.h"
+#include "damage.h"
+
+/** @file glamor_compositerects.
+ *
+ * compositeRects acceleration implementation
+ */
+
+static int16_t bound(int16_t a, uint16_t b)
+{
+ int v = (int)a + (int)b;
+ if (v > MAXSHORT)
+ return MAXSHORT;
+ return v;
+}
+
+static Bool
+_pixman_region_init_clipped_rectangles(pixman_region16_t *region,
+ unsigned int num_rects,
+ xRectangle *rects,
+ int tx, int ty,
+ BoxPtr extents)
+{
+ pixman_box16_t stack_boxes[64], *boxes = stack_boxes;
+ pixman_bool_t ret;
+ unsigned int i, j;
+
+ if (num_rects > ARRAY_SIZE(stack_boxes)) {
+ boxes = malloc(sizeof(pixman_box16_t) * num_rects);
+ if (boxes == NULL)
+ return FALSE;
+ }
+
+ for (i = j = 0; i < num_rects; i++) {
+ boxes[j].x1 = rects[i].x + tx;
+ if (boxes[j].x1 < extents->x1)
+ boxes[j].x1 = extents->x1;
+
+ boxes[j].y1 = rects[i].y + ty;
+ if (boxes[j].y1 < extents->y1)
+ boxes[j].y1 = extents->y1;
+
+ boxes[j].x2 = bound(rects[i].x + tx, rects[i].width);
+ if (boxes[j].x2 > extents->x2)
+ boxes[j].x2 = extents->x2;
+
+ boxes[j].y2 = bound(rects[i].y + ty, rects[i].height);
+ if (boxes[j].y2 > extents->y2)
+ boxes[j].y2 = extents->y2;
+
+ if (boxes[j].x2 > boxes[j].x1 && boxes[j].y2 > boxes[j].y1)
+ j++;
+ }
+
+ ret = FALSE;
+ if (j)
+ ret = pixman_region_init_rects(region, boxes, j);
+
+ if (boxes != stack_boxes)
+ free(boxes);
+
+ DEBUGF("%s: nrects=%d, region=(%d, %d), (%d, %d) x %d\n",
+ __FUNCTION__, num_rects,
+ region->extents.x1, region->extents.y1,
+ region->extents.x2, region->extents.y2,
+ j);
+ return ret;
+}
+
+
+void
+glamor_composite_rectangles(CARD8 op,
+ PicturePtr dst,
+ xRenderColor *color,
+ int num_rects,
+ xRectangle *rects)
+{
+ PixmapPtr pixmap;
+ struct glamor_pixmap_private *priv;
+ pixman_region16_t region;
+ pixman_box16_t *boxes;
+ int dst_x, dst_y;
+ int num_boxes;
+ PicturePtr source = NULL;
+ Bool need_free_region = FALSE;
+
+ DEBUGF("%s(op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n",
+ __FUNCTION__, op,
+ (color->alpha >> 8 << 24) |
+ (color->red >> 8 << 16) |
+ (color->green >> 8 << 8) |
+ (color->blue >> 8 << 0),
+ num_rects,
+ rects[0].x, rects[0].y, rects[0].width, rects[0].height);
+
+ if (!num_rects)
+ return;
+
+ if (region_is_empty(dst->pCompositeClip)) {
+ DEBUGF("%s: empty clip, skipping\n", __FUNCTION__);
+ return;
+ }
+
+ if ((color->red|color->green|color->blue|color->alpha) <= 0x00ff) {
+ switch (op) {
+ case PictOpOver:
+ case PictOpOutReverse:
+ case PictOpAdd:
+ return;
+ case PictOpInReverse:
+ case PictOpSrc:
+ op = PictOpClear;
+ break;
+ case PictOpAtopReverse:
+ op = PictOpOut;
+ break;
+ case PictOpXor:
+ op = PictOpOverReverse;
+ break;
+ }
+ }
+ if (color->alpha <= 0x00ff) {
+ switch (op) {
+ case PictOpOver:
+ case PictOpOutReverse:
+ return;
+ case PictOpInReverse:
+ op = PictOpClear;
+ break;
+ case PictOpAtopReverse:
+ op = PictOpOut;
+ break;
+ case PictOpXor:
+ op = PictOpOverReverse;
+ break;
+ }
+ } else if (color->alpha >= 0xff00) {
+ switch (op) {
+ case PictOpOver:
+ op = PictOpSrc;
+ break;
+ case PictOpInReverse:
+ return;
+ case PictOpOutReverse:
+ op = PictOpClear;
+ break;
+ case PictOpAtopReverse:
+ op = PictOpOverReverse;
+ break;
+ case PictOpXor:
+ op = PictOpOut;
+ break;
+ }
+ }
+ DEBUGF("%s: converted to op %d\n", __FUNCTION__, op);
+
+ if (!_pixman_region_init_clipped_rectangles(&region,
+ num_rects, rects,
+ dst->pDrawable->x,
+ dst->pDrawable->y,
+ &dst->pCompositeClip->extents))
+ {
+ DEBUGF("%s: allocation failed for region\n", __FUNCTION__);
+ return;
+ }
+
+ pixmap = glamor_get_drawable_pixmap(dst->pDrawable);
+ priv = glamor_get_pixmap_private(pixmap);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv))
+ goto fallback;
+ if (dst->alphaMap) {
+ DEBUGF("%s: fallback, dst has an alpha-map\n", __FUNCTION__);
+ goto fallback;
+ }
+
+ need_free_region = TRUE;
+
+ DEBUGF("%s: drawable extents (%d, %d),(%d, %d) x %d\n",
+ __FUNCTION__,
+ RegionExtents(&region)->x1, RegionExtents(&region)->y1,
+ RegionExtents(&region)->x2, RegionExtents(&region)->y2,
+ RegionNumRects(&region));
+
+ if (dst->pCompositeClip->data &&
+ (!pixman_region_intersect(&region, &region, dst->pCompositeClip) ||
+ region_is_empty(&region))) {
+ DEBUGF("%s: zero-intersection between rectangles and clip\n",
+ __FUNCTION__);
+ pixman_region_fini(&region);
+ return;
+ }
+
+ DEBUGF("%s: clipped extents (%d, %d),(%d, %d) x %d\n",
+ __FUNCTION__,
+ RegionExtents(&region)->x1, RegionExtents(&region)->y1,
+ RegionExtents(&region)->x2, RegionExtents(&region)->y2,
+ RegionNumRects(&region));
+
+ glamor_get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y);
+ pixman_region_translate(&region, dst_x, dst_y);
+
+ DEBUGF("%s: pixmap +(%d, %d) extents (%d, %d),(%d, %d)\n",
+ __FUNCTION__, dst_x, dst_y,
+ RegionExtents(&region)->x1, RegionExtents(&region)->y1,
+ RegionExtents(&region)->x2, RegionExtents(&region)->y2);
+
+
+ boxes = pixman_region_rectangles(&region, &num_boxes);
+ if (op == PictOpSrc || op == PictOpClear) {
+ CARD32 pixel;
+ if (op == PictOpClear)
+ pixel = 0;
+ else
+ miRenderColorToPixel(dst->pFormat, color, &pixel);
+ glamor_solid_boxes(pixmap, boxes, num_boxes, pixel);
+
+ goto done;
+ } else {
+ if (likely(priv->type != GLAMOR_TEXTURE_LARGE)) {
+ int error;
+
+ source = CreateSolidPicture(0, color, &error);
+ if (!source)
+ goto done;
+ if (glamor_composite_clipped_region(op, source,
+ NULL, dst,
+ NULL, NULL, priv,
+ &region,
+ 0,0,0,0,0,0))
+ goto done;
+ }
+ }
+fallback:
+ miCompositeRects(op, dst, color, num_rects, rects);
+done:
+ /* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must
+ * manually append the damaged regions ourselves.
+ */
+ DamageRegionAppend(&pixmap->drawable, &region);
+ DamageRegionProcessPending(&pixmap->drawable);
+
+ if (need_free_region)
+ pixman_region_fini(&region);
+ if (source)
+ FreePicture(source, 0);
+ return;
+}
diff --git a/glamor/glamor_copyarea.c b/glamor/glamor_copyarea.c
new file mode 100644
index 000000000..4e6f953d2
--- /dev/null
+++ b/glamor/glamor_copyarea.c
@@ -0,0 +1,676 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ */
+
+#include "glamor_priv.h"
+
+/** @file glamor_copyarea.c
+ *
+ * GC CopyArea implementation
+ */
+#ifndef GLAMOR_GLES2
+static Bool
+glamor_copy_n_to_n_fbo_blit(DrawablePtr src,
+ DrawablePtr dst,
+ GCPtr gc, BoxPtr box, int nbox, int dx, int dy)
+{
+ ScreenPtr screen = dst->pScreen;
+ PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
+ PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
+ glamor_pixmap_private *src_pixmap_priv, *dst_pixmap_priv;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch;
+ int dst_x_off, dst_y_off, src_x_off, src_y_off, i;
+ int fbo_x_off, fbo_y_off;
+ int src_fbo_x_off, src_fbo_y_off;
+
+ if (!glamor_priv->has_fbo_blit) {
+ glamor_delayed_fallback(screen,
+ "no EXT_framebuffer_blit\n");
+ return FALSE;
+ }
+ src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
+ dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
+
+ if (gc) {
+ if (gc->alu != GXcopy) {
+ glamor_delayed_fallback(screen, "non-copy ALU\n");
+ return FALSE;
+ }
+ }
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)) {
+ glamor_delayed_fallback(screen, "no src fbo\n");
+ return FALSE;
+ }
+
+ if (glamor_set_destination_pixmap(dst_pixmap))
+ return FALSE;
+
+ pixmap_priv_get_fbo_off(dst_pixmap_priv, &fbo_x_off, &fbo_y_off);
+ pixmap_priv_get_fbo_off(src_pixmap_priv, &src_fbo_x_off, &src_fbo_y_off);
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT,
+ src_pixmap_priv->base.fbo->fb);
+ glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off,
+ &dst_y_off);
+ glamor_get_drawable_deltas(src, src_pixmap, &src_x_off,
+ &src_y_off);
+ dst_x_off += fbo_x_off;
+ dst_y_off += fbo_y_off;
+ src_y_off += dy + src_fbo_y_off;
+ src_x_off += src_fbo_x_off;
+
+ for (i = 0; i < nbox; i++) {
+ if (glamor_priv->yInverted) {
+ dispatch->glBlitFramebuffer((box[i].x1 + dx +
+ src_x_off),
+ (box[i].y1 +
+ src_y_off),
+ (box[i].x2 + dx +
+ src_x_off),
+ (box[i].y2 +
+ src_y_off),
+ (box[i].x1 +
+ dst_x_off),
+ (box[i].y1 +
+ dst_y_off),
+ (box[i].x2 +
+ dst_x_off),
+ (box[i].y2 +
+ dst_y_off),
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+ } else {
+ int flip_dst_y1 =
+ dst_pixmap->drawable.height - (box[i].y2 +
+ dst_y_off);
+ int flip_dst_y2 =
+ dst_pixmap->drawable.height - (box[i].y1 +
+ dst_y_off);
+ int flip_src_y1 =
+ src_pixmap->drawable.height - (box[i].y2 +
+ src_y_off);
+ int flip_src_y2 =
+ src_pixmap->drawable.height - (box[i].y1 +
+ src_y_off);
+
+ dispatch->glBlitFramebuffer(box[i].x1 + dx +
+ src_x_off,
+ flip_src_y1,
+ box[i].x2 + dx +
+ src_x_off,
+ flip_src_y2,
+ box[i].x1 +
+ dst_x_off,
+ flip_dst_y1,
+ box[i].x2 +
+ dst_x_off,
+ flip_dst_y2,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+ }
+ }
+ glamor_put_dispatch(glamor_priv);
+ glamor_priv->state = BLIT_STATE;
+ return TRUE;
+}
+#endif
+
+static Bool
+glamor_copy_n_to_n_textured(DrawablePtr src,
+ DrawablePtr dst,
+ GCPtr gc, BoxPtr box, int nbox, int dx, int dy)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(dst->pScreen);
+ glamor_gl_dispatch *dispatch;
+ PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
+ PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
+ int i;
+ float vertices[8], texcoords[8];
+ glamor_pixmap_private *src_pixmap_priv;
+ glamor_pixmap_private *dst_pixmap_priv;
+ int src_x_off, src_y_off, dst_x_off, dst_y_off;
+ enum glamor_pixmap_status src_status = GLAMOR_NONE;
+ GLfloat dst_xscale, dst_yscale, src_xscale, src_yscale;
+
+ src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
+ dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
+
+ if (!src_pixmap_priv->base.gl_fbo) {
+#ifndef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
+ glamor_delayed_fallback(dst->pScreen, "src has no fbo.\n");
+ return FALSE;
+#else
+ src_status = glamor_upload_pixmap_to_texture(src_pixmap);
+ if (src_status != GLAMOR_UPLOAD_DONE)
+ return FALSE;
+
+ src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
+#endif
+ }
+
+
+ pixmap_priv_get_dest_scale(dst_pixmap_priv, &dst_xscale, &dst_yscale);
+ pixmap_priv_get_scale(src_pixmap_priv, &src_xscale, &src_yscale);
+
+ glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off,
+ &dst_y_off);
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+
+ glamor_set_destination_pixmap_priv_nc(dst_pixmap_priv);
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
+ GL_FALSE, 2 * sizeof(float),
+ vertices);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+
+ glamor_get_drawable_deltas(src, src_pixmap, &src_x_off,
+ &src_y_off);
+ dx += src_x_off;
+ dy += src_y_off;
+
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glBindTexture(GL_TEXTURE_2D,
+ src_pixmap_priv->base.fbo->tex);
+#ifndef GLAMOR_GLES2
+ dispatch->glEnable(GL_TEXTURE_2D);
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_BORDER);
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_BORDER);
+#endif
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2,
+ GL_FLOAT, GL_FALSE,
+ 2 * sizeof(float),
+ texcoords);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glUseProgram(glamor_priv->finish_access_prog[0]);
+ dispatch->glUniform1i(glamor_priv->finish_access_revert[0],
+ REVERT_NONE);
+ dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[0],
+ SWAP_NONE_UPLOADING);
+
+ for (i = 0; i < nbox; i++) {
+
+ glamor_set_normalize_vcoords(dst_pixmap_priv,
+ dst_xscale, dst_yscale,
+ box[i].x1 + dst_x_off,
+ box[i].y1 + dst_y_off,
+ box[i].x2 + dst_x_off,
+ box[i].y2 + dst_y_off,
+ glamor_priv->yInverted,
+ vertices);
+
+ glamor_set_normalize_tcoords(src_pixmap_priv,
+ src_xscale,
+ src_yscale,
+ box[i].x1 + dx,
+ box[i].y1 + dy,
+ box[i].x2 + dx,
+ box[i].y2 + dy,
+ glamor_priv->yInverted,
+ texcoords);
+ dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+#ifndef GLAMOR_GLES2
+ dispatch->glDisable(GL_TEXTURE_2D);
+#endif
+ dispatch->glUseProgram(0);
+ /* The source texture is bound to a fbo, we have to flush it here. */
+ glamor_put_dispatch(glamor_priv);
+ glamor_priv->state = RENDER_STATE;
+ glamor_priv->render_idle_cnt = 0;
+ return TRUE;
+}
+
+static Bool
+__glamor_copy_n_to_n(DrawablePtr src,
+ DrawablePtr dst,
+ GCPtr gc,
+ BoxPtr box,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown, Pixel bitplane,
+ void *closure)
+{
+ PixmapPtr dst_pixmap, src_pixmap, temp_pixmap = NULL;
+ DrawablePtr temp_src = src;
+ glamor_pixmap_private *dst_pixmap_priv, *src_pixmap_priv;
+ glamor_screen_private *glamor_priv;
+ BoxRec bound;
+ ScreenPtr screen;
+ int temp_dx = dx;
+ int temp_dy = dy;
+ int src_x_off, src_y_off, dst_x_off, dst_y_off;
+ int i;
+ int overlaped = 0;
+ Bool ret = FALSE;
+
+ dst_pixmap = glamor_get_drawable_pixmap(dst);
+ dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
+ src_pixmap = glamor_get_drawable_pixmap(src);
+ src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
+ screen = dst_pixmap->drawable.pScreen;
+ glamor_priv = glamor_get_screen_private(dst->pScreen);
+ glamor_get_drawable_deltas(src, src_pixmap, &src_x_off,
+ &src_y_off);
+
+ glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off,
+ &dst_y_off);
+
+ if (src_pixmap_priv->base.fbo
+ && src_pixmap_priv->base.fbo->fb == dst_pixmap_priv->base.fbo->fb) {
+ int x_shift = abs(src_x_off - dx - dst_x_off);
+ int y_shift = abs(src_y_off - dy - dst_y_off);
+ for (i = 0; i < nbox; i++) {
+ if (x_shift < abs(box[i].x2 - box[i].x1)
+ && y_shift < abs(box[i].y2 - box[i].y1)) {
+ overlaped = 1;
+ break;
+ }
+ }
+ }
+ DEBUGF("Copy %d %d %dx%d dx %d dy %d from %p to %p \n",
+ box[0].x1, box[0].y1,
+ box[0].x2 - box[0].x1, box[0].y2 - box[0].y1,
+ dx, dy,
+ src_pixmap, dst_pixmap);
+#ifndef GLAMOR_GLES2
+ if (!overlaped &&
+ (glamor_priv->state != RENDER_STATE
+ || !src_pixmap_priv->base.gl_tex || !dst_pixmap_priv->base.gl_tex)
+ && glamor_copy_n_to_n_fbo_blit(src, dst, gc, box, nbox, dx,
+ dy)) {
+ ret = TRUE;
+ goto done;
+ }
+#endif
+ glamor_calculate_boxes_bound(&bound, box, nbox);
+
+ /* Overlaped indicate the src and dst are the same pixmap. */
+ if (overlaped || (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)
+ && (((bound.x2 - bound.x1) * (bound.y2 - bound.y1)
+ * 4 >
+ src_pixmap->drawable.width *
+ src_pixmap->drawable.height)
+ || !(glamor_check_fbo_size(glamor_priv,
+ src_pixmap->drawable.width,
+ src_pixmap->drawable.height))))) {
+
+ temp_pixmap = glamor_create_pixmap(screen,
+ bound.x2 - bound.x1,
+ bound.y2 - bound.y1,
+ src_pixmap->
+ drawable.depth,
+ overlaped ? 0 :
+ GLAMOR_CREATE_PIXMAP_CPU);
+ assert(bound.x2 - bound.x1 <= glamor_priv->max_fbo_size);
+ assert(bound.y2 - bound.y1 <= glamor_priv->max_fbo_size);
+ if (!temp_pixmap)
+ goto done;
+ glamor_translate_boxes(box, nbox, -bound.x1, -bound.y1);
+ temp_src = &temp_pixmap->drawable;
+
+ if (overlaped)
+ glamor_copy_n_to_n_textured(src, temp_src, gc, box,
+ nbox,
+ temp_dx + bound.x1,
+ temp_dy + bound.y1);
+ else
+ fbCopyNtoN(src, temp_src, gc, box, nbox,
+ temp_dx + bound.x1, temp_dy + bound.y1,
+ reverse, upsidedown, bitplane, closure);
+ glamor_translate_boxes(box, nbox, bound.x1, bound.y1);
+ temp_dx = -bound.x1;
+ temp_dy = -bound.y1;
+ } else {
+ temp_dx = dx;
+ temp_dy = dy;
+ temp_src = src;
+ }
+
+ if (glamor_copy_n_to_n_textured
+ (temp_src, dst, gc, box, nbox, temp_dx, temp_dy)) {
+ ret = TRUE;
+ }
+done:
+ if (temp_src != src)
+ glamor_destroy_pixmap(temp_pixmap);
+ return ret;
+}
+
+static Bool
+_glamor_copy_n_to_n(DrawablePtr src,
+ DrawablePtr dst,
+ GCPtr gc,
+ BoxPtr box,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown, Pixel bitplane,
+ void *closure, Bool fallback)
+{
+ PixmapPtr dst_pixmap, src_pixmap;
+ glamor_pixmap_private *dst_pixmap_priv, *src_pixmap_priv;
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ BoxPtr extent;
+ RegionRec region;
+ int src_x_off, src_y_off, dst_x_off, dst_y_off;
+ Bool ok = FALSE;
+ int force_clip = 0;
+
+ if (nbox == 0)
+ return TRUE;
+ dst_pixmap = glamor_get_drawable_pixmap(dst);
+ dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
+ src_pixmap = glamor_get_drawable_pixmap(src);
+ src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
+
+ glamor_priv = glamor_get_screen_private(dst->pScreen);
+
+ DEBUGF("Copy %d %d %dx%d dx %d dy %d from %p to %p \n",
+ box[0].x1, box[0].y1,
+ box[0].x2 - box[0].x1, box[0].y2 - box[0].y1,
+ dx, dy,
+ src_pixmap, dst_pixmap);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv))
+ goto fall_back;
+
+ if (gc) {
+ if (!glamor_set_planemask(dst_pixmap, gc->planemask))
+ goto fall_back;
+ dispatch = glamor_get_dispatch(glamor_priv);
+ if (!glamor_set_alu(dispatch, gc->alu)) {
+ glamor_put_dispatch(glamor_priv);
+ goto fail;
+ }
+ glamor_put_dispatch(glamor_priv);
+ }
+
+ if (!src_pixmap_priv) {
+ glamor_set_pixmap_type(src_pixmap, GLAMOR_MEMORY);
+ src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
+ }
+
+ glamor_get_drawable_deltas(src, src_pixmap, &src_x_off,
+ &src_y_off);
+ glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off,
+ &dst_y_off);
+
+ RegionInitBoxes(&region, box, nbox);
+ extent = RegionExtents(&region);
+
+ if (!glamor_check_fbo_size(glamor_priv,
+ extent->x2 - extent->x1, extent->y2 - extent->y1)
+ && (src_pixmap_priv->type == GLAMOR_MEMORY
+ || (src_pixmap_priv == dst_pixmap_priv))) {
+ force_clip = 1;
+ }
+
+ if (force_clip || dst_pixmap_priv->type == GLAMOR_TEXTURE_LARGE
+ || src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ glamor_pixmap_clipped_regions *clipped_dst_regions;
+ int n_dst_region, i, j;
+ PixmapPtr temp_source_pixmap;
+ glamor_pixmap_private *temp_source_priv = NULL;
+
+ RegionTranslate(&region, dst_x_off, dst_y_off);
+ if (!force_clip)
+ clipped_dst_regions = glamor_compute_clipped_regions(dst_pixmap_priv,
+ &region, &n_dst_region, 0,
+ reverse, upsidedown);
+ else
+ clipped_dst_regions = glamor_compute_clipped_regions_ext(dst_pixmap_priv,
+ &region, &n_dst_region,
+ glamor_priv->max_fbo_size,
+ glamor_priv->max_fbo_size,
+ reverse, upsidedown);
+ for(i = 0; i < n_dst_region; i++)
+ {
+ int n_src_region;
+ glamor_pixmap_clipped_regions *clipped_src_regions;
+ BoxPtr current_boxes;
+ int n_current_boxes;
+
+ SET_PIXMAP_FBO_CURRENT(dst_pixmap_priv, clipped_dst_regions[i].block_idx);
+
+ temp_source_pixmap = NULL;
+ if (src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ RegionTranslate(clipped_dst_regions[i].region,
+ -dst_x_off + src_x_off + dx, -dst_y_off + src_y_off + dy);
+ clipped_src_regions = glamor_compute_clipped_regions(src_pixmap_priv,
+ clipped_dst_regions[i].region,
+ &n_src_region, 0,
+ reverse, upsidedown);
+ DEBUGF("Source is large pixmap.\n");
+ for (j = 0; j < n_src_region; j++)
+ {
+ if (src_pixmap_priv != dst_pixmap_priv)
+ SET_PIXMAP_FBO_CURRENT(src_pixmap_priv, clipped_src_regions[j].block_idx);
+ else if (src_pixmap_priv == dst_pixmap_priv &&
+ clipped_src_regions[j].block_idx != clipped_dst_regions[i].block_idx) {
+ /* source and the dest are the same, but need different block_idx.
+ * we create a empty pixmap and fill the required source fbo and box to
+ * it. It's a little hacky, but avoid extra copy. */
+ temp_source_pixmap = glamor_create_pixmap(src->pScreen, 0, 0,
+ src->depth, 0);
+ if (!temp_source_pixmap) {
+ ok = FALSE;
+ goto fail;
+ }
+ src->pScreen->ModifyPixmapHeader(temp_source_pixmap,
+ src_pixmap->drawable.width,
+ src_pixmap->drawable.height,
+ 0, 0, src_pixmap->devKind, NULL);
+ temp_source_priv = glamor_get_pixmap_private(temp_source_pixmap);
+ *temp_source_priv = *src_pixmap_priv;
+ temp_source_priv->large.box = src_pixmap_priv->large.box_array[clipped_src_regions[j].block_idx];
+ temp_source_priv->base.fbo = src_pixmap_priv->large.fbo_array[clipped_src_regions[j].block_idx];
+ temp_source_priv->base.pixmap = temp_source_pixmap;
+ }
+ assert(temp_source_pixmap || !(src_pixmap_priv == dst_pixmap_priv
+ && (clipped_src_regions[j].block_idx != clipped_dst_regions[i].block_idx)));
+
+ RegionTranslate(clipped_src_regions[j].region,
+ -src_x_off - dx,
+ -src_y_off - dy);
+ current_boxes = RegionRects(clipped_src_regions[j].region);
+ n_current_boxes = RegionNumRects(clipped_src_regions[j].region);
+ DEBUGF("dst pixmap fbo idx %d src pixmap fbo idx %d \n",
+ clipped_dst_regions[i].block_idx,
+ clipped_src_regions[j].block_idx);
+ DEBUGF("Copy %d %d %d %d dx %d dy %d from %p to %p \n",
+ current_boxes[0].x1, current_boxes[0].y1,
+ current_boxes[0].x2, current_boxes[0].y2,
+ dx, dy, src_pixmap, dst_pixmap);
+ if (!temp_source_pixmap)
+ ok = __glamor_copy_n_to_n(src, dst, gc, current_boxes,
+ n_current_boxes, dx, dy, reverse,
+ upsidedown, bitplane, closure);
+ else {
+ ok = __glamor_copy_n_to_n(&temp_source_pixmap->drawable,
+ dst, gc, current_boxes,
+ n_current_boxes, dx, dy, reverse,
+ upsidedown, bitplane, closure);
+ temp_source_priv->type = GLAMOR_MEMORY;
+ temp_source_priv->base.fbo = NULL;
+ glamor_destroy_pixmap(temp_source_pixmap);
+ temp_source_pixmap = NULL;
+ }
+
+ RegionDestroy(clipped_src_regions[j].region);
+ if (!ok) {
+ assert(0);
+ goto fail;
+ }
+ }
+
+ if (n_src_region == 0)
+ ok = TRUE;
+ free(clipped_src_regions);
+ } else {
+ RegionTranslate(clipped_dst_regions[i].region,
+ - dst_x_off,
+ - dst_y_off);
+ current_boxes = RegionRects(clipped_dst_regions[i].region);
+ n_current_boxes = RegionNumRects(clipped_dst_regions[i].region);
+
+ DEBUGF("dest pixmap fbo idx %d \n",
+ clipped_dst_regions[i].block_idx);
+ DEBUGF("Copy %d %d %d %d dx %d dy %d from %p to %p \n",
+ current_boxes[0].x1, current_boxes[0].y1,
+ current_boxes[0].x2, current_boxes[0].y2,
+ dx, dy, src_pixmap, dst_pixmap);
+
+ ok = __glamor_copy_n_to_n(src, dst, gc, current_boxes,
+ n_current_boxes, dx, dy, reverse,
+ upsidedown, bitplane, closure);
+
+ }
+ RegionDestroy(clipped_dst_regions[i].region);
+ }
+ if (n_dst_region == 0)
+ ok = TRUE;
+ free(clipped_dst_regions);
+ RegionUninit(&region);
+ } else {
+ ok = __glamor_copy_n_to_n(src, dst, gc, box, nbox, dx, dy,
+ reverse, upsidedown, bitplane,
+ closure);
+ }
+
+fail:
+ dispatch = glamor_get_dispatch(glamor_priv);
+ glamor_set_alu(dispatch, GXcopy);
+ glamor_put_dispatch(glamor_priv);
+
+ if (ok)
+ return TRUE;
+fall_back:
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(src)
+ && glamor_ddx_fallback_check_pixmap(dst))
+ goto done;
+
+ if (src_pixmap_priv->type == GLAMOR_DRM_ONLY
+ || dst_pixmap_priv->type == GLAMOR_DRM_ONLY) {
+ LogMessage(X_WARNING,
+ "Access a DRM only pixmap is not allowed within glamor.\n");
+ return TRUE;
+ }
+ glamor_report_delayed_fallbacks(src->pScreen);
+ glamor_report_delayed_fallbacks(dst->pScreen);
+
+ glamor_fallback("from %p to %p (%c,%c)\n", src, dst,
+ glamor_get_drawable_location(src),
+ glamor_get_drawable_location(dst));
+
+ if (glamor_prepare_access(dst, GLAMOR_ACCESS_RW)) {
+ if (dst == src
+ || glamor_prepare_access(src, GLAMOR_ACCESS_RO)) {
+ fbCopyNtoN(src, dst, gc, box, nbox,
+ dx, dy, reverse, upsidedown, bitplane,
+ closure);
+ if (dst != src)
+ glamor_finish_access(src, GLAMOR_ACCESS_RO);
+ }
+ glamor_finish_access(dst, GLAMOR_ACCESS_RW);
+ }
+ ok = TRUE;
+
+ done:
+ glamor_clear_delayed_fallbacks(src->pScreen);
+ glamor_clear_delayed_fallbacks(dst->pScreen);
+ return ok;
+}
+
+RegionPtr
+glamor_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
+ int srcx, int srcy, int width, int height, int dstx,
+ int dsty)
+{
+ RegionPtr region;
+ region = miDoCopy(src, dst, gc,
+ srcx, srcy, width, height,
+ dstx, dsty, glamor_copy_n_to_n, 0, NULL);
+
+ return region;
+}
+
+void
+glamor_copy_n_to_n(DrawablePtr src,
+ DrawablePtr dst,
+ GCPtr gc,
+ BoxPtr box,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown, Pixel bitplane,
+ void *closure)
+{
+ _glamor_copy_n_to_n(src, dst, gc, box, nbox, dx,
+ dy, reverse, upsidedown, bitplane, closure, TRUE);
+}
+
+Bool
+glamor_copy_n_to_n_nf(DrawablePtr src,
+ DrawablePtr dst,
+ GCPtr gc,
+ BoxPtr box,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown, Pixel bitplane,
+ void *closure)
+{
+ return _glamor_copy_n_to_n(src, dst, gc, box, nbox, dx,
+ dy, reverse, upsidedown, bitplane, closure, FALSE);
+}
+
diff --git a/glamor/glamor_copyplane.c b/glamor/glamor_copyplane.c
new file mode 100644
index 000000000..3f2652ac7
--- /dev/null
+++ b/glamor/glamor_copyplane.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@gmail.com>
+ *
+ */
+
+#include "glamor_priv.h"
+
+static Bool
+_glamor_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty,
+ unsigned long bitPlane, RegionPtr *pRegion, Bool fallback)
+{
+ if (!fallback
+ && glamor_ddx_fallback_check_gc(pGC)
+ && glamor_ddx_fallback_check_pixmap(pSrc)
+ && glamor_ddx_fallback_check_pixmap(pDst))
+ goto fail;
+
+ glamor_prepare_access(pDst, GLAMOR_ACCESS_RW);
+ glamor_prepare_access(pSrc, GLAMOR_ACCESS_RO);
+ *pRegion = fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h,
+ dstx, dsty, bitPlane);
+ glamor_finish_access(pSrc, GLAMOR_ACCESS_RO);
+ glamor_finish_access(pDst, GLAMOR_ACCESS_RW);
+ return TRUE;
+
+ fail:
+ return FALSE;
+}
+
+RegionPtr
+glamor_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty,
+ unsigned long bitPlane)
+{
+ RegionPtr ret;
+ _glamor_copy_plane(pSrc, pDst, pGC, srcx, srcy, w, h,
+ dstx, dsty, bitPlane, &ret, TRUE);
+ return ret;
+}
+
+Bool
+glamor_copy_plane_nf(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty,
+ unsigned long bitPlane, RegionPtr *pRegion)
+{
+ return _glamor_copy_plane(pSrc, pDst, pGC, srcx, srcy, w, h,
+ dstx, dsty, bitPlane, pRegion, FALSE);
+}
diff --git a/glamor/glamor_copywindow.c b/glamor/glamor_copywindow.c
new file mode 100644
index 000000000..b181ff529
--- /dev/null
+++ b/glamor/glamor_copywindow.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "glamor_priv.h"
+
+/** @file glamor_copywindow.c
+ *
+ * Screen CopyWindow implementation.
+ */
+
+void
+glamor_copy_window(WindowPtr win, DDXPointRec old_origin,
+ RegionPtr src_region)
+{
+ RegionRec dst_region;
+ int dx, dy;
+ PixmapPtr pixmap = win->drawable.pScreen->GetWindowPixmap(win);
+
+ dx = old_origin.x - win->drawable.x;
+ dy = old_origin.y - win->drawable.y;
+ REGION_TRANSLATE(win->drawable.pScreen, src_region, -dx, -dy);
+
+ REGION_INIT(win->drawable.pScreen, &dst_region, NullBox, 0);
+
+ REGION_INTERSECT(win->drawable.pScreen, &dst_region,
+ &win->borderClip, src_region);
+#ifdef COMPOSITE
+ if (pixmap->screen_x || pixmap->screen_y)
+ REGION_TRANSLATE(win->drawable.pScreen, &dst_region,
+ -pixmap->screen_x, -pixmap->screen_y);
+#endif
+
+ miCopyRegion(&pixmap->drawable, &pixmap->drawable,
+ NULL, &dst_region, dx, dy, glamor_copy_n_to_n, 0,
+ NULL);
+
+ REGION_UNINIT(win->drawable.pScreen, &dst_region);
+}
diff --git a/glamor/glamor_core.c b/glamor/glamor_core.c
new file mode 100644
index 000000000..eb1a08d43
--- /dev/null
+++ b/glamor/glamor_core.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright © 2001 Keith Packard
+ * Copyright © 2008 Intel Corporation
+ *
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+/** @file glamor_core.c
+ *
+ * This file covers core X rendering in glamor.
+ */
+
+#include <stdlib.h>
+
+#include "glamor_priv.h"
+
+const Bool
+glamor_get_drawable_location(const DrawablePtr drawable)
+{
+ PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
+ glamor_pixmap_private *pixmap_priv =
+ glamor_get_pixmap_private(pixmap);
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(drawable->pScreen);
+ if (pixmap_priv == NULL || pixmap_priv->base.gl_fbo == 0)
+ return 'm';
+ if (pixmap_priv->base.fbo->fb == glamor_priv->screen_fbo)
+ return 's';
+ else
+ return 'f';
+}
+
+GLint
+glamor_compile_glsl_prog(glamor_gl_dispatch * dispatch, GLenum type,
+ const char *source)
+{
+ GLint ok;
+ GLint prog;
+
+ prog = dispatch->glCreateShader(type);
+ dispatch->glShaderSource(prog, 1, (const GLchar **) &source, NULL);
+ dispatch->glCompileShader(prog);
+ dispatch->glGetShaderiv(prog, GL_COMPILE_STATUS, &ok);
+ if (!ok) {
+ GLchar *info;
+ GLint size;
+
+ dispatch->glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &size);
+ info = malloc(size);
+ if (info) {
+ dispatch->glGetShaderInfoLog(prog, size, NULL, info);
+ ErrorF("Failed to compile %s: %s\n",
+ type == GL_FRAGMENT_SHADER ? "FS" : "VS", info);
+ ErrorF("Program source:\n%s", source);
+ free(info);
+ } else
+ ErrorF("Failed to get shader compilation info.\n");
+ FatalError("GLSL compile failure\n");
+ }
+
+ return prog;
+}
+
+void
+glamor_link_glsl_prog(glamor_gl_dispatch * dispatch, GLint prog)
+{
+ GLint ok;
+
+ dispatch->glLinkProgram(prog);
+ dispatch->glGetProgramiv(prog, GL_LINK_STATUS, &ok);
+ if (!ok) {
+ GLchar *info;
+ GLint size;
+
+ dispatch->glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
+ info = malloc(size);
+
+ dispatch->glGetProgramInfoLog(prog, size, NULL, info);
+ ErrorF("Failed to link: %s\n", info);
+ FatalError("GLSL link failure\n");
+ }
+}
+
+
+Bool
+glamor_prepare_access(DrawablePtr drawable, glamor_access_t access)
+{
+ PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
+ return glamor_download_pixmap_to_cpu(pixmap, access);
+}
+
+/*
+ * When downloading a unsupported color format to CPU memory,
+ we need to shuffle the color elements and then use a supported
+ color format to read it back to CPU memory.
+
+ For an example, the picture's format is PICT_b8g8r8a8,
+ Then the expecting color layout is as below (little endian):
+ 0 1 2 3 : address
+ a r g b
+
+ Now the in GLES2 the supported color format is GL_RGBA, type is
+ GL_UNSIGNED_TYPE, then we need to shuffle the fragment
+ color as :
+ frag_color = sample(texture).argb;
+ before we use glReadPixel to get it back.
+
+ For the uploading process, the shuffle is a revert shuffle.
+ We still use GL_RGBA, GL_UNSIGNED_BYTE to upload the color
+ to a texture, then let's see
+ 0 1 2 3 : address
+ a r g b : correct colors
+ R G B A : GL_RGBA with GL_UNSIGNED_BYTE
+
+ Now we need to shuffle again, the mapping rule is
+ r = G, g = B, b = A, a = R. Then the uploading shuffle is as
+ below:
+ frag_color = sample(texture).gbar;
+*/
+
+void
+glamor_init_finish_access_shaders(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ const char *vs_source =
+ "attribute vec4 v_position;\n"
+ "attribute vec4 v_texcoord0;\n"
+ "varying vec2 source_texture;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = v_position;\n"
+ " source_texture = v_texcoord0.xy;\n" "}\n";
+
+ const char *common_source =
+ GLAMOR_DEFAULT_PRECISION
+ "varying vec2 source_texture;\n"
+ "uniform sampler2D sampler;\n"
+ "uniform int revert;\n"
+ "uniform int swap_rb;\n"
+
+ "#define REVERT_NONE 0\n"
+ "#define REVERT_NORMAL 1\n"
+ "#define SWAP_NONE_DOWNLOADING 0\n"
+ "#define SWAP_DOWNLOADING 1\n"
+ "#define SWAP_UPLOADING 2\n"
+ "#define SWAP_NONE_UPLOADING 3\n";
+
+ const char *fs_source =
+ "void main()\n"
+ "{\n"
+ " if (revert == REVERT_NONE) \n"
+ " { \n"
+ " if ((swap_rb != SWAP_NONE_DOWNLOADING) && (swap_rb != SWAP_NONE_UPLOADING)) \n"
+ " gl_FragColor = texture2D(sampler, source_texture).bgra;\n"
+ " else \n"
+ " gl_FragColor = texture2D(sampler, source_texture).rgba;\n"
+ " } \n"
+ " else \n"
+ " { \n"
+ " if (swap_rb == SWAP_DOWNLOADING) \n"
+ " gl_FragColor = texture2D(sampler, source_texture).argb;\n"
+ " else if (swap_rb == SWAP_NONE_DOWNLOADING)\n"
+ " gl_FragColor = texture2D(sampler, source_texture).abgr;\n"
+ " else if (swap_rb == SWAP_UPLOADING)\n"
+ " gl_FragColor = texture2D(sampler, source_texture).gbar;\n"
+ " else if (swap_rb == SWAP_NONE_UPLOADING)\n"
+ " gl_FragColor = texture2D(sampler, source_texture).abgr;\n"
+ " } \n" "}\n";
+
+ const char *set_alpha_source =
+ "void main()\n"
+ "{\n"
+ " if (revert == REVERT_NONE) \n"
+ " { \n"
+ " if ((swap_rb != SWAP_NONE_DOWNLOADING) && (swap_rb != SWAP_NONE_UPLOADING)) \n"
+ " gl_FragColor = vec4(texture2D(sampler, source_texture).bgr, 1);\n"
+ " else \n"
+ " gl_FragColor = vec4(texture2D(sampler, source_texture).rgb, 1);\n"
+ " } \n"
+ " else \n"
+ " { \n"
+ " if (swap_rb == SWAP_DOWNLOADING) \n"
+ " gl_FragColor = vec4(1, texture2D(sampler, source_texture).rgb);\n"
+ " else if (swap_rb == SWAP_NONE_DOWNLOADING)\n"
+ " gl_FragColor = vec4(1, texture2D(sampler, source_texture).bgr);\n"
+ " else if (swap_rb == SWAP_UPLOADING)\n"
+ " gl_FragColor = vec4(texture2D(sampler, source_texture).gba, 1);\n"
+ " else if (swap_rb == SWAP_NONE_UPLOADING)\n"
+ " gl_FragColor = vec4(texture2D(sampler, source_texture).abg, 1);\n"
+ " } \n"
+ "}\n";
+ GLint fs_prog, vs_prog, avs_prog, set_alpha_prog;
+ GLint sampler_uniform_location;
+ char *source;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+ glamor_priv->finish_access_prog[0] = dispatch->glCreateProgram();
+ glamor_priv->finish_access_prog[1] = dispatch->glCreateProgram();
+
+ vs_prog = glamor_compile_glsl_prog(dispatch, GL_VERTEX_SHADER,
+ vs_source);
+
+ XNFasprintf(&source, "%s%s", common_source, fs_source);
+ fs_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER,
+ source);
+ free(source);
+
+ dispatch->glAttachShader(glamor_priv->finish_access_prog[0],
+ vs_prog);
+ dispatch->glAttachShader(glamor_priv->finish_access_prog[0],
+ fs_prog);
+
+ avs_prog = glamor_compile_glsl_prog(dispatch, GL_VERTEX_SHADER,
+ vs_source);
+
+ XNFasprintf(&source, "%s%s", common_source, set_alpha_source);
+ set_alpha_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER,
+ source);
+ free(source);
+
+ dispatch->glAttachShader(glamor_priv->finish_access_prog[1],
+ avs_prog);
+ dispatch->glAttachShader(glamor_priv->finish_access_prog[1],
+ set_alpha_prog);
+
+ dispatch->glBindAttribLocation(glamor_priv->finish_access_prog[0],
+ GLAMOR_VERTEX_POS, "v_position");
+ dispatch->glBindAttribLocation(glamor_priv->finish_access_prog[0],
+ GLAMOR_VERTEX_SOURCE,
+ "v_texcoord0");
+ glamor_link_glsl_prog(dispatch,
+ glamor_priv->finish_access_prog[0]);
+
+ dispatch->glBindAttribLocation(glamor_priv->finish_access_prog[1],
+ GLAMOR_VERTEX_POS, "v_position");
+ dispatch->glBindAttribLocation(glamor_priv->finish_access_prog[1],
+ GLAMOR_VERTEX_SOURCE,
+ "v_texcoord0");
+ glamor_link_glsl_prog(dispatch,
+ glamor_priv->finish_access_prog[1]);
+
+ glamor_priv->finish_access_revert[0] =
+ dispatch->
+ glGetUniformLocation(glamor_priv->finish_access_prog[0],
+ "revert");
+
+ glamor_priv->finish_access_swap_rb[0] =
+ dispatch->
+ glGetUniformLocation(glamor_priv->finish_access_prog[0],
+ "swap_rb");
+ sampler_uniform_location =
+ dispatch->
+ glGetUniformLocation(glamor_priv->finish_access_prog[0],
+ "sampler");
+ dispatch->glUseProgram(glamor_priv->finish_access_prog[0]);
+ dispatch->glUniform1i(sampler_uniform_location, 0);
+ dispatch->glUniform1i(glamor_priv->finish_access_revert[0], 0);
+ dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[0], 0);
+ dispatch->glUseProgram(0);
+
+ glamor_priv->finish_access_revert[1] =
+ dispatch->
+ glGetUniformLocation(glamor_priv->finish_access_prog[1],
+ "revert");
+ glamor_priv->finish_access_swap_rb[1] =
+ dispatch->
+ glGetUniformLocation(glamor_priv->finish_access_prog[1],
+ "swap_rb");
+ sampler_uniform_location =
+ dispatch->
+ glGetUniformLocation(glamor_priv->finish_access_prog[1],
+ "sampler");
+ dispatch->glUseProgram(glamor_priv->finish_access_prog[1]);
+ dispatch->glUniform1i(glamor_priv->finish_access_revert[1], 0);
+ dispatch->glUniform1i(sampler_uniform_location, 0);
+ dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[1], 0);
+ dispatch->glUseProgram(0);
+ glamor_put_dispatch(glamor_priv);
+}
+
+void
+glamor_fini_finish_access_shaders(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glDeleteProgram(glamor_priv->finish_access_prog[0]);
+ dispatch->glDeleteProgram(glamor_priv->finish_access_prog[1]);
+ glamor_put_dispatch(glamor_priv);
+}
+
+void
+glamor_finish_access(DrawablePtr drawable, glamor_access_t access_mode)
+{
+ PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
+ glamor_pixmap_private *pixmap_priv =
+ glamor_get_pixmap_private(pixmap);
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(drawable->pScreen);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO_DOWNLOADED(pixmap_priv))
+ return;
+
+ if (access_mode != GLAMOR_ACCESS_RO) {
+ glamor_restore_pixmap_to_texture(pixmap);
+ }
+
+ if (pixmap_priv->base.fbo->pbo != 0 && pixmap_priv->base.fbo->pbo_valid) {
+ glamor_gl_dispatch *dispatch;
+
+ assert(glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP);
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+ dispatch->glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ dispatch->glDeleteBuffers(1, &pixmap_priv->base.fbo->pbo);
+ glamor_put_dispatch(glamor_priv);
+
+ pixmap_priv->base.fbo->pbo_valid = FALSE;
+ pixmap_priv->base.fbo->pbo = 0;
+ } else {
+ free(pixmap->devPrivate.ptr);
+ }
+
+ if (pixmap_priv->type == GLAMOR_TEXTURE_DRM)
+ pixmap->devKind = pixmap_priv->base.drm_stride;
+
+ if (pixmap_priv->base.gl_fbo == GLAMOR_FBO_DOWNLOADED)
+ pixmap_priv->base.gl_fbo = GLAMOR_FBO_NORMAL;
+
+ pixmap->devPrivate.ptr = NULL;
+}
+
+
+/**
+ * Calls uxa_prepare_access with UXA_PREPARE_SRC for the tile, if that is the
+ * current fill style.
+ *
+ * Solid doesn't use an extra pixmap source, so we don't worry about them.
+ * Stippled/OpaqueStippled are 1bpp and can be in fb, so we should worry
+ * about them.
+ */
+Bool
+glamor_prepare_access_gc(GCPtr gc)
+{
+ if (gc->stipple) {
+ if (!glamor_prepare_access
+ (&gc->stipple->drawable, GLAMOR_ACCESS_RO))
+ return FALSE;
+ }
+ if (gc->fillStyle == FillTiled) {
+ if (!glamor_prepare_access(&gc->tile.pixmap->drawable,
+ GLAMOR_ACCESS_RO)) {
+ if (gc->stipple)
+ glamor_finish_access(&gc->
+ stipple->drawable,
+ GLAMOR_ACCESS_RO);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * Finishes access to the tile in the GC, if used.
+ */
+void
+glamor_finish_access_gc(GCPtr gc)
+{
+ if (gc->fillStyle == FillTiled)
+ glamor_finish_access(&gc->tile.pixmap->drawable, GLAMOR_ACCESS_RO);
+ if (gc->stipple)
+ glamor_finish_access(&gc->stipple->drawable, GLAMOR_ACCESS_RO);
+}
+
+Bool
+glamor_stipple(PixmapPtr pixmap, PixmapPtr stipple,
+ int x, int y, int width, int height,
+ unsigned char alu, unsigned long planemask,
+ unsigned long fg_pixel, unsigned long bg_pixel,
+ int stipple_x, int stipple_y)
+{
+ glamor_fallback("stubbed out stipple depth %d\n",
+ pixmap->drawable.depth);
+ return FALSE;
+}
+
+GCOps glamor_gc_ops = {
+ .FillSpans = glamor_fill_spans,
+ .SetSpans = glamor_set_spans,
+ .PutImage = glamor_put_image,
+ .CopyArea = glamor_copy_area,
+ .CopyPlane = glamor_copy_plane,
+ .PolyPoint = glamor_poly_point,
+ .Polylines = glamor_poly_lines,
+ .PolySegment = glamor_poly_segment,
+ .PolyRectangle = miPolyRectangle,
+ .PolyArc = miPolyArc,
+ .FillPolygon = miFillPolygon,
+ .PolyFillRect = glamor_poly_fill_rect,
+ .PolyFillArc = miPolyFillArc,
+ .PolyText8 = miPolyText8,
+ .PolyText16 = miPolyText16,
+ .ImageText8 = miImageText8,
+ .ImageText16 = miImageText16,
+ .ImageGlyphBlt = glamor_image_glyph_blt, //miImageGlyphBlt,
+ .PolyGlyphBlt = glamor_poly_glyph_blt, //miPolyGlyphBlt,
+ .PushPixels = glamor_push_pixels, //miPushPixels,
+};
+
+/**
+ * uxa_validate_gc() sets the ops to glamor's implementations, which may be
+ * accelerated or may sync the card and fall back to fb.
+ */
+void
+glamor_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable)
+{
+ /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
+ * Preempt fbValidateGC by doing its work and masking the change out, so
+ * that we can do the Prepare/finish_access.
+ */
+#ifdef FB_24_32BIT
+ if ((changes & GCTile) && fbGetRotatedPixmap(gc)) {
+ gc->pScreen->DestroyPixmap(fbGetRotatedPixmap(gc));
+ fbGetRotatedPixmap(gc) = 0;
+ }
+
+ if (gc->fillStyle == FillTiled) {
+ PixmapPtr old_tile, new_tile;
+
+ old_tile = gc->tile.pixmap;
+ if (old_tile->drawable.bitsPerPixel !=
+ drawable->bitsPerPixel) {
+ new_tile = fbGetRotatedPixmap(gc);
+ if (!new_tile ||
+ new_tile->drawable.bitsPerPixel !=
+ drawable->bitsPerPixel) {
+ if (new_tile)
+ gc->pScreen->DestroyPixmap
+ (new_tile);
+ /* fb24_32ReformatTile will do direct access of a newly-
+ * allocated pixmap.
+ */
+ glamor_fallback
+ ("GC %p tile FB_24_32 transformat %p.\n",
+ gc, old_tile);
+
+ if (glamor_prepare_access
+ (&old_tile->drawable,
+ GLAMOR_ACCESS_RO)) {
+ new_tile =
+ fb24_32ReformatTile
+ (old_tile,
+ drawable->bitsPerPixel);
+ glamor_finish_access
+ (&old_tile->drawable, GLAMOR_ACCESS_RO);
+ }
+ }
+ if (new_tile) {
+ fbGetRotatedPixmap(gc) = old_tile;
+ gc->tile.pixmap = new_tile;
+ changes |= GCTile;
+ }
+ }
+ }
+#endif
+ if (changes & GCTile) {
+ if (!gc->tileIsPixel) {
+ glamor_pixmap_private *pixmap_priv =
+ glamor_get_pixmap_private(gc->tile.pixmap);
+ if ((!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ && FbEvenTile(gc->tile.pixmap->drawable.width *
+ drawable->bitsPerPixel)) {
+ glamor_fallback
+ ("GC %p tile changed %p.\n", gc,
+ gc->tile.pixmap);
+ if (glamor_prepare_access
+ (&gc->tile.pixmap->drawable,
+ GLAMOR_ACCESS_RW)) {
+ fbPadPixmap(gc->tile.pixmap);
+ glamor_finish_access
+ (&gc->tile.pixmap->drawable, GLAMOR_ACCESS_RW);
+ }
+ }
+ }
+ /* Mask out the GCTile change notification, now that we've done FB's
+ * job for it.
+ */
+ changes &= ~GCTile;
+ }
+
+ if (changes & GCStipple && gc->stipple) {
+ /* We can't inline stipple handling like we do for GCTile because
+ * it sets fbgc privates.
+ */
+ if (glamor_prepare_access
+ (&gc->stipple->drawable, GLAMOR_ACCESS_RW)) {
+ fbValidateGC(gc, changes, drawable);
+ glamor_finish_access(&gc->stipple->drawable, GLAMOR_ACCESS_RW);
+ }
+ } else {
+ fbValidateGC(gc, changes, drawable);
+ }
+
+ gc->ops = &glamor_gc_ops;
+}
+
+static GCFuncs glamor_gc_funcs = {
+ glamor_validate_gc,
+ miChangeGC,
+ miCopyGC,
+ miDestroyGC,
+ miChangeClip,
+ miDestroyClip,
+ miCopyClip
+};
+
+/**
+ * exaCreateGC makes a new GC and hooks up its funcs handler, so that
+ * exaValidateGC() will get called.
+ */
+int
+glamor_create_gc(GCPtr gc)
+{
+ if (!fbCreateGC(gc))
+ return FALSE;
+
+ gc->funcs = &glamor_gc_funcs;
+
+ return TRUE;
+}
+
+RegionPtr
+glamor_bitmap_to_region(PixmapPtr pixmap)
+{
+ RegionPtr ret;
+ glamor_fallback("pixmap %p \n", pixmap);
+ if (!glamor_prepare_access(&pixmap->drawable, GLAMOR_ACCESS_RO))
+ return NULL;
+ ret = fbPixmapToRegion(pixmap);
+ glamor_finish_access(&pixmap->drawable, GLAMOR_ACCESS_RO);
+ return ret;
+}
+
+/* Borrow from cairo. */
+Bool
+glamor_gl_has_extension(const char *extension)
+{
+ const char *pext;
+ int ext_len;
+ ext_len = strlen(extension);
+
+ pext = (const char*)glGetString(GL_EXTENSIONS);
+
+ if (pext == NULL || extension == NULL)
+ return FALSE;
+
+ while ((pext = strstr(pext, extension)) != NULL) {
+ if (pext[ext_len] == ' ' || pext[ext_len] == '\0')
+ return TRUE;
+ pext += ext_len;
+ }
+ return FALSE;
+}
+
+int
+glamor_gl_get_version(void)
+{
+ int major, minor;
+ const char *version = (const char *) glGetString(GL_VERSION);
+ const char *dot = version == NULL ? NULL : strchr(version, '.');
+ const char *major_start = dot;
+
+ /* Sanity check */
+ if (dot == NULL || dot == version || *(dot + 1) == '\0') {
+ major = 0;
+ minor = 0;
+ } else {
+ /* Find the start of the major version in the string */
+ while (major_start > version && *major_start != ' ')
+ --major_start;
+ major = strtol(major_start, NULL, 10);
+ minor = strtol(dot + 1, NULL, 10);
+ }
+
+ return GLAMOR_GL_VERSION_ENCODE(major, minor);
+}
diff --git a/glamor/glamor_debug.h b/glamor/glamor_debug.h
new file mode 100644
index 000000000..f0c969b11
--- /dev/null
+++ b/glamor/glamor_debug.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@gmail.com>
+ *
+ */
+
+#ifndef __GLAMOR_DEBUG_H__
+#define __GLAMOR_DEBUG_H__
+
+
+#define GLAMOR_DELAYED_STRING_MAX 64
+
+#define GLAMOR_DEBUG_NONE 0
+#define GLAMOR_DEBUG_UNIMPL 0
+#define GLAMOR_DEBUG_FALLBACK 1
+#define GLAMOR_DEBUG_TEXTURE_DOWNLOAD 2
+#define GLAMOR_DEBUG_TEXTURE_DYNAMIC_UPLOAD 3
+
+extern void
+AbortServer(void)
+ _X_NORETURN;
+
+#define GLAMOR_PANIC(_format_, ...) \
+ do { \
+ LogMessageVerb(X_NONE, 0, "Glamor Fatal Error" \
+ " at %32s line %d: " _format_ "\n", \
+ __FUNCTION__, __LINE__, \
+ ##__VA_ARGS__ ); \
+ exit(1); \
+ } while(0)
+
+
+
+
+#define __debug_output_message(_format_, _prefix_, ...) \
+ LogMessageVerb(X_NONE, 0, \
+ "%32s:\t" _format_ , \
+ /*_prefix_,*/ \
+ __FUNCTION__, \
+ ##__VA_ARGS__)
+
+#define glamor_debug_output(_level_, _format_,...) \
+ do { \
+ if (glamor_debug_level >= _level_) \
+ __debug_output_message(_format_, \
+ "Glamor debug", \
+ ##__VA_ARGS__); \
+ } while(0)
+
+
+#define glamor_fallback(_format_,...) \
+ do { \
+ if (glamor_debug_level >= GLAMOR_DEBUG_FALLBACK) \
+ __debug_output_message(_format_, \
+ "Glamor fallback", \
+ ##__VA_ARGS__);} while(0)
+
+
+
+#define glamor_delayed_fallback(_screen_, _format_,...) \
+ do { \
+ if (glamor_debug_level >= GLAMOR_DEBUG_FALLBACK) { \
+ glamor_screen_private *_glamor_priv_; \
+ _glamor_priv_ = glamor_get_screen_private(_screen_); \
+ _glamor_priv_->delayed_fallback_pending = 1; \
+ snprintf(_glamor_priv_->delayed_fallback_string, \
+ GLAMOR_DELAYED_STRING_MAX, \
+ "glamor delayed fallback: \t%s " _format_ , \
+ __FUNCTION__, ##__VA_ARGS__); } } while(0)
+
+
+#define glamor_clear_delayed_fallbacks(_screen_) \
+ do { \
+ if (glamor_debug_level >= GLAMOR_DEBUG_FALLBACK) { \
+ glamor_screen_private *_glamor_priv_; \
+ _glamor_priv_ = glamor_get_screen_private(_screen_); \
+ _glamor_priv_->delayed_fallback_pending = 0; } } while(0)
+
+#define glamor_report_delayed_fallbacks(_screen_) \
+ do { \
+ if (glamor_debug_level >= GLAMOR_DEBUG_FALLBACK) { \
+ glamor_screen_private *_glamor_priv_; \
+ _glamor_priv_ = glamor_get_screen_private(_screen_); \
+ LogMessageVerb(X_INFO, 0, "%s", \
+ _glamor_priv_->delayed_fallback_string); \
+ _glamor_priv_->delayed_fallback_pending = 0; } } while(0)
+
+#define DEBUGF(str, ...) do {} while(0)
+//#define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__)
+#define DEBUGRegionPrint(x) do {} while (0)
+//#define DEBUGRegionPrint RegionPrint
+
+
+#endif
diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
new file mode 100644
index 000000000..ff4c0bdd9
--- /dev/null
+++ b/glamor/glamor_egl.c
@@ -0,0 +1,860 @@
+/*
+ * Copyright © 2010 Intel Corporation.
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define GLAMOR_FOR_XORG
+#include <xorg-server.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <xf86.h>
+#include <xf86drm.h>
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+#define EGL_DISPLAY_NO_X_MESA
+
+#ifdef GLAMOR_HAS_GBM
+#include <gbm.h>
+#include <drm_fourcc.h>
+#endif
+
+#if GLAMOR_GLES2
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#else
+#include <GL/gl.h>
+#endif
+
+#define MESA_EGL_NO_X11_HEADERS
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "glamor.h"
+#include "compat-api.h"
+#include "glamor_gl_dispatch.h"
+#ifdef GLX_USE_SHARED_DISPATCH
+#include "glapi.h"
+#endif
+
+static const char glamor_name[] = "glamor";
+
+static DevPrivateKeyRec glamor_egl_pixmap_private_key_index;
+DevPrivateKey glamor_egl_pixmap_private_key = &glamor_egl_pixmap_private_key_index;
+
+static void
+glamor_identify(int flags)
+{
+ xf86Msg(X_INFO, "%s: OpenGL accelerated X.org driver based.\n",
+ glamor_name);
+}
+
+struct glamor_egl_screen_private {
+ EGLDisplay display;
+ EGLContext context;
+ EGLint major, minor;
+
+ CreateScreenResourcesProcPtr CreateScreenResources;
+ CloseScreenProcPtr CloseScreen;
+ int fd;
+ EGLImageKHR front_image;
+ PixmapPtr *back_pixmap;
+ int cpp;
+#ifdef GLAMOR_HAS_GBM
+ struct gbm_device *gbm;
+#endif
+ int has_gem;
+ void *glamor_context;
+ void *current_context;
+ int gl_context_depth;
+ int dri3_capable;
+
+ PFNEGLCREATEIMAGEKHRPROC egl_create_image_khr;
+ PFNEGLDESTROYIMAGEKHRPROC egl_destroy_image_khr;
+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC egl_image_target_texture2d_oes;
+ struct glamor_gl_dispatch *dispatch;
+ CloseScreenProcPtr saved_close_screen;
+ xf86FreeScreenProc *saved_free_screen;
+};
+
+int xf86GlamorEGLPrivateIndex = -1;
+
+static struct glamor_egl_screen_private *
+glamor_egl_get_screen_private(ScrnInfoPtr scrn)
+{
+ return (struct glamor_egl_screen_private *)
+ scrn->privates[xf86GlamorEGLPrivateIndex].ptr;
+}
+#ifdef GLX_USE_SHARED_DISPATCH
+_X_EXPORT void
+glamor_egl_make_current(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_egl_screen_private *glamor_egl =
+ glamor_egl_get_screen_private(scrn);
+
+ if (glamor_egl->gl_context_depth++)
+ return;
+
+ GET_CURRENT_CONTEXT(glamor_egl->current_context);
+
+ if (glamor_egl->glamor_context != glamor_egl->current_context) {
+ eglMakeCurrent(glamor_egl->display, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ if (!eglMakeCurrent(glamor_egl->display,
+ EGL_NO_SURFACE, EGL_NO_SURFACE,
+ glamor_egl->context)) {
+ FatalError("Failed to make EGL context current\n");
+ }
+ }
+}
+
+_X_EXPORT void
+glamor_egl_restore_context(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_egl_screen_private *glamor_egl =
+ glamor_egl_get_screen_private(scrn);
+
+ if (--glamor_egl->gl_context_depth)
+ return;
+
+ if (glamor_egl->current_context &&
+ glamor_egl->glamor_context != glamor_egl->current_context)
+ SET_CURRENT_CONTEXT(glamor_egl->current_context);
+}
+#else
+#define glamor_egl_make_current(x)
+#define glamor_egl_restore_context(s)
+#endif
+
+static EGLImageKHR
+_glamor_egl_create_image(struct glamor_egl_screen_private *glamor_egl,
+ int width, int height, int stride, int name, int depth)
+{
+ EGLImageKHR image;
+ EGLint attribs[] = {
+ EGL_WIDTH, 0,
+ EGL_HEIGHT, 0,
+ EGL_DRM_BUFFER_STRIDE_MESA, 0,
+ EGL_DRM_BUFFER_FORMAT_MESA,
+ EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
+ EGL_DRM_BUFFER_USE_MESA,
+ EGL_DRM_BUFFER_USE_SHARE_MESA |
+ EGL_DRM_BUFFER_USE_SCANOUT_MESA,
+ EGL_NONE
+ };
+ attribs[1] = width;
+ attribs[3] = height;
+ attribs[5] = stride;
+ if (depth != 32 && depth != 24)
+ return EGL_NO_IMAGE_KHR;
+ image = glamor_egl->egl_create_image_khr(glamor_egl->display,
+ glamor_egl->context,
+ EGL_DRM_BUFFER_MESA,
+ (void *) (uintptr_t)name, attribs);
+ if (image == EGL_NO_IMAGE_KHR)
+ return EGL_NO_IMAGE_KHR;
+
+
+ return image;
+}
+
+static int
+glamor_get_flink_name(int fd, int handle, int *name)
+{
+ struct drm_gem_flink flink;
+ flink.handle = handle;
+ if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0)
+ return FALSE;
+ *name = flink.name;
+ return TRUE;
+}
+
+static Bool
+glamor_create_texture_from_image(struct glamor_egl_screen_private
+ *glamor_egl,
+ EGLImageKHR image, GLuint * texture)
+{
+ glamor_egl->dispatch->glGenTextures(1, texture);
+ glamor_egl->dispatch->glBindTexture(GL_TEXTURE_2D, *texture);
+ glamor_egl->dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glamor_egl->dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+
+ (glamor_egl->egl_image_target_texture2d_oes) (GL_TEXTURE_2D,
+ image);
+ glamor_egl->dispatch->glBindTexture(GL_TEXTURE_2D, 0);
+ return TRUE;
+}
+
+unsigned int
+glamor_egl_create_argb8888_based_texture(ScreenPtr screen,
+ int w,
+ int h)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_egl_screen_private *glamor_egl;
+ EGLImageKHR image;
+ GLuint texture;
+#ifdef GLAMOR_HAS_DRI3_SUPPORT
+ struct gbm_bo *bo;
+ EGLNativePixmapType native_pixmap;
+ glamor_egl = glamor_egl_get_screen_private(scrn);
+ bo = gbm_bo_create (glamor_egl->gbm, w, h, GBM_FORMAT_ARGB8888,
+ GBM_BO_USE_RENDERING |
+ GBM_BO_USE_SCANOUT);
+ if (!bo)
+ return 0;
+
+ /* If the following assignment raises an error or a warning
+ * then that means EGLNativePixmapType is not struct gbm_bo *
+ * on your platform: This code won't work and you should not
+ * compile with dri3 support enabled */
+ native_pixmap = bo;
+
+ image = glamor_egl->egl_create_image_khr(glamor_egl->display,
+ EGL_NO_CONTEXT,
+ EGL_NATIVE_PIXMAP_KHR,
+ native_pixmap, NULL);
+ gbm_bo_destroy(bo);
+ if (image == EGL_NO_IMAGE_KHR)
+ return 0;
+ glamor_create_texture_from_image(glamor_egl, image, &texture);
+ glamor_egl->egl_destroy_image_khr(glamor_egl->display, image);
+
+ return texture;
+#else
+ return 0; /* this path should never happen */
+#endif
+}
+
+Bool
+glamor_egl_create_textured_screen(ScreenPtr screen, int handle, int stride)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_egl_screen_private *glamor_egl;
+ PixmapPtr screen_pixmap;
+
+ glamor_egl = glamor_egl_get_screen_private(scrn);
+ screen_pixmap = screen->GetScreenPixmap(screen);
+
+ if (!glamor_egl_create_textured_pixmap(screen_pixmap, handle, stride)) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create textured screen.");
+ return FALSE;
+ }
+
+ glamor_egl->front_image = dixLookupPrivate(&screen_pixmap->devPrivates,
+ glamor_egl_pixmap_private_key);
+ glamor_set_screen_pixmap(screen_pixmap, glamor_egl->back_pixmap);
+ return TRUE;
+}
+
+Bool
+glamor_egl_create_textured_screen_ext(ScreenPtr screen,
+ int handle,
+ int stride,
+ PixmapPtr *back_pixmap)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_egl_screen_private *glamor_egl;
+
+ glamor_egl = glamor_egl_get_screen_private(scrn);
+
+ glamor_egl->back_pixmap = back_pixmap;
+ if (!glamor_egl_create_textured_screen(screen, handle, stride))
+ return FALSE;
+ return TRUE;
+}
+
+static Bool
+glamor_egl_check_has_gem(int fd)
+{
+ struct drm_gem_flink flink;
+ flink.handle = 0;
+
+ ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
+ if (errno == ENOENT || errno == EINVAL)
+ return TRUE;
+ return FALSE;
+}
+
+Bool
+glamor_egl_create_textured_pixmap(PixmapPtr pixmap, int handle, int stride)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_egl_screen_private *glamor_egl;
+ EGLImageKHR image;
+ GLuint texture;
+ int name;
+ Bool ret = FALSE;
+
+ glamor_egl = glamor_egl_get_screen_private(scrn);
+
+ glamor_egl_make_current(screen);
+ if (glamor_egl->has_gem) {
+ if (!glamor_get_flink_name(glamor_egl->fd, handle, &name)) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Couldn't flink pixmap handle\n");
+ glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
+ assert(0);
+ return FALSE;
+ }
+ } else
+ name = handle;
+
+ image = _glamor_egl_create_image(glamor_egl,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ ((stride * 8 + 7) / pixmap->drawable.bitsPerPixel),
+ name,
+ pixmap->drawable.depth);
+ if (image == EGL_NO_IMAGE_KHR) {
+ glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
+ goto done;
+ }
+ glamor_create_texture_from_image(glamor_egl, image, &texture);
+ glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
+ glamor_set_pixmap_texture(pixmap, texture);
+ dixSetPrivate(&pixmap->devPrivates, glamor_egl_pixmap_private_key,
+ image);
+ ret = TRUE;
+
+done:
+ glamor_egl_restore_context(screen);
+ return ret;
+}
+
+Bool
+glamor_egl_create_textured_pixmap_from_gbm_bo(PixmapPtr pixmap, void *bo)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_egl_screen_private *glamor_egl;
+ EGLImageKHR image;
+ GLuint texture;
+ Bool ret = FALSE;
+
+ glamor_egl = glamor_egl_get_screen_private(scrn);
+
+ glamor_egl_make_current(screen);
+
+ image = glamor_egl->egl_create_image_khr(glamor_egl->display,
+ glamor_egl->context,
+ EGL_NATIVE_PIXMAP_KHR,
+ bo, NULL);
+ if (image == EGL_NO_IMAGE_KHR) {
+ glamor_set_pixmap_type(pixmap, GLAMOR_DRM_ONLY);
+ goto done;
+ }
+ glamor_create_texture_from_image(glamor_egl, image, &texture);
+ glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
+ glamor_set_pixmap_texture(pixmap, texture);
+ dixSetPrivate(&pixmap->devPrivates, glamor_egl_pixmap_private_key,
+ image);
+ ret = TRUE;
+
+done:
+ glamor_egl_restore_context(screen);
+ return ret;
+}
+
+#ifdef GLAMOR_HAS_DRI3_SUPPORT
+int glamor_get_fd_from_bo (int gbm_fd, struct gbm_bo *bo, int *fd);
+void glamor_get_name_from_bo (int gbm_fd, struct gbm_bo *bo, int *name);
+int
+glamor_get_fd_from_bo (int gbm_fd, struct gbm_bo *bo, int *fd)
+{
+ union gbm_bo_handle handle;
+ struct drm_prime_handle args;
+
+ handle = gbm_bo_get_handle(bo);
+ args.handle = handle.u32;
+ args.flags = DRM_CLOEXEC;
+ if (ioctl (gbm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args))
+ return FALSE;
+ *fd = args.fd;
+ return TRUE;
+}
+
+void
+glamor_get_name_from_bo (int gbm_fd, struct gbm_bo *bo, int *name)
+{
+ union gbm_bo_handle handle;
+
+ handle = gbm_bo_get_handle(bo);
+ if (!glamor_get_flink_name(gbm_fd, handle.u32, name))
+ *name = -1;
+}
+#endif
+
+int glamor_egl_dri3_fd_name_from_tex (ScreenPtr screen,
+ PixmapPtr pixmap,
+ unsigned int tex,
+ Bool want_name,
+ CARD16 *stride,
+ CARD32 *size)
+{
+#ifdef GLAMOR_HAS_DRI3_SUPPORT
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_egl_screen_private *glamor_egl;
+ EGLImageKHR image;
+ struct gbm_bo* bo;
+ int fd = -1;
+
+ EGLint attribs[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_GL_TEXTURE_LEVEL_KHR, 0,
+ EGL_NONE
+ };
+
+ glamor_egl = glamor_egl_get_screen_private(scrn);
+
+ glamor_egl_make_current(screen);
+
+ image = dixLookupPrivate(&pixmap->devPrivates,
+ glamor_egl_pixmap_private_key);
+
+ if (image == EGL_NO_IMAGE_KHR || image == NULL)
+ {
+ image = glamor_egl->egl_create_image_khr(glamor_egl->display,
+ glamor_egl->context,
+ EGL_GL_TEXTURE_2D_KHR,
+ (EGLClientBuffer)(uintptr_t)tex, attribs);
+ if (image == EGL_NO_IMAGE_KHR)
+ goto failure;
+
+ dixSetPrivate(&pixmap->devPrivates,
+ glamor_egl_pixmap_private_key,
+ image);
+ glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM);
+ }
+
+ bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, image, 0);
+ if (!bo)
+ goto failure;
+
+ pixmap->devKind = gbm_bo_get_stride(bo);
+
+ if (want_name)
+ {
+ if (glamor_egl->has_gem)
+ glamor_get_name_from_bo(glamor_egl->fd, bo, &fd);
+ }
+ else
+ {
+ if (glamor_get_fd_from_bo(glamor_egl->fd, bo, &fd))
+ {
+ *stride = pixmap->devKind;
+ *size = pixmap->devKind * gbm_bo_get_height(bo);
+ }
+ }
+
+ gbm_bo_destroy(bo);
+failure:
+ glamor_egl_restore_context(screen);
+ return fd;
+#else
+ return -1;
+#endif
+}
+
+PixmapPtr glamor_egl_dri3_pixmap_from_fd (ScreenPtr screen,
+ int fd,
+ CARD16 width,
+ CARD16 height,
+ CARD16 stride,
+ CARD8 depth,
+ CARD8 bpp)
+{
+#ifdef GLAMOR_HAS_DRI3_SUPPORT
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_egl_screen_private *glamor_egl;
+ struct gbm_bo* bo;
+ EGLImageKHR image;
+ PixmapPtr pixmap;
+ Bool ret = FALSE;
+ EGLint attribs[] = {
+ EGL_WIDTH, 0,
+ EGL_HEIGHT, 0,
+ EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
+ EGL_DMA_BUF_PLANE0_FD_EXT, 0,
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
+ EGL_DMA_BUF_PLANE0_PITCH_EXT, 0,
+ EGL_NONE
+ };
+
+ glamor_egl = glamor_egl_get_screen_private(scrn);
+
+ if (!glamor_egl->dri3_capable)
+ return NULL;
+
+ if (bpp != 32 || !(depth == 24 || depth == 32) || width == 0 || height == 0)
+ return NULL;
+
+ attribs[1] = width;
+ attribs[3] = height;
+ attribs[7] = fd;
+ attribs[11] = stride;
+ image = glamor_egl->egl_create_image_khr(glamor_egl->display,
+ EGL_NO_CONTEXT,
+ EGL_LINUX_DMA_BUF_EXT,
+ NULL, attribs);
+
+ if (image == EGL_NO_IMAGE_KHR)
+ return NULL;
+
+ /* EGL_EXT_image_dma_buf_import can impose restrictions on the
+ * usage of the image. Use gbm_bo to bypass the limitations. */
+
+ bo = gbm_bo_import(glamor_egl->gbm, GBM_BO_IMPORT_EGL_IMAGE, image, 0);
+ glamor_egl->egl_destroy_image_khr(glamor_egl->display, image);
+
+ if (!bo)
+ return NULL;
+
+ pixmap = screen->CreatePixmap(screen, 0, 0, depth, 0);
+ screen->ModifyPixmapHeader (pixmap, width, height, 0, 0, stride, NULL);
+
+ ret = glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo);
+ gbm_bo_destroy(bo);
+
+ if (ret)
+ return pixmap;
+ else
+ {
+ screen->DestroyPixmap(pixmap);
+ return NULL;
+ }
+#else
+ return NULL;
+#endif
+}
+
+static void
+_glamor_egl_destroy_pixmap_image(PixmapPtr pixmap)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
+ EGLImageKHR image;
+ struct glamor_egl_screen_private *glamor_egl =
+ glamor_egl_get_screen_private(scrn);
+
+ image = dixLookupPrivate(&pixmap->devPrivates,
+ glamor_egl_pixmap_private_key);
+ if (image != EGL_NO_IMAGE_KHR && image != NULL) {
+ /* Before destroy an image which was attached to
+ * a texture. we must call glFlush to make sure the
+ * operation on that texture has been done.*/
+ glamor_block_handler(pixmap->drawable.pScreen);
+ glamor_egl->egl_destroy_image_khr(glamor_egl->display, image);
+ dixSetPrivate(&pixmap->devPrivates, glamor_egl_pixmap_private_key, NULL);
+ }
+}
+
+_X_EXPORT void
+glamor_egl_exchange_buffers(PixmapPtr front, PixmapPtr back)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(front->drawable.pScreen);
+ struct glamor_egl_screen_private *glamor_egl =
+ glamor_egl_get_screen_private(scrn);
+ EGLImageKHR old_front_image;
+ EGLImageKHR new_front_image;
+
+ glamor_pixmap_exchange_fbos(front, back);
+ new_front_image = dixLookupPrivate(&back->devPrivates, glamor_egl_pixmap_private_key);
+ old_front_image = dixLookupPrivate(&front->devPrivates, glamor_egl_pixmap_private_key);
+ dixSetPrivate(&front->devPrivates, glamor_egl_pixmap_private_key, new_front_image);
+ dixSetPrivate(&back->devPrivates, glamor_egl_pixmap_private_key, old_front_image);
+ glamor_set_pixmap_type(front, GLAMOR_TEXTURE_DRM);
+ glamor_set_pixmap_type(back, GLAMOR_TEXTURE_DRM);
+ glamor_egl->front_image = new_front_image;
+
+}
+
+void
+glamor_egl_destroy_textured_pixmap(PixmapPtr pixmap)
+{
+ if (pixmap->refcnt == 1)
+ _glamor_egl_destroy_pixmap_image(pixmap);
+ glamor_destroy_textured_pixmap(pixmap);
+}
+
+static Bool
+glamor_egl_close_screen(CLOSE_SCREEN_ARGS_DECL)
+{
+ ScrnInfoPtr scrn;
+ struct glamor_egl_screen_private *glamor_egl;
+ PixmapPtr screen_pixmap;
+ EGLImageKHR back_image;
+
+ scrn = xf86ScreenToScrn(screen);
+ glamor_egl = glamor_egl_get_screen_private(scrn);
+ screen_pixmap = screen->GetScreenPixmap(screen);
+
+ glamor_egl->egl_destroy_image_khr(glamor_egl->display, glamor_egl->front_image);
+ dixSetPrivate(&screen_pixmap->devPrivates, glamor_egl_pixmap_private_key, NULL);
+ glamor_egl->front_image = NULL;
+ if (glamor_egl->back_pixmap && *glamor_egl->back_pixmap) {
+ back_image = dixLookupPrivate(&(*glamor_egl->back_pixmap)->devPrivates,
+ glamor_egl_pixmap_private_key);
+ if (back_image != NULL && back_image != EGL_NO_IMAGE_KHR) {
+ glamor_egl->egl_destroy_image_khr(glamor_egl->display, back_image);
+ dixSetPrivate(&(*glamor_egl->back_pixmap)->devPrivates,
+ glamor_egl_pixmap_private_key, NULL);
+ }
+ }
+
+ screen->CloseScreen = glamor_egl->saved_close_screen;
+
+ return screen->CloseScreen(CLOSE_SCREEN_ARGS);
+}
+
+static Bool
+glamor_egl_has_extension(struct glamor_egl_screen_private *glamor_egl,
+ const char *extension)
+{
+ const char *pext;
+ int ext_len;
+
+ ext_len = strlen(extension);
+ pext =
+ (const char *) eglQueryString(glamor_egl->display,
+ EGL_EXTENSIONS);
+ if (pext == NULL || extension == NULL)
+ return FALSE;
+ while ((pext = strstr(pext, extension)) != NULL) {
+ if (pext[ext_len] == ' ' || pext[ext_len] == '\0')
+ return TRUE;
+ pext += ext_len;
+ }
+ return FALSE;
+}
+
+void
+glamor_egl_screen_init(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_egl_screen_private *glamor_egl =
+ glamor_egl_get_screen_private(scrn);
+
+ glamor_egl->saved_close_screen = screen->CloseScreen;
+ screen->CloseScreen = glamor_egl_close_screen;
+}
+
+static void
+glamor_egl_free_screen(FREE_SCREEN_ARGS_DECL)
+{
+ ScrnInfoPtr scrn;
+ struct glamor_egl_screen_private *glamor_egl;
+#ifndef XF86_SCRN_INTERFACE
+ scrn = xf86Screens[arg];
+#else
+ scrn = arg;
+#endif
+
+ glamor_egl = glamor_egl_get_screen_private(scrn);
+ if (glamor_egl != NULL) {
+
+ eglMakeCurrent(glamor_egl->display,
+ EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
+#ifdef GLAMOR_HAS_GBM
+ if (glamor_egl->gbm)
+ gbm_device_destroy(glamor_egl->gbm);
+#endif
+ scrn->FreeScreen = glamor_egl->saved_free_screen;
+ free(glamor_egl);
+ scrn->FreeScreen(FREE_SCREEN_ARGS);
+ }
+}
+
+Bool
+glamor_egl_init(ScrnInfoPtr scrn, int fd)
+{
+ struct glamor_egl_screen_private *glamor_egl;
+ const char *version;
+ EGLint config_attribs[] = {
+#ifdef GLAMOR_GLES2
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+#endif
+ EGL_NONE
+ };
+
+ glamor_identify(0);
+ glamor_egl = calloc(sizeof(*glamor_egl), 1);
+ if (glamor_egl == NULL)
+ return FALSE;
+ if (xf86GlamorEGLPrivateIndex == -1)
+ xf86GlamorEGLPrivateIndex =
+ xf86AllocateScrnInfoPrivateIndex();
+
+ scrn->privates[xf86GlamorEGLPrivateIndex].ptr = glamor_egl;
+ glamor_egl->fd = fd;
+#ifdef GLAMOR_HAS_GBM
+ glamor_egl->gbm = gbm_create_device(glamor_egl->fd);
+ if (glamor_egl->gbm == NULL) {
+ ErrorF("couldn't get display device\n");
+ return FALSE;
+ }
+ glamor_egl->display = eglGetDisplay(glamor_egl->gbm);
+#else
+ glamor_egl->display = eglGetDisplay((EGLNativeDisplayType)(intptr_t)fd);
+#endif
+
+ glamor_egl->has_gem = glamor_egl_check_has_gem(fd);
+
+#ifndef GLAMOR_GLES2
+ eglBindAPI(EGL_OPENGL_API);
+#else
+ eglBindAPI(EGL_OPENGL_ES_API);
+#endif
+ if (!eglInitialize
+ (glamor_egl->display, &glamor_egl->major, &glamor_egl->minor))
+ {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "eglInitialize() failed\n");
+ return FALSE;
+ }
+
+ version = eglQueryString(glamor_egl->display, EGL_VERSION);
+ xf86Msg(X_INFO, "%s: EGL version %s:\n", glamor_name, version);
+
+#define GLAMOR_CHECK_EGL_EXTENSION(EXT) \
+ if (!glamor_egl_has_extension(glamor_egl, "EGL_" #EXT)) { \
+ ErrorF("EGL_" #EXT " required.\n"); \
+ return FALSE; \
+ }
+
+#define GLAMOR_CHECK_EGL_EXTENSIONS(EXT1, EXT2) \
+ if (!glamor_egl_has_extension(glamor_egl, "EGL_" #EXT1) && \
+ !glamor_egl_has_extension(glamor_egl, "EGL_" #EXT2)) { \
+ ErrorF("EGL_" #EXT1 " or EGL_" #EXT2 " required.\n"); \
+ return FALSE; \
+ }
+
+ GLAMOR_CHECK_EGL_EXTENSION(MESA_drm_image);
+ GLAMOR_CHECK_EGL_EXTENSION(KHR_gl_renderbuffer_image);
+#ifdef GLAMOR_GLES2
+ GLAMOR_CHECK_EGL_EXTENSIONS(KHR_surfaceless_context, KHR_surfaceless_gles2);
+#else
+ GLAMOR_CHECK_EGL_EXTENSIONS(KHR_surfaceless_context, KHR_surfaceless_opengl);
+#endif
+
+#ifdef GLAMOR_HAS_DRI3_SUPPORT
+ if (glamor_egl_has_extension(glamor_egl, "EGL_KHR_gl_texture_2D_image") &&
+ glamor_egl_has_extension(glamor_egl, "EGL_EXT_image_dma_buf_import") )
+ glamor_egl->dri3_capable = TRUE;
+#endif
+ glamor_egl->egl_create_image_khr = (PFNEGLCREATEIMAGEKHRPROC)
+ eglGetProcAddress("eglCreateImageKHR");
+
+ glamor_egl->egl_destroy_image_khr = (PFNEGLDESTROYIMAGEKHRPROC)
+ eglGetProcAddress("eglDestroyImageKHR");
+
+ glamor_egl->egl_image_target_texture2d_oes =
+ (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)
+ eglGetProcAddress("glEGLImageTargetTexture2DOES");
+
+ if (!glamor_egl->egl_create_image_khr
+ || !glamor_egl->egl_image_target_texture2d_oes) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "eglGetProcAddress() failed\n");
+ return FALSE;
+ }
+
+ glamor_egl->context = eglCreateContext(glamor_egl->display,
+ NULL, EGL_NO_CONTEXT,
+ config_attribs);
+ if (glamor_egl->context == EGL_NO_CONTEXT) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Failed to create EGL context\n");
+ return FALSE;
+ }
+
+ if (!eglMakeCurrent(glamor_egl->display,
+ EGL_NO_SURFACE, EGL_NO_SURFACE,
+ glamor_egl->context)) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Failed to make EGL context current\n");
+ return FALSE;
+ }
+#ifdef GLX_USE_SHARED_DISPATCH
+ GET_CURRENT_CONTEXT(glamor_egl->glamor_context);
+#endif
+ glamor_egl->saved_free_screen = scrn->FreeScreen;
+ scrn->FreeScreen = glamor_egl_free_screen;
+#ifdef GLAMOR_GLES2
+ xf86DrvMsg(scrn->scrnIndex, X_INFO, "Using GLES2.\n");
+#ifdef GLX_USE_SHARED_DISPATCH
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Glamor is using GLES2 but GLX needs GL. "
+ "Indirect GLX may not work correctly.\n");
+#endif
+#endif
+ return TRUE;
+}
+
+Bool
+glamor_egl_init_textured_pixmap(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_egl_screen_private *glamor_egl =
+ glamor_egl_get_screen_private(scrn);
+ if (!dixRegisterPrivateKey
+ (glamor_egl_pixmap_private_key, PRIVATE_PIXMAP, 0)) {
+ LogMessage(X_WARNING,
+ "glamor%d: Failed to allocate egl pixmap private\n",
+ screen->myNum);
+ return FALSE;
+ }
+ if (glamor_egl->dri3_capable)
+ glamor_enable_dri3(screen);
+ return TRUE;
+}
+
+Bool
+glamor_gl_dispatch_init(ScreenPtr screen,
+ struct glamor_gl_dispatch *dispatch,
+ int gl_version)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ struct glamor_egl_screen_private *glamor_egl =
+ glamor_egl_get_screen_private(scrn);
+ if (!glamor_gl_dispatch_init_impl
+ (dispatch, gl_version, (get_proc_address_t)eglGetProcAddress))
+ return FALSE;
+ glamor_egl->dispatch = dispatch;
+ return TRUE;
+}
diff --git a/glamor/glamor_eglmodule.c b/glamor/glamor_eglmodule.c
new file mode 100644
index 000000000..9a0dec9f2
--- /dev/null
+++ b/glamor/glamor_eglmodule.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 1998 The XFree86 Project, Inc. All Rights Reserved.
+ *
+ * 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
+ * XFREE86 PROJECT 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.
+ *
+ * Except as contained in this notice, the name of the XFree86 Project shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization from the
+ * XFree86 Project.
+ *
+ * Authors:
+ * Zhigang Gong <zhigang.gong@gmail.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xorg-server.h>
+#define GLAMOR_FOR_XORG
+#include <xf86Module.h>
+#include "glamor.h"
+
+static XF86ModuleVersionInfo VersRec = {
+ GLAMOR_EGL_MODULE_NAME,
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
+ ABI_CLASS_ANSIC, /* Only need the ansic layer */
+ ABI_ANSIC_VERSION,
+ MOD_CLASS_NONE,
+ {0, 0, 0, 0} /* signature, to be patched into the file by a tool */
+};
+
+_X_EXPORT XF86ModuleData glamoreglModuleData = { &VersRec, NULL, NULL };
diff --git a/glamor/glamor_fbo.c b/glamor/glamor_fbo.c
new file mode 100644
index 000000000..d1b087ebe
--- /dev/null
+++ b/glamor/glamor_fbo.c
@@ -0,0 +1,590 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@gmail.com>
+ *
+ */
+
+#include <stdlib.h>
+
+#include "glamor_priv.h"
+
+#define GLAMOR_CACHE_EXPIRE_MAX 100
+
+#define GLAMOR_CACHE_DEFAULT 0
+#define GLAMOR_CACHE_EXACT_SIZE 1
+
+//#define NO_FBO_CACHE 1
+#define FBO_CACHE_THRESHOLD (256*1024*1024)
+
+/* Loop from the tail to the head. */
+#define xorg_list_for_each_entry_reverse(pos, head, member) \
+ for (pos = __container_of((head)->prev, pos, member); \
+ &pos->member != (head); \
+ pos = __container_of(pos->member.prev, pos, member))
+
+
+#define xorg_list_for_each_entry_safe_reverse(pos, tmp, head, member) \
+ for (pos = __container_of((head)->prev, pos, member), \
+ tmp = __container_of(pos->member.prev, pos, member); \
+ &pos->member != (head); \
+ pos = tmp, tmp = __container_of(pos->member.prev, tmp, member))
+
+inline static int cache_wbucket(int size)
+{
+ int order = __fls(size / 32);
+ if (order >= CACHE_BUCKET_WCOUNT)
+ order = CACHE_BUCKET_WCOUNT - 1;
+ return order;
+}
+
+inline static int cache_hbucket(int size)
+{
+ int order = __fls(size / 32);
+ if (order >= CACHE_BUCKET_HCOUNT)
+ order = CACHE_BUCKET_HCOUNT - 1;
+ return order;
+}
+
+static glamor_pixmap_fbo *
+glamor_pixmap_fbo_cache_get(glamor_screen_private *glamor_priv,
+ int w, int h, GLenum format, int flag)
+{
+ struct xorg_list *cache;
+ glamor_pixmap_fbo *fbo_entry, *ret_fbo = NULL;
+ int n_format;
+#ifdef NO_FBO_CACHE
+ return NULL;
+#else
+ n_format = cache_format(format);
+ if (n_format == -1)
+ return NULL;
+ cache = &glamor_priv->fbo_cache[n_format]
+ [cache_wbucket(w)]
+ [cache_hbucket(h)];
+ if (!(flag & GLAMOR_CACHE_EXACT_SIZE)) {
+ xorg_list_for_each_entry(fbo_entry, cache, list) {
+ if (fbo_entry->width >= w && fbo_entry->height >= h) {
+
+ DEBUGF("Request w %d h %d format %x \n", w, h, format);
+ DEBUGF("got cache entry %p w %d h %d fbo %d tex %d format %x\n",
+ fbo_entry, fbo_entry->width, fbo_entry->height,
+ fbo_entry->fb, fbo_entry->tex);
+ xorg_list_del(&fbo_entry->list);
+ ret_fbo = fbo_entry;
+ break;
+ }
+ }
+ }
+ else {
+ xorg_list_for_each_entry(fbo_entry, cache, list) {
+ if (fbo_entry->width == w && fbo_entry->height == h) {
+
+ DEBUGF("Request w %d h %d format %x \n", w, h, format);
+ DEBUGF("got cache entry %p w %d h %d fbo %d tex %d format %x\n",
+ fbo_entry, fbo_entry->width, fbo_entry->height,
+ fbo_entry->fb, fbo_entry->tex, fbo_entry->format);
+ assert(format == fbo_entry->format);
+ xorg_list_del(&fbo_entry->list);
+ ret_fbo = fbo_entry;
+ break;
+ }
+ }
+ }
+
+ if (ret_fbo)
+ glamor_priv->fbo_cache_watermark -= ret_fbo->width * ret_fbo->height;
+
+ assert(glamor_priv->fbo_cache_watermark >= 0);
+
+ return ret_fbo;
+#endif
+}
+
+void
+glamor_purge_fbo(glamor_pixmap_fbo *fbo)
+{
+ glamor_gl_dispatch *dispatch = glamor_get_dispatch(fbo->glamor_priv);
+ if (fbo->fb)
+ dispatch->glDeleteFramebuffers(1, &fbo->fb);
+ if (fbo->tex)
+ dispatch->glDeleteTextures(1, &fbo->tex);
+ if (fbo->pbo)
+ dispatch->glDeleteBuffers(1, &fbo->pbo);
+ glamor_put_dispatch(fbo->glamor_priv);
+
+ free(fbo);
+}
+
+static void
+glamor_pixmap_fbo_cache_put(glamor_pixmap_fbo *fbo)
+{
+ struct xorg_list *cache;
+ int n_format;
+
+#ifdef NO_FBO_CACHE
+ glamor_purge_fbo(fbo);
+ return;
+#else
+ n_format = cache_format(fbo->format);
+
+ if (fbo->fb == 0 || n_format == -1
+ || fbo->glamor_priv->fbo_cache_watermark >= FBO_CACHE_THRESHOLD) {
+ fbo->glamor_priv->tick += GLAMOR_CACHE_EXPIRE_MAX;
+ glamor_fbo_expire(fbo->glamor_priv);
+ glamor_purge_fbo(fbo);
+ return;
+ }
+
+ cache = &fbo->glamor_priv->fbo_cache[n_format]
+ [cache_wbucket(fbo->width)]
+ [cache_hbucket(fbo->height)];
+ DEBUGF("Put cache entry %p to cache %p w %d h %d format %x fbo %d tex %d \n", fbo, cache,
+ fbo->width, fbo->height, fbo->format, fbo->fb, fbo->tex);
+
+ fbo->glamor_priv->fbo_cache_watermark += fbo->width * fbo->height;
+ xorg_list_add(&fbo->list, cache);
+ fbo->expire = fbo->glamor_priv->tick + GLAMOR_CACHE_EXPIRE_MAX;
+#endif
+}
+
+static void
+glamor_pixmap_ensure_fb(glamor_pixmap_fbo *fbo)
+{
+ glamor_gl_dispatch *dispatch;
+ int status;
+
+ dispatch = glamor_get_dispatch(fbo->glamor_priv);
+
+ if (fbo->fb == 0)
+ dispatch->glGenFramebuffers(1, &fbo->fb);
+ assert(fbo->tex != 0);
+ dispatch->glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
+ dispatch->glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, fbo->tex,
+ 0);
+ status = dispatch->glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ const char *str;
+ switch (status) {
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+ str = "incomplete attachment";
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+ str = "incomplete/missing attachment";
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
+ str = "incomplete draw buffer";
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
+ str = "incomplete read buffer";
+ break;
+ case GL_FRAMEBUFFER_UNSUPPORTED:
+ str = "unsupported";
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
+ str = "incomplete multiple";
+ break;
+ default:
+ str = "unknown error";
+ break;
+ }
+
+ FatalError("destination is framebuffer incomplete: %s [%x]\n",
+ str, status);
+ }
+ glamor_put_dispatch(fbo->glamor_priv);
+}
+
+glamor_pixmap_fbo *
+glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv,
+ int w, int h, GLenum format, GLint tex, int flag)
+{
+ glamor_pixmap_fbo *fbo;
+
+ fbo = calloc(1, sizeof(*fbo));
+ if (fbo == NULL)
+ return NULL;
+
+ xorg_list_init(&fbo->list);
+
+ fbo->tex = tex;
+ fbo->width = w;
+ fbo->height = h;
+ fbo->format = format;
+ fbo->glamor_priv = glamor_priv;
+
+ if (flag == GLAMOR_CREATE_PIXMAP_MAP) {
+ glamor_gl_dispatch *dispatch;
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glGenBuffers(1, &fbo->pbo);
+ glamor_put_dispatch(glamor_priv);
+ goto done;
+ }
+
+ if (flag != GLAMOR_CREATE_FBO_NO_FBO)
+ glamor_pixmap_ensure_fb(fbo);
+
+done:
+ return fbo;
+}
+
+
+void
+glamor_fbo_expire(glamor_screen_private *glamor_priv)
+{
+ struct xorg_list *cache;
+ glamor_pixmap_fbo *fbo_entry, *tmp;
+ int i,j,k;
+
+ for(i = 0; i < CACHE_FORMAT_COUNT; i++)
+ for(j = 0; j < CACHE_BUCKET_WCOUNT; j++)
+ for(k = 0; k < CACHE_BUCKET_HCOUNT; k++) {
+ cache = &glamor_priv->fbo_cache[i][j][k];
+ xorg_list_for_each_entry_safe_reverse(fbo_entry, tmp, cache, list) {
+ if (GLAMOR_TICK_AFTER(fbo_entry->expire, glamor_priv->tick)) {
+ break;
+ }
+
+ glamor_priv->fbo_cache_watermark -= fbo_entry->width * fbo_entry->height;
+ xorg_list_del(&fbo_entry->list);
+ DEBUGF("cache %p fbo %p expired %d current %d \n", cache, fbo_entry,
+ fbo_entry->expire, glamor_priv->tick);
+ glamor_purge_fbo(fbo_entry);
+ }
+ }
+
+}
+
+void
+glamor_init_pixmap_fbo(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ int i,j,k;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ for(i = 0; i < CACHE_FORMAT_COUNT; i++)
+ for(j = 0; j < CACHE_BUCKET_WCOUNT; j++)
+ for(k = 0; k < CACHE_BUCKET_HCOUNT; k++)
+ {
+ xorg_list_init(&glamor_priv->fbo_cache[i][j][k]);
+ }
+ glamor_priv->fbo_cache_watermark = 0;
+}
+
+void
+glamor_fini_pixmap_fbo(ScreenPtr screen)
+{
+ struct xorg_list *cache;
+ glamor_screen_private *glamor_priv;
+ glamor_pixmap_fbo *fbo_entry, *tmp;
+ int i,j,k;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ for(i = 0; i < CACHE_FORMAT_COUNT; i++)
+ for(j = 0; j < CACHE_BUCKET_WCOUNT; j++)
+ for(k = 0; k < CACHE_BUCKET_HCOUNT; k++)
+ {
+ cache = &glamor_priv->fbo_cache[i][j][k];
+ xorg_list_for_each_entry_safe_reverse(fbo_entry, tmp, cache, list) {
+ xorg_list_del(&fbo_entry->list);
+ glamor_purge_fbo(fbo_entry);
+ }
+ }
+}
+
+void
+glamor_destroy_fbo(glamor_pixmap_fbo *fbo)
+{
+ xorg_list_del(&fbo->list);
+ glamor_pixmap_fbo_cache_put(fbo);
+
+}
+
+static int
+_glamor_create_tex(glamor_screen_private *glamor_priv,
+ int w, int h, GLenum format)
+{
+ glamor_gl_dispatch *dispatch;
+ unsigned int tex = 0;
+
+ /* With dri3, we want to allocate ARGB8888 pixmaps only.
+ * Depending on the implementation, GL_RGBA might not
+ * give us ARGB8888. We ask glamor_egl to use get
+ * an ARGB8888 based texture for us. */
+ if (glamor_priv->dri3_enabled && format == GL_RGBA)
+ {
+ tex = glamor_egl_create_argb8888_based_texture(glamor_priv->screen,
+ w, h);
+ }
+ if (!tex)
+ {
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glGenTextures(1, &tex);
+ dispatch->glBindTexture(GL_TEXTURE_2D, tex);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ dispatch->glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0,
+ format, GL_UNSIGNED_BYTE, NULL);
+ glamor_put_dispatch(glamor_priv);
+ }
+ return tex;
+}
+
+glamor_pixmap_fbo *
+glamor_create_fbo(glamor_screen_private *glamor_priv,
+ int w, int h,
+ GLenum format,
+ int flag)
+{
+ glamor_pixmap_fbo *fbo;
+ GLint tex = 0;
+ int cache_flag;
+
+ if (!glamor_check_fbo_size(glamor_priv, w, h))
+ return NULL;
+
+ if (flag == GLAMOR_CREATE_FBO_NO_FBO)
+ goto new_fbo;
+
+ if (flag == GLAMOR_CREATE_PIXMAP_MAP)
+ goto no_tex;
+
+ if (flag == GLAMOR_CREATE_PIXMAP_FIXUP)
+ cache_flag = GLAMOR_CACHE_EXACT_SIZE;
+ else
+ cache_flag = 0;
+
+ fbo = glamor_pixmap_fbo_cache_get(glamor_priv, w, h,
+ format, cache_flag);
+ if (fbo)
+ return fbo;
+new_fbo:
+ tex = _glamor_create_tex(glamor_priv, w, h, format);
+no_tex:
+ fbo = glamor_create_fbo_from_tex(glamor_priv, w, h, format, tex, flag);
+
+ return fbo;
+}
+
+static glamor_pixmap_fbo *
+_glamor_create_fbo_array(glamor_screen_private *glamor_priv,
+ int w, int h, GLenum format, int flag,
+ int block_w, int block_h,
+ glamor_pixmap_private *pixmap_priv,
+ int has_fbo)
+{
+ int block_wcnt;
+ int block_hcnt;
+ glamor_pixmap_fbo **fbo_array;
+ BoxPtr box_array;
+ int i,j;
+ glamor_pixmap_private_large_t *priv;
+
+ priv = &pixmap_priv->large;
+
+ block_wcnt = (w + block_w - 1) / block_w;
+ block_hcnt = (h + block_h - 1) / block_h;
+
+ box_array = calloc(block_wcnt * block_hcnt, sizeof(box_array[0]));
+ if (box_array == NULL)
+ return NULL;
+
+ fbo_array = calloc(block_wcnt * block_hcnt, sizeof(glamor_pixmap_fbo*));
+ if (fbo_array == NULL) {
+ free(box_array);
+ return FALSE;
+ }
+ for(i = 0; i < block_hcnt; i++)
+ {
+ int block_y1, block_y2;
+ int fbo_w, fbo_h;
+
+ block_y1 = i * block_h;
+ block_y2 = (block_y1 + block_h) > h ? h : (block_y1 + block_h);
+ fbo_h = block_y2 - block_y1;
+
+ for (j = 0; j < block_wcnt; j++)
+ {
+ box_array[i * block_wcnt + j].x1 = j * block_w;
+ box_array[i * block_wcnt + j].y1 = block_y1;
+ box_array[i * block_wcnt + j].x2 = (j + 1) * block_w > w ? w : (j + 1) * block_w;
+ box_array[i * block_wcnt + j].y2 = block_y2;
+ fbo_w = box_array[i * block_wcnt + j].x2 - box_array[i * block_wcnt + j].x1;
+ if (!has_fbo)
+ fbo_array[i * block_wcnt + j] = glamor_create_fbo(glamor_priv,
+ fbo_w, fbo_h, format,
+ GLAMOR_CREATE_PIXMAP_FIXUP);
+ else
+ fbo_array[i * block_wcnt + j] = priv->base.fbo;
+ if (fbo_array[i * block_wcnt + j] == NULL)
+ goto cleanup;
+ }
+ }
+
+ priv->box = box_array[0];
+ priv->box_array = box_array;
+ priv->fbo_array = fbo_array;
+ priv->block_wcnt = block_wcnt;
+ priv->block_hcnt = block_hcnt;
+ return fbo_array[0];
+
+cleanup:
+ for(i = 0; i < block_wcnt * block_hcnt; i++)
+ if ((fbo_array)[i])
+ glamor_destroy_fbo((fbo_array)[i]);
+ free(box_array);
+ free(fbo_array);
+ return NULL;
+}
+
+
+/* Create a fbo array to cover the w*h region, by using block_w*block_h
+ * block.*/
+glamor_pixmap_fbo *
+glamor_create_fbo_array(glamor_screen_private *glamor_priv,
+ int w, int h, GLenum format, int flag,
+ int block_w, int block_h,
+ glamor_pixmap_private *pixmap_priv)
+{
+ pixmap_priv->large.block_w = block_w;
+ pixmap_priv->large.block_h = block_h;
+ return _glamor_create_fbo_array(glamor_priv, w, h, format, flag,
+ block_w, block_h, pixmap_priv, 0);
+}
+
+glamor_pixmap_fbo *
+glamor_pixmap_detach_fbo(glamor_pixmap_private *pixmap_priv)
+{
+ glamor_pixmap_fbo *fbo;
+
+ if (pixmap_priv == NULL)
+ return NULL;
+
+ fbo = pixmap_priv->base.fbo;
+ if (fbo == NULL)
+ return NULL;
+
+ pixmap_priv->base.fbo = NULL;
+ return fbo;
+}
+
+/* The pixmap must not be attached to another fbo. */
+void
+glamor_pixmap_attach_fbo(PixmapPtr pixmap, glamor_pixmap_fbo *fbo)
+{
+ glamor_pixmap_private *pixmap_priv;
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ if (pixmap_priv->base.fbo)
+ return;
+
+ pixmap_priv->base.fbo = fbo;
+
+ switch (pixmap_priv->type) {
+ case GLAMOR_TEXTURE_LARGE:
+ case GLAMOR_TEXTURE_ONLY:
+ case GLAMOR_TEXTURE_DRM:
+ pixmap_priv->base.gl_fbo = 1;
+ if (fbo->tex != 0)
+ pixmap_priv->base.gl_tex = 1;
+ else {
+ /* XXX For the Xephyr only, may be broken now.*/
+ pixmap_priv->base.gl_tex = 0;
+ }
+ case GLAMOR_MEMORY_MAP:
+ pixmap->devPrivate.ptr = NULL;
+ break;
+ default:
+ break;
+ }
+}
+
+void
+glamor_pixmap_destroy_fbo(glamor_pixmap_private *priv)
+{
+ glamor_pixmap_fbo *fbo;
+ if (priv->type == GLAMOR_TEXTURE_LARGE) {
+ int i;
+ glamor_pixmap_private_large_t *large = &priv->large;
+ for(i = 0; i < large->block_wcnt * large->block_hcnt; i++)
+ glamor_destroy_fbo(large->fbo_array[i]);
+ free(large->fbo_array);
+ } else {
+ fbo = glamor_pixmap_detach_fbo(priv);
+ if (fbo)
+ glamor_destroy_fbo(fbo);
+ }
+
+ free(priv);
+}
+
+Bool
+glamor_pixmap_ensure_fbo(PixmapPtr pixmap, GLenum format, int flag)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_pixmap_private *pixmap_priv;
+ glamor_pixmap_fbo *fbo;
+
+ glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ if (pixmap_priv->base.fbo == NULL) {
+
+ fbo = glamor_create_fbo(glamor_priv, pixmap->drawable.width,
+ pixmap->drawable.height,
+ format,
+ flag);
+ if (fbo == NULL)
+ return FALSE;
+
+ glamor_pixmap_attach_fbo(pixmap, fbo);
+ } else {
+ /* We do have a fbo, but it may lack of fb or tex. */
+ if (!pixmap_priv->base.fbo->tex)
+ pixmap_priv->base.fbo->tex = _glamor_create_tex(glamor_priv, pixmap->drawable.width,
+ pixmap->drawable.height, format);
+
+ if (flag != GLAMOR_CREATE_FBO_NO_FBO && pixmap_priv->base.fbo->fb == 0)
+ glamor_pixmap_ensure_fb(pixmap_priv->base.fbo);
+ }
+
+ return TRUE;
+}
+
+_X_EXPORT void
+glamor_pixmap_exchange_fbos(PixmapPtr front, PixmapPtr back)
+{
+ glamor_pixmap_private *front_priv, *back_priv;
+ glamor_pixmap_fbo *temp_fbo;
+
+ front_priv = glamor_get_pixmap_private(front);
+ back_priv = glamor_get_pixmap_private(back);
+ temp_fbo = front_priv->base.fbo;
+ front_priv->base.fbo = back_priv->base.fbo;
+ back_priv->base.fbo = temp_fbo;
+}
diff --git a/glamor/glamor_fill.c b/glamor/glamor_fill.c
new file mode 100644
index 000000000..fbc87392e
--- /dev/null
+++ b/glamor/glamor_fill.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ */
+
+#include "glamor_priv.h"
+
+/** @file glamor_fillspans.c
+ *
+ * GC fill implementation, based loosely on fb_fill.c
+ */
+Bool
+glamor_fill(DrawablePtr drawable,
+ GCPtr gc, int x, int y, int width, int height, Bool fallback)
+{
+ PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(drawable);
+ int off_x, off_y;
+ PixmapPtr sub_pixmap = NULL;
+ glamor_access_t sub_pixmap_access;
+ DrawablePtr saved_drawable = NULL;
+ int saved_x = x, saved_y = y;
+
+ glamor_get_drawable_deltas(drawable, dst_pixmap, &off_x, &off_y);
+
+ switch (gc->fillStyle) {
+ case FillSolid:
+ if (!glamor_solid(dst_pixmap,
+ x + off_x,
+ y + off_y,
+ width, height, gc->alu, gc->planemask,
+ gc->fgPixel))
+ goto fail;
+ break;
+ case FillStippled:
+ case FillOpaqueStippled:
+ if (!glamor_stipple(dst_pixmap,
+ gc->stipple,
+ x + off_x,
+ y + off_y,
+ width,
+ height,
+ gc->alu,
+ gc->planemask,
+ gc->fgPixel,
+ gc->bgPixel, gc->patOrg.x,
+ gc->patOrg.y))
+ goto fail;
+ break;
+ case FillTiled:
+ if (!glamor_tile(dst_pixmap,
+ gc->tile.pixmap,
+ x + off_x,
+ y + off_y,
+ width,
+ height,
+ gc->alu,
+ gc->planemask,
+ x - drawable->x - gc->patOrg.x,
+ y - drawable->y - gc->patOrg.y))
+ goto fail;
+ break;
+ }
+ return TRUE;
+
+ fail:
+ if (!fallback) {
+ if (glamor_ddx_fallback_check_pixmap(&dst_pixmap->drawable)
+ && glamor_ddx_fallback_check_gc(gc))
+ return FALSE;
+ }
+ /* Is it possible to set the access as WO? */
+
+ sub_pixmap_access = GLAMOR_ACCESS_RW;
+
+ sub_pixmap = glamor_get_sub_pixmap(dst_pixmap, x + off_x,
+ y + off_y, width, height,
+ sub_pixmap_access);
+
+ if (sub_pixmap != NULL) {
+ if (gc->fillStyle != FillSolid) {
+ gc->patOrg.x += (drawable->x - x);
+ gc->patOrg.y += (drawable->y - y);
+ }
+ saved_drawable = drawable;
+ drawable = &sub_pixmap->drawable;
+ saved_x = x;
+ saved_y = y;
+ x = 0;
+ y = 0;
+ }
+ if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW)) {
+ if (glamor_prepare_access_gc(gc)) {
+ fbFill(drawable, gc, x, y, width, height);
+ glamor_finish_access_gc(gc);
+ }
+ glamor_finish_access(drawable, GLAMOR_ACCESS_RW);
+ }
+
+ if (sub_pixmap != NULL) {
+ if (gc->fillStyle != FillSolid) {
+ gc->patOrg.x -= (saved_drawable->x - saved_x);
+ gc->patOrg.y -= (saved_drawable->y - saved_y);
+ }
+
+ x = saved_x;
+ y = saved_y;
+
+ glamor_put_sub_pixmap(sub_pixmap, dst_pixmap,
+ x + off_x, y + off_y,
+ width, height, sub_pixmap_access);
+ }
+
+ return TRUE;
+}
+
+void
+glamor_init_solid_shader(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ const char *solid_vs =
+ "attribute vec4 v_position;"
+ "void main()\n" "{\n" " gl_Position = v_position;\n"
+ "}\n";
+ const char *solid_fs =
+ GLAMOR_DEFAULT_PRECISION "uniform vec4 color;\n"
+ "void main()\n" "{\n" " gl_FragColor = color;\n" "}\n";
+ GLint fs_prog, vs_prog;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+ glamor_priv->solid_prog = dispatch->glCreateProgram();
+ vs_prog = glamor_compile_glsl_prog(dispatch, GL_VERTEX_SHADER, solid_vs);
+ fs_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER,
+ solid_fs);
+ dispatch->glAttachShader(glamor_priv->solid_prog, vs_prog);
+ dispatch->glAttachShader(glamor_priv->solid_prog, fs_prog);
+
+ dispatch->glBindAttribLocation(glamor_priv->solid_prog,
+ GLAMOR_VERTEX_POS, "v_position");
+ glamor_link_glsl_prog(dispatch, glamor_priv->solid_prog);
+
+ glamor_priv->solid_color_uniform_location =
+ dispatch->glGetUniformLocation(glamor_priv->solid_prog,
+ "color");
+ glamor_put_dispatch(glamor_priv);
+}
+
+void
+glamor_fini_solid_shader(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glDeleteProgram(glamor_priv->solid_prog);
+ glamor_put_dispatch(glamor_priv);
+}
+
+static void
+_glamor_solid_boxes(PixmapPtr pixmap, BoxPtr box, int nbox, float *color)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_pixmap_private *pixmap_priv =
+ glamor_get_pixmap_private(pixmap);
+ glamor_gl_dispatch *dispatch;
+ GLfloat xscale, yscale;
+ float vertices[32];
+ float *pvertices = vertices;
+ int valid_nbox = ARRAY_SIZE(vertices);
+
+ glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glUseProgram(glamor_priv->solid_prog);
+
+ dispatch->glUniform4fv(glamor_priv->solid_color_uniform_location,
+ 1, color);
+
+ pixmap_priv_get_dest_scale(pixmap_priv, &xscale, &yscale);
+
+ if (unlikely(nbox*4*2 > ARRAY_SIZE(vertices))) {
+ int allocated_box;
+
+ if (nbox * 6 > GLAMOR_COMPOSITE_VBO_VERT_CNT) {
+ allocated_box = GLAMOR_COMPOSITE_VBO_VERT_CNT / 6;
+ } else
+ allocated_box = nbox;
+ pvertices = malloc(allocated_box * 4 * 2 * sizeof(float));
+ if (pvertices)
+ valid_nbox = allocated_box;
+ else {
+ pvertices = vertices;
+ valid_nbox = ARRAY_SIZE(vertices) / (4*2);
+ }
+ }
+
+ if (unlikely(nbox > 1))
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glamor_priv->ebo);
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
+ GL_FALSE, 2 * sizeof(float),
+ pvertices);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+
+ while(nbox) {
+ int box_cnt, i;
+ float *valid_vertices;
+ valid_vertices = pvertices;
+ box_cnt = nbox > valid_nbox ? valid_nbox : nbox;
+ for (i = 0; i < box_cnt; i++) {
+ glamor_set_normalize_vcoords(pixmap_priv, xscale, yscale,
+ box[i].x1, box[i].y1,
+ box[i].x2, box[i].y2,
+ glamor_priv->yInverted,
+ valid_vertices);
+ valid_vertices += 4*2;
+ }
+ if (box_cnt == 1)
+ dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, box_cnt * 4);
+ else
+#ifndef GLAMOR_GLES2
+ dispatch->glDrawRangeElements(GL_TRIANGLES,
+ 0,
+ box_cnt * 4,
+ box_cnt * 6,
+ GL_UNSIGNED_SHORT,
+ NULL);
+#else
+ dispatch->glDrawElements(GL_TRIANGLES,
+ box_cnt * 6,
+ GL_UNSIGNED_SHORT,
+ NULL);
+#endif
+ nbox -= box_cnt;
+ box += box_cnt;
+ }
+
+ if (pvertices != vertices)
+ free(pvertices);
+
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glUseProgram(0);
+ glamor_put_dispatch(glamor_priv);
+ glamor_priv->state = RENDER_STATE;
+ glamor_priv->render_idle_cnt = 0;
+}
+
+Bool
+glamor_solid_boxes(PixmapPtr pixmap,
+ BoxPtr box, int nbox,
+ unsigned long fg_pixel)
+{
+ glamor_pixmap_private *pixmap_priv;
+ GLfloat color[4];
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ return FALSE;
+
+ glamor_get_rgba_from_pixel(fg_pixel,
+ &color[0],
+ &color[1],
+ &color[2],
+ &color[3], format_for_pixmap(pixmap));
+
+ if (pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ RegionRec region;
+ int n_region;
+ glamor_pixmap_clipped_regions *clipped_regions;
+ int i;
+
+ RegionInitBoxes(&region, box, nbox);
+ clipped_regions = glamor_compute_clipped_regions(pixmap_priv, &region, &n_region, 0, 0, 0);
+ for(i = 0; i < n_region; i++)
+ {
+ BoxPtr inner_box;
+ int inner_nbox;
+ SET_PIXMAP_FBO_CURRENT(pixmap_priv, clipped_regions[i].block_idx);
+
+ inner_box = RegionRects(clipped_regions[i].region);
+ inner_nbox = RegionNumRects(clipped_regions[i].region);
+ _glamor_solid_boxes(pixmap, inner_box, inner_nbox, color);
+ RegionDestroy(clipped_regions[i].region);
+ }
+ free(clipped_regions);
+ RegionUninit(&region);
+ } else
+ _glamor_solid_boxes(pixmap, box, nbox, color);
+
+ return TRUE;
+}
+
+Bool
+glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
+ unsigned char alu, unsigned long planemask,
+ unsigned long fg_pixel)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_pixmap_private *pixmap_priv;
+ glamor_gl_dispatch *dispatch;
+ BoxRec box;
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ return FALSE;
+
+ if (!glamor_set_planemask(pixmap, planemask)) {
+ glamor_fallback
+ ("Failedto set planemask in glamor_solid.\n");
+ return FALSE;
+ }
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ if (!glamor_set_alu(dispatch, alu)) {
+ if (alu == GXclear)
+ fg_pixel = 0;
+ else {
+ glamor_fallback("unsupported alu %x\n", alu);
+ glamor_put_dispatch(glamor_priv);
+ return FALSE;
+ }
+ }
+ box.x1 = x;
+ box.y1 = y;
+ box.x2 = x + width;
+ box.y2 = y + height;
+ glamor_solid_boxes(pixmap, &box, 1, fg_pixel);
+
+ glamor_set_alu(dispatch, GXcopy);
+ glamor_put_dispatch(glamor_priv);
+
+ return TRUE;
+}
+
diff --git a/glamor/glamor_fillspans.c b/glamor/glamor_fillspans.c
new file mode 100644
index 000000000..35e881f61
--- /dev/null
+++ b/glamor/glamor_fillspans.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright © 1998 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/** @file glamor_fillspans.c
+ *
+ * FillSpans implementation, taken from fb_fillsp.c
+ */
+#include "glamor_priv.h"
+
+static Bool
+_glamor_fill_spans(DrawablePtr drawable,
+ GCPtr gc,
+ int n, DDXPointPtr points, int *widths, int sorted, Bool fallback)
+{
+ DDXPointPtr ppt;
+ int nbox;
+ BoxPtr pbox;
+ int x1, x2, y;
+ RegionPtr pClip = fbGetCompositeClip(gc);
+ Bool ret = FALSE;
+
+ if (gc->fillStyle != FillSolid && gc->fillStyle != FillTiled)
+ goto fail;
+
+ ppt = points;
+ while (n--) {
+ x1 = ppt->x;
+ y = ppt->y;
+ x2 = x1 + (int) *widths;
+ ppt++;
+ widths++;
+
+ nbox = REGION_NUM_RECTS(pClip);
+ pbox = REGION_RECTS(pClip);
+ while (nbox--) {
+ int real_x1 = x1, real_x2 = x2;
+
+ if (real_x1 < pbox->x1)
+ real_x1 = pbox->x1;
+
+ if (real_x2 > pbox->x2)
+ real_x2 = pbox->x2;
+
+ if (real_x2 > real_x1 && pbox->y1 <= y && pbox->y2 > y) {
+ if (!glamor_fill(drawable, gc, real_x1, y,
+ real_x2 - real_x1, 1, fallback))
+ goto fail;
+ }
+ pbox++;
+ }
+ }
+ ret = TRUE;
+ goto done;
+
+fail:
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(drawable)
+ && glamor_ddx_fallback_check_gc(gc)) {
+ goto done;
+ }
+ glamor_fallback("to %p (%c)\n", drawable,
+ glamor_get_drawable_location(drawable));
+ if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW)) {
+ if (glamor_prepare_access_gc(gc)) {
+ fbFillSpans(drawable, gc, n, points, widths,
+ sorted);
+ glamor_finish_access_gc(gc);
+ }
+ glamor_finish_access(drawable, GLAMOR_ACCESS_RW);
+ }
+ ret = TRUE;
+
+done:
+ return ret;
+}
+
+
+void
+glamor_fill_spans(DrawablePtr drawable,
+ GCPtr gc,
+ int n, DDXPointPtr points, int *widths, int sorted)
+{
+ _glamor_fill_spans(drawable, gc, n, points, widths, sorted, TRUE);
+}
+
+Bool
+glamor_fill_spans_nf(DrawablePtr drawable,
+ GCPtr gc,
+ int n, DDXPointPtr points, int *widths, int sorted)
+{
+ return _glamor_fill_spans(drawable, gc, n, points, widths, sorted, FALSE);
+}
+
+
diff --git a/glamor/glamor_getimage.c b/glamor/glamor_getimage.c
new file mode 100644
index 000000000..5df576c45
--- /dev/null
+++ b/glamor/glamor_getimage.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@gmail.com>
+ *
+ */
+
+#include "glamor_priv.h"
+
+
+static Bool
+_glamor_get_image(DrawablePtr drawable, int x, int y, int w, int h,
+ unsigned int format, unsigned long planeMask, char *d,
+ Bool fallback)
+{
+ PixmapPtr pixmap, sub_pixmap;
+ struct glamor_pixmap_private *pixmap_priv;
+ int x_off, y_off;
+ int stride;
+ void *data;
+
+ pixmap = glamor_get_drawable_pixmap(drawable);
+ glamor_get_drawable_deltas(drawable, pixmap, &x_off, &y_off);
+
+ if (format != ZPixmap)
+ goto fall_back;
+ pixmap = glamor_get_drawable_pixmap(drawable);
+ glamor_get_drawable_deltas(drawable, pixmap, &x_off, &y_off);
+
+ if (!glamor_set_planemask(pixmap, planeMask)) {
+ glamor_fallback
+ ("Failedto set planemask in glamor_solid.\n");
+ goto fall_back;
+ }
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ goto fall_back;
+ stride = PixmapBytePad(w, drawable->depth);
+
+ x += drawable->x + x_off;
+ y += drawable->y + y_off;
+
+ data = glamor_download_sub_pixmap_to_cpu(pixmap, x, y, w, h, stride,
+ d, 0, GLAMOR_ACCESS_RO);
+ if (data != NULL) {
+ assert(data == d);
+ return TRUE;
+ }
+fall_back:
+ sub_pixmap = glamor_get_sub_pixmap(pixmap, x + x_off + drawable->x,
+ y + y_off + drawable->y, w, h,
+ GLAMOR_ACCESS_RO);
+ if (sub_pixmap) {
+ fbGetImage(&sub_pixmap->drawable, 0, 0, w, h, format, planeMask, d);
+ glamor_put_sub_pixmap(sub_pixmap, pixmap,
+ x + x_off + drawable->x,
+ y + y_off + drawable->y,
+ w, h, GLAMOR_ACCESS_RO);
+ } else
+ miGetImage(drawable, x, y, w, h, format, planeMask, d);
+
+ return TRUE;
+}
+
+void
+glamor_get_image(DrawablePtr pDrawable, int x, int y, int w, int h,
+ unsigned int format, unsigned long planeMask, char *d)
+{
+ _glamor_get_image(pDrawable, x, y, w, h, format, planeMask, d, TRUE);
+}
+
+Bool
+glamor_get_image_nf(DrawablePtr pDrawable, int x, int y, int w, int h,
+ unsigned int format, unsigned long planeMask, char *d)
+{
+ return _glamor_get_image(pDrawable, x, y, w,
+ h, format, planeMask, d, FALSE);
+}
diff --git a/glamor/glamor_getspans.c b/glamor/glamor_getspans.c
new file mode 100644
index 000000000..6d6c8e9a4
--- /dev/null
+++ b/glamor/glamor_getspans.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ *
+ */
+
+#include "glamor_priv.h"
+
+static Bool
+_glamor_get_spans(DrawablePtr drawable,
+ int wmax,
+ DDXPointPtr points, int *widths, int count, char *dst,
+ Bool fallback)
+{
+ PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
+ glamor_pixmap_private *pixmap_priv =
+ glamor_get_pixmap_private(pixmap);
+ int i;
+ uint8_t *readpixels_dst = (uint8_t *) dst;
+ void *data;
+ int x_off, y_off;
+ Bool ret = FALSE;
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ goto fail;
+
+ glamor_get_drawable_deltas(drawable, pixmap, &x_off, &y_off);
+ for (i = 0; i < count; i++) {
+ data = glamor_download_sub_pixmap_to_cpu(pixmap, points[i].x + x_off,
+ points[i].y + y_off, widths[i], 1,
+ PixmapBytePad(widths[i], drawable->depth),
+ readpixels_dst, 0, GLAMOR_ACCESS_RO);
+ assert(data == readpixels_dst);
+ readpixels_dst += PixmapBytePad(widths[i], drawable->depth);
+ }
+
+ ret = TRUE;
+ goto done;
+fail:
+
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(drawable))
+ goto done;
+
+ ret = TRUE;
+ if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RO)) {
+ fbGetSpans(drawable, wmax, points, widths, count, dst);
+ glamor_finish_access(drawable, GLAMOR_ACCESS_RO);
+ }
+done:
+ return ret;
+}
+
+void
+glamor_get_spans(DrawablePtr drawable,
+ int wmax,
+ DDXPointPtr points, int *widths, int count, char *dst)
+{
+ _glamor_get_spans(drawable, wmax, points,
+ widths, count, dst, TRUE);
+}
+
+Bool
+glamor_get_spans_nf(DrawablePtr drawable,
+ int wmax,
+ DDXPointPtr points, int *widths, int count, char *dst)
+{
+ return _glamor_get_spans(drawable, wmax, points,
+ widths, count, dst, FALSE);
+}
+
+
+
diff --git a/glamor/glamor_gl_dispatch.c b/glamor/glamor_gl_dispatch.c
new file mode 100644
index 000000000..da99e2627
--- /dev/null
+++ b/glamor/glamor_gl_dispatch.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@gmail.com>
+ *
+ */
+
+#include "glamor_priv.h"
+#include <dlfcn.h>
+
+#define INIT_FUNC(dst,func_name,get) \
+ dst->func_name = get(#func_name); \
+ if (dst->func_name == NULL) { \
+ dst->func_name = (void *)dlsym(NULL, #func_name); \
+ if (dst->func_name == NULL) { \
+ ErrorF("Failed to get function %s\n", #func_name);\
+ goto fail; \
+ } \
+ } \
+
+_X_EXPORT Bool
+glamor_gl_dispatch_init_impl(struct glamor_gl_dispatch *dispatch,
+ int gl_version,
+ void *(*get_proc_address) (const char *))
+{
+#ifndef GLAMOR_GLES2
+ INIT_FUNC(dispatch, glMatrixMode, get_proc_address);
+ INIT_FUNC(dispatch, glLoadIdentity, get_proc_address);
+ INIT_FUNC(dispatch, glRasterPos2i, get_proc_address);
+ INIT_FUNC(dispatch, glDrawPixels, get_proc_address);
+ INIT_FUNC(dispatch, glLogicOp, get_proc_address);
+ INIT_FUNC(dispatch, glMapBuffer, get_proc_address);
+ INIT_FUNC(dispatch, glMapBufferRange, get_proc_address);
+ INIT_FUNC(dispatch, glUnmapBuffer, get_proc_address);
+ INIT_FUNC(dispatch, glBlitFramebuffer, get_proc_address);
+ INIT_FUNC(dispatch, glDrawRangeElements, get_proc_address);
+#endif
+ INIT_FUNC(dispatch, glViewport, get_proc_address);
+ INIT_FUNC(dispatch, glDrawArrays, get_proc_address);
+ INIT_FUNC(dispatch, glDrawElements, get_proc_address);
+ INIT_FUNC(dispatch, glReadPixels, get_proc_address);
+ INIT_FUNC(dispatch, glPixelStorei, get_proc_address);
+ INIT_FUNC(dispatch, glTexParameteri, get_proc_address);
+ INIT_FUNC(dispatch, glTexImage2D, get_proc_address);
+ INIT_FUNC(dispatch, glGenTextures, get_proc_address);
+ INIT_FUNC(dispatch, glDeleteTextures, get_proc_address);
+ INIT_FUNC(dispatch, glBindTexture, get_proc_address);
+ INIT_FUNC(dispatch, glTexSubImage2D, get_proc_address);
+ INIT_FUNC(dispatch, glFlush, get_proc_address);
+ INIT_FUNC(dispatch, glFinish, get_proc_address);
+ INIT_FUNC(dispatch, glGetIntegerv, get_proc_address);
+ INIT_FUNC(dispatch, glGetString, get_proc_address);
+ INIT_FUNC(dispatch, glScissor, get_proc_address);
+ INIT_FUNC(dispatch, glEnable, get_proc_address);
+ INIT_FUNC(dispatch, glDisable, get_proc_address);
+ INIT_FUNC(dispatch, glBlendFunc, get_proc_address);
+ INIT_FUNC(dispatch, glActiveTexture, get_proc_address);
+ INIT_FUNC(dispatch, glGenBuffers, get_proc_address);
+ INIT_FUNC(dispatch, glBufferData, get_proc_address);
+ INIT_FUNC(dispatch, glBindBuffer, get_proc_address);
+ INIT_FUNC(dispatch, glDeleteBuffers, get_proc_address);
+ INIT_FUNC(dispatch, glFramebufferTexture2D, get_proc_address);
+ INIT_FUNC(dispatch, glBindFramebuffer, get_proc_address);
+ INIT_FUNC(dispatch, glDeleteFramebuffers, get_proc_address);
+ INIT_FUNC(dispatch, glGenFramebuffers, get_proc_address);
+ INIT_FUNC(dispatch, glCheckFramebufferStatus, get_proc_address);
+ INIT_FUNC(dispatch, glVertexAttribPointer, get_proc_address);
+ INIT_FUNC(dispatch, glDisableVertexAttribArray, get_proc_address);
+ INIT_FUNC(dispatch, glEnableVertexAttribArray, get_proc_address);
+ INIT_FUNC(dispatch, glBindAttribLocation, get_proc_address);
+ INIT_FUNC(dispatch, glLinkProgram, get_proc_address);
+ INIT_FUNC(dispatch, glShaderSource, get_proc_address);
+
+ INIT_FUNC(dispatch, glUseProgram, get_proc_address);
+ INIT_FUNC(dispatch, glUniform1i, get_proc_address);
+ INIT_FUNC(dispatch, glUniform1f, get_proc_address);
+ INIT_FUNC(dispatch, glUniform4f, get_proc_address);
+ INIT_FUNC(dispatch, glUniform4fv, get_proc_address);
+ INIT_FUNC(dispatch, glUniform1fv, get_proc_address);
+ INIT_FUNC(dispatch, glUniform2fv, get_proc_address);
+ INIT_FUNC(dispatch, glUniformMatrix3fv, get_proc_address);
+ INIT_FUNC(dispatch, glCreateProgram, get_proc_address);
+ INIT_FUNC(dispatch, glDeleteProgram, get_proc_address);
+ INIT_FUNC(dispatch, glCreateShader, get_proc_address);
+ INIT_FUNC(dispatch, glCompileShader, get_proc_address);
+ INIT_FUNC(dispatch, glAttachShader, get_proc_address);
+ INIT_FUNC(dispatch, glDeleteShader, get_proc_address);
+ INIT_FUNC(dispatch, glGetShaderiv, get_proc_address);
+ INIT_FUNC(dispatch, glGetShaderInfoLog, get_proc_address);
+ INIT_FUNC(dispatch, glGetProgramiv, get_proc_address);
+ INIT_FUNC(dispatch, glGetProgramInfoLog, get_proc_address);
+ INIT_FUNC(dispatch, glGetUniformLocation, get_proc_address);
+
+ return TRUE;
+ fail:
+ return FALSE;
+}
diff --git a/glamor/glamor_gl_dispatch.h b/glamor/glamor_gl_dispatch.h
new file mode 100644
index 000000000..76dadd49e
--- /dev/null
+++ b/glamor/glamor_gl_dispatch.h
@@ -0,0 +1,138 @@
+typedef struct glamor_gl_dispatch {
+ /* Transformation functions */
+ void (*glMatrixMode) (GLenum mode);
+ void (*glLoadIdentity) (void);
+ void (*glViewport) (GLint x, GLint y, GLsizei width,
+ GLsizei height);
+ /* Drawing functions */
+ void (*glRasterPos2i) (GLint x, GLint y);
+
+ /* Vertex Array */
+ void (*glDrawArrays) (GLenum mode, GLint first, GLsizei count);
+
+ /* Elements Array*/
+ void (*glDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid * indices);
+ void (*glDrawRangeElements) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid * indices);
+
+ /* Raster functions */
+ void (*glReadPixels) (GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid * pixels);
+
+ void (*glDrawPixels) (GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const GLvoid * pixels);
+ void (*glPixelStorei) (GLenum pname, GLint param);
+ /* Texture Mapping */
+
+ void (*glTexParameteri) (GLenum target, GLenum pname, GLint param);
+ void (*glTexImage2D) (GLenum target, GLint level,
+ GLint internalFormat,
+ GLsizei width, GLsizei height,
+ GLint border, GLenum format, GLenum type,
+ const GLvoid * pixels);
+ /* 1.1 */
+ void (*glGenTextures) (GLsizei n, GLuint * textures);
+ void (*glDeleteTextures) (GLsizei n, const GLuint * textures);
+ void (*glBindTexture) (GLenum target, GLuint texture);
+ void (*glTexSubImage2D) (GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const GLvoid * pixels);
+ /* MISC */
+ void (*glFlush) (void);
+ void (*glFinish) (void);
+ void (*glGetIntegerv) (GLenum pname, GLint * params);
+ const GLubyte *(*glGetString) (GLenum name);
+ void (*glScissor) (GLint x, GLint y, GLsizei width,
+ GLsizei height);
+ void (*glEnable) (GLenum cap);
+ void (*glDisable) (GLenum cap);
+ void (*glBlendFunc) (GLenum sfactor, GLenum dfactor);
+ void (*glLogicOp) (GLenum opcode);
+
+ /* 1.3 */
+ void (*glActiveTexture) (GLenum texture);
+
+ /* GL Extentions */
+ void (*glGenBuffers) (GLsizei n, GLuint * buffers);
+ void (*glBufferData) (GLenum target, GLsizeiptr size,
+ const GLvoid * data, GLenum usage);
+ GLvoid *(*glMapBuffer) (GLenum target, GLenum access);
+ GLvoid *(*glMapBufferRange) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+ GLboolean (*glUnmapBuffer) (GLenum target);
+ void (*glBindBuffer) (GLenum target, GLuint buffer);
+ void (*glDeleteBuffers) (GLsizei n, const GLuint * buffers);
+
+ void (*glFramebufferTexture2D) (GLenum target, GLenum attachment,
+ GLenum textarget, GLuint texture,
+ GLint level);
+ void (*glBindFramebuffer) (GLenum target, GLuint framebuffer);
+ void (*glDeleteFramebuffers) (GLsizei n,
+ const GLuint * framebuffers);
+ void (*glGenFramebuffers) (GLsizei n, GLuint * framebuffers);
+ GLenum (*glCheckFramebufferStatus) (GLenum target);
+ void (*glBlitFramebuffer) (GLint srcX0, GLint srcY0, GLint srcX1,
+ GLint srcY1, GLint dstX0, GLint dstY0,
+ GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter);
+
+ void (*glVertexAttribPointer) (GLuint index, GLint size,
+ GLenum type, GLboolean normalized,
+ GLsizei stride,
+ const GLvoid * pointer);
+ void (*glDisableVertexAttribArray) (GLuint index);
+ void (*glEnableVertexAttribArray) (GLuint index);
+ void (*glBindAttribLocation) (GLuint program, GLuint index,
+ const GLchar * name);
+
+ void (*glLinkProgram) (GLuint program);
+ void (*glShaderSource) (GLuint shader, GLsizei count,
+ const GLchar * *string,
+ const GLint * length);
+ void (*glUseProgram) (GLuint program);
+ void (*glUniform1i) (GLint location, GLint v0);
+ void (*glUniform1f) (GLint location, GLfloat v0);
+ void (*glUniform4f) (GLint location, GLfloat v0, GLfloat v1,
+ GLfloat v2, GLfloat v3);
+ void (*glUniform1fv) (GLint location, GLsizei count,
+ const GLfloat * value);
+ void (*glUniform2fv) (GLint location, GLsizei count,
+ const GLfloat * value);
+ void (*glUniform4fv) (GLint location, GLsizei count,
+ const GLfloat * value);
+ void (*glUniformMatrix3fv) (GLint location, GLsizei count,
+ GLboolean transpose, const GLfloat* value);
+ GLuint (*glCreateProgram) (void);
+ GLuint (*glDeleteProgram) (GLuint);
+ GLuint (*glCreateShader) (GLenum type);
+ void (*glCompileShader) (GLuint shader);
+ void (*glAttachShader) (GLuint program, GLuint shader);
+ void (*glDeleteShader) (GLuint shader);
+ void (*glGetShaderiv) (GLuint shader, GLenum pname,
+ GLint * params);
+ void (*glGetShaderInfoLog) (GLuint shader, GLsizei bufSize,
+ GLsizei * length, GLchar * infoLog);
+ void (*glGetProgramiv) (GLuint program, GLenum pname,
+ GLint * params);
+ void (*glGetProgramInfoLog) (GLuint program, GLsizei bufSize,
+ GLsizei * length, GLchar * infoLog);
+ GLint (*glGetUniformLocation) (GLuint program,
+ const GLchar * name);
+
+} glamor_gl_dispatch;
+
+
+typedef void *(*get_proc_address_t) (const char *);
+
+_X_EXPORT Bool
+glamor_gl_dispatch_init_impl(struct glamor_gl_dispatch *dispatch,
+ int gl_version,
+ get_proc_address_t get_proc_address);
+
+
+_X_EXPORT Bool
+glamor_gl_dispatch_init(ScreenPtr screen,
+ struct glamor_gl_dispatch *dispatch,
+ int gl_version);
diff --git a/glamor/glamor_glext.h b/glamor/glamor_glext.h
new file mode 100644
index 000000000..1f7206b99
--- /dev/null
+++ b/glamor/glamor_glext.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright © 2001 Keith Packard
+ * Copyright © 2008 Intel Corporation
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ *
+ */
+
+
+#ifdef GLAMOR_GLES2
+
+#define GL_BGRA GL_BGRA_EXT
+#define GL_COLOR_INDEX 0x1900
+#define GL_BITMAP 0x1A00
+#define GL_UNSIGNED_INT_8_8_8_8 0x8035
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#define GL_UNSIGNED_INT_10_10_10_2 0x8036
+#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+
+#define GL_PIXEL_PACK_BUFFER 0x88EB
+#define GL_PIXEL_UNPACK_BUFFER 0x88EC
+#define GL_CLAMP_TO_BORDER 0x812D
+
+#define GL_READ_WRITE 0x88BA
+#define GL_READ_ONLY 0x88B8
+#define GL_WRITE_ONLY 0x88B9
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STREAM_READ 0x88E1
+#define GL_PACK_ROW_LENGTH 0x0D02
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
+
+#define GL_PACK_INVERT_MESA 0x8758
+#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
+#define GL_MAP_READ_BIT 0x0001
+#define GL_MAP_WRITE_BIT 0x0002
+
+#endif
diff --git a/glamor/glamor_glyphblt.c b/glamor/glamor_glyphblt.c
new file mode 100644
index 000000000..b55327c4b
--- /dev/null
+++ b/glamor/glamor_glyphblt.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@gmail.com>
+ *
+ */
+
+#include "glamor_priv.h"
+
+static Bool
+_glamor_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr * ppci, pointer pglyphBase, Bool fallback)
+{
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(pDrawable)
+ && glamor_ddx_fallback_check_gc(pGC))
+ return FALSE;
+
+ miImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+ return TRUE;
+}
+
+void
+glamor_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr * ppci, pointer pglyphBase)
+{
+ _glamor_image_glyph_blt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase, TRUE);
+}
+
+Bool
+glamor_image_glyph_blt_nf(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr * ppci, pointer pglyphBase)
+{
+ return _glamor_image_glyph_blt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase, FALSE);
+}
+
+static Bool
+_glamor_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr * ppci, pointer pglyphBase, Bool fallback)
+{
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(pDrawable)
+ && glamor_ddx_fallback_check_gc(pGC))
+ return FALSE;
+
+ miPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+ return TRUE;
+}
+
+void
+glamor_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr * ppci, pointer pglyphBase)
+{
+ _glamor_poly_glyph_blt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase, TRUE);
+}
+
+Bool
+glamor_poly_glyph_blt_nf(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr * ppci, pointer pglyphBase)
+{
+ return _glamor_poly_glyph_blt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase, FALSE);
+}
+
+static Bool
+_glamor_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable, int w, int h, int x, int y, Bool fallback)
+{
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(pDrawable)
+ && glamor_ddx_fallback_check_pixmap(&pBitmap->drawable)
+ && glamor_ddx_fallback_check_gc(pGC))
+ return FALSE;
+
+ miPushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
+ return TRUE;
+}
+
+void
+glamor_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable, int w, int h, int x, int y)
+{
+ _glamor_push_pixels(pGC, pBitmap, pDrawable, w, h, x, y, TRUE);
+}
+
+Bool
+glamor_push_pixels_nf(GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable, int w, int h, int x, int y)
+{
+ return _glamor_push_pixels(pGC, pBitmap, pDrawable, w, h, x, y, FALSE);
+}
+
diff --git a/glamor/glamor_glyphs.c b/glamor/glamor_glyphs.c
new file mode 100644
index 000000000..fc361df42
--- /dev/null
+++ b/glamor/glamor_glyphs.c
@@ -0,0 +1,1806 @@
+/*
+ * Copyright © 2008 Red Hat, Inc.
+ * Partly based on code Copyright © 2000 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Red Hat makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Owen Taylor <otaylor@fishsoup.net>
+ * Based on code by: Keith Packard
+ */
+
+#include <stdlib.h>
+
+#include "glamor_priv.h"
+
+#include <mipict.h>
+
+#if DEBUG_GLYPH_CACHE
+#define DBG_GLYPH_CACHE(a) ErrorF a
+#else
+#define DBG_GLYPH_CACHE(a)
+#endif
+
+/* Width of the pixmaps we use for the caches; this should be less than
+ * max texture size of the driver; this may need to actually come from
+ * the driver.
+ */
+
+/* Maximum number of glyphs we buffer on the stack before flushing
+ * rendering to the mask or destination surface.
+ */
+#define GLYPH_BUFFER_SIZE 1024
+
+#define CACHE_PICTURE_SIZE 1024
+#define GLYPH_MIN_SIZE 8
+#define GLYPH_MAX_SIZE 64
+#define GLYPH_CACHE_SIZE ((CACHE_PICTURE_SIZE) * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE))
+#define MASK_CACHE_MAX_SIZE 32
+#define MASK_CACHE_WIDTH (CACHE_PICTURE_SIZE / MASK_CACHE_MAX_SIZE)
+#define MASK_CACHE_MASK ((1LL << (MASK_CACHE_WIDTH)) - 1)
+
+typedef struct {
+ PicturePtr source;
+ glamor_composite_rect_t rects[GLYPH_BUFFER_SIZE + 4];
+ int count;
+} glamor_glyph_buffer_t;
+
+struct glamor_glyph {
+ glamor_glyph_cache_t *cache;
+ uint16_t x, y;
+ uint16_t size, pos;
+ unsigned long long left_x1_map, left_x2_map;
+ unsigned long long right_x1_map, right_x2_map; /* Use to check real intersect or not. */
+ Bool has_edge_map;
+ Bool cached;
+};
+
+typedef enum {
+ GLAMOR_GLYPH_SUCCESS, /* Glyph added to render buffer */
+ GLAMOR_GLYPH_FAIL, /* out of memory, etc */
+ GLAMOR_GLYPH_NEED_FLUSH, /* would evict a glyph already in the buffer */
+} glamor_glyph_cache_result_t;
+
+#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
+static DevPrivateKeyRec glamor_glyph_key;
+
+static inline struct glamor_glyph *
+glamor_glyph_get_private(GlyphPtr glyph)
+{
+ return (struct glamor_glyph*)glyph->devPrivates;
+}
+
+/*
+ * Mask cache is located at the corresponding cache picture's last row.
+ * and is deadicated for the mask picture when do the glyphs_via_mask.
+ *
+ * As we split the glyphs list according to its overlapped or non-overlapped,
+ * we can reduce the length of glyphs to do the glyphs_via_mask to 2 or 3
+ * glyphs one time for most cases. Thus it give us a case to allocate a
+ * small portion of the corresponding cache directly as the mask picture.
+ * Then we can rendering the glyphs to this mask picture, and latter we
+ * can accumulate the second steps, composite the mask to the dest with
+ * the other non-overlapped glyphs's rendering process.
+ * Another major benefit is we now only need to clear a relatively small mask
+ * region then before. It also make us implement a bunch mask picture clearing
+ * algorithm to avoid too frequently small region clearing.
+ *
+ * If there is no any overlapping, this method will not get performance gain.
+ * If there is some overlapping, then this algorithm can get about 15% performance
+ * gain.
+ */
+
+struct glamor_glyph_mask_cache_entry {
+ int idx;
+ int width;
+ int height;
+ int x;
+ int y;
+};
+
+static struct glamor_glyph_mask_cache {
+ PixmapPtr pixmap;
+ struct glamor_glyph_mask_cache_entry mcache[MASK_CACHE_WIDTH];
+ unsigned int free_bitmap;
+ unsigned int cleared_bitmap;
+}*mask_cache[GLAMOR_NUM_GLYPH_CACHE_FORMATS] = {NULL};
+
+static void
+clear_mask_cache_bitmap(struct glamor_glyph_mask_cache *maskcache,
+ unsigned int clear_mask_bits)
+{
+ unsigned int i = 0;
+ BoxRec box[MASK_CACHE_WIDTH];
+ int box_cnt = 0;
+
+ assert((clear_mask_bits & ~MASK_CACHE_MASK) == 0);
+ for(i = 0; i < MASK_CACHE_WIDTH;i++)
+ {
+ if (clear_mask_bits & (1 << i)) {
+ box[box_cnt].x1 = maskcache->mcache[i].x;
+ box[box_cnt].x2 = maskcache->mcache[i].x + MASK_CACHE_MAX_SIZE;
+ box[box_cnt].y1 = maskcache->mcache[i].y;
+ box[box_cnt].y2 = maskcache->mcache[i].y + MASK_CACHE_MAX_SIZE;
+ box_cnt++;
+ }
+ }
+ glamor_solid_boxes(maskcache->pixmap, box, box_cnt, 0);
+ maskcache->cleared_bitmap |= clear_mask_bits;
+}
+
+static void
+clear_mask_cache(struct glamor_glyph_mask_cache *maskcache)
+{
+ int x = 0;
+ int cnt = MASK_CACHE_WIDTH;
+ unsigned int i = 0;
+ struct glamor_glyph_mask_cache_entry *mce;
+ glamor_solid(maskcache->pixmap, 0, CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE,
+ MASK_CACHE_MAX_SIZE, GXcopy, 0xFFFFFFFF, 0);
+ mce = &maskcache->mcache[0];
+ while(cnt--) {
+ mce->width = 0;
+ mce->height = 0;
+ mce->x = x;
+ mce->y = CACHE_PICTURE_SIZE;
+ mce->idx = i++;
+ x += MASK_CACHE_MAX_SIZE;
+ mce++;
+ }
+ maskcache->free_bitmap = MASK_CACHE_MASK;
+ maskcache->cleared_bitmap = MASK_CACHE_MASK;
+}
+
+static int
+find_continuous_bits(unsigned int bits, int bits_cnt, unsigned int *pbits_mask)
+{
+ int idx = 0;
+ unsigned int bits_mask;
+ bits_mask = ((1LL << bits_cnt) - 1);
+
+ if (unlikely(bits_cnt > 56)) {
+ while(bits) {
+ if ((bits & bits_mask) == bits_mask) {
+ *pbits_mask = bits_mask << idx;
+ return idx;
+ }
+ bits >>= 1;
+ idx++;
+ }
+ } else {
+ idx = __fls(bits);
+ while(bits) {
+ unsigned int temp_bits;
+ temp_bits = bits_mask << (idx - bits_cnt + 1);
+ if ((bits & temp_bits) == temp_bits) {
+ *pbits_mask = temp_bits;
+ return (idx - bits_cnt + 1);
+ }
+ /* Find first zero. And clear the tested bit.*/
+ bits &= ~(1LL<<idx);
+ idx = __fls(~bits);
+ bits &= ~((1LL << idx) - 1);
+ idx--;
+ }
+ }
+ return -1;
+}
+
+static struct glamor_glyph_mask_cache_entry *
+get_mask_cache(struct glamor_glyph_mask_cache *maskcache, int blocks)
+{
+ int free_cleared_bit, idx = -1;
+ int retry_cnt = 0;
+ unsigned int bits_mask = 0;
+
+ if (maskcache->free_bitmap == 0)
+ return NULL;
+retry:
+ free_cleared_bit = maskcache->free_bitmap & maskcache->cleared_bitmap;
+ if (free_cleared_bit && blocks == 1) {
+ idx = __fls(free_cleared_bit);
+ bits_mask = 1 << idx;
+ } else if (free_cleared_bit && blocks > 1) {
+ idx = find_continuous_bits(free_cleared_bit, blocks, &bits_mask);
+ }
+
+ if (idx < 0) {
+ clear_mask_cache_bitmap(maskcache, maskcache->free_bitmap);
+ if (retry_cnt++ > 2)
+ return NULL;
+ goto retry;
+ }
+
+ maskcache->cleared_bitmap &= ~bits_mask;
+ maskcache->free_bitmap &= ~bits_mask;
+ DEBUGF("get idx %d free %x clear %x \n",
+ idx, maskcache->free_bitmap, maskcache->cleared_bitmap);
+ return &maskcache->mcache[idx];
+}
+
+static void
+put_mask_cache_bitmap(struct glamor_glyph_mask_cache *maskcache,
+ unsigned int bitmap)
+{
+ maskcache->free_bitmap |= bitmap;
+ DEBUGF("put bitmap %x free %x clear %x \n",
+ bitmap, maskcache->free_bitmap, maskcache->cleared_bitmap);
+}
+
+static void
+glamor_unrealize_glyph_caches(ScreenPtr pScreen)
+{
+ glamor_screen_private *glamor = glamor_get_screen_private(pScreen);
+ int i;
+
+ if (!glamor->glyph_cache_initialized)
+ return;
+
+ for (i = 0; i < GLAMOR_NUM_GLYPH_CACHE_FORMATS; i++) {
+ glamor_glyph_cache_t *cache = &glamor->glyphCaches[i];
+
+ if (cache->picture)
+ FreePicture(cache->picture, 0);
+
+ if (cache->glyphs)
+ free(cache->glyphs);
+
+ if (mask_cache[i])
+ free(mask_cache[i]);
+ }
+ glamor->glyph_cache_initialized = FALSE;
+}
+
+void
+glamor_glyphs_fini(ScreenPtr pScreen)
+{
+ glamor_unrealize_glyph_caches(pScreen);
+}
+
+/* All caches for a single format share a single pixmap for glyph storage,
+ * allowing mixing glyphs of different sizes without paying a penalty
+ * for switching between source pixmaps. (Note that for a size of font
+ * right at the border between two sizes, we might be switching for almost
+ * every glyph.)
+ *
+ * This function allocates the storage pixmap, and then fills in the
+ * rest of the allocated structures for all caches with the given format.
+ */
+
+static Bool
+glamor_realize_glyph_caches(ScreenPtr pScreen)
+{
+ glamor_screen_private *glamor = glamor_get_screen_private(pScreen);
+ unsigned int formats[] = {
+ PIXMAN_a8,
+ PIXMAN_a8r8g8b8,
+ };
+ int i;
+
+ if (glamor->glyph_cache_initialized)
+ return TRUE;
+
+ glamor->glyph_cache_initialized = TRUE;
+ memset(glamor->glyphCaches, 0, sizeof(glamor->glyphCaches));
+
+ for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) {
+ glamor_glyph_cache_t *cache = &glamor->glyphCaches[i];
+ PixmapPtr pixmap;
+ PicturePtr picture;
+ XID component_alpha;
+ int depth = PIXMAN_FORMAT_DEPTH(formats[i]);
+ int error;
+ PictFormatPtr pPictFormat =
+ PictureMatchFormat(pScreen, depth, formats[i]);
+ if (!pPictFormat)
+ goto bail;
+
+ /* Now allocate the pixmap and picture */
+ pixmap = pScreen->CreatePixmap(pScreen,
+ CACHE_PICTURE_SIZE,
+ CACHE_PICTURE_SIZE + MASK_CACHE_MAX_SIZE, depth,
+ 0);
+ if (!pixmap)
+ goto bail;
+
+ component_alpha = NeedsComponent(pPictFormat->format);
+ picture = CreatePicture(0, &pixmap->drawable, pPictFormat,
+ CPComponentAlpha, &component_alpha,
+ serverClient, &error);
+
+ pScreen->DestroyPixmap(pixmap);
+ if (!picture)
+ goto bail;
+
+ ValidatePicture(picture);
+
+ cache->picture = picture;
+ cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE);
+ if (!cache->glyphs)
+ goto bail;
+
+ cache->evict = rand() % GLYPH_CACHE_SIZE;
+ mask_cache[i] = calloc(1, sizeof(*mask_cache[i]));
+ mask_cache[i]->pixmap = pixmap;
+ clear_mask_cache(mask_cache[i]);
+ }
+ assert(i == GLAMOR_NUM_GLYPH_CACHE_FORMATS);
+
+ return TRUE;
+
+ bail:
+ glamor_unrealize_glyph_caches(pScreen);
+ return FALSE;
+}
+
+
+Bool
+glamor_glyphs_init(ScreenPtr pScreen)
+{
+ if (!dixRegisterPrivateKey(&glamor_glyph_key,
+ PRIVATE_GLYPH, sizeof(struct glamor_glyph)))
+ return FALSE;
+
+ /* Skip pixmap creation if we don't intend to use it. */
+
+ return glamor_realize_glyph_caches(pScreen);
+}
+
+/* The most efficient thing to way to upload the glyph to the screen
+ * is to use CopyArea; glamor pixmaps are always offscreen.
+ */
+static void
+glamor_glyph_cache_upload_glyph(ScreenPtr screen,
+ glamor_glyph_cache_t * cache,
+ GlyphPtr glyph, int x, int y)
+{
+ PicturePtr pGlyphPicture = GlyphPicture(glyph)[screen->myNum];
+ PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
+ PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
+ PixmapPtr scratch;
+ BoxRec box;
+ GCPtr gc;
+
+ gc = GetScratchGC(pCachePixmap->drawable.depth, screen);
+ if (!gc)
+ return;
+
+ ValidateGC(&pCachePixmap->drawable, gc);
+
+ scratch = pGlyphPixmap;
+ if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) {
+
+ scratch = glamor_create_pixmap(screen,
+ glyph->info.width,
+ glyph->info.height,
+ pCachePixmap->
+ drawable.depth, 0);
+ if (scratch) {
+ PicturePtr picture;
+ int error;
+
+ picture =
+ CreatePicture(0,
+ &scratch->drawable,
+ PictureMatchFormat
+ (screen,
+ pCachePixmap->
+ drawable.depth,
+ cache->picture->format),
+ 0, NULL, serverClient,
+ &error);
+ if (picture) {
+ ValidatePicture(picture);
+ glamor_composite(PictOpSrc,
+ pGlyphPicture,
+ NULL, picture,
+ 0, 0, 0, 0, 0,
+ 0,
+ glyph->info.width,
+ glyph->info.height);
+ FreePicture(picture, 0);
+ }
+ } else {
+ scratch = pGlyphPixmap;
+ }
+ }
+
+ box.x1 = x;
+ box.y1 = y;
+ box.x2 = x + glyph->info.width;
+ box.y2 = y + glyph->info.height;
+ glamor_copy_n_to_n_nf(&scratch->drawable,
+ &pCachePixmap->drawable, NULL,
+ &box, 1,
+ -x, -y,
+ FALSE, FALSE, 0, NULL);
+ if (scratch != pGlyphPixmap)
+ screen->DestroyPixmap(scratch);
+
+ FreeScratchGC(gc);
+}
+
+
+void
+glamor_glyph_unrealize(ScreenPtr screen, GlyphPtr glyph)
+{
+ struct glamor_glyph *priv;
+
+ /* Use Lookup in case we have not attached to this glyph. */
+ priv = glamor_glyph_get_private(glyph);
+
+ if (priv->cached)
+ priv->cache->glyphs[priv->pos] = NULL;
+}
+
+/* Cut and paste from render/glyph.c - probably should export it instead */
+static void
+glamor_glyph_extents(int nlist,
+ GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents)
+{
+ int x1, x2, y1, y2;
+ int x, y, n;
+
+ x1 = y1 = MAXSHORT;
+ x2 = y2 = MINSHORT;
+ x = y = 0;
+ while (nlist--) {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ list++;
+ while (n--) {
+ GlyphPtr glyph = *glyphs++;
+ int v;
+
+ v = x - glyph->info.x;
+ if (v < x1)
+ x1 = v;
+ v += glyph->info.width;
+ if (v > x2)
+ x2 = v;
+
+ v = y - glyph->info.y;
+ if (v < y1)
+ y1 = v;
+ v += glyph->info.height;
+ if (v > y2)
+ y2 = v;
+
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ }
+
+ extents->x1 = x1 < MINSHORT ? MINSHORT : x1;
+ extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2;
+ extents->y1 = y1 < MINSHORT ? MINSHORT : y1;
+ extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2;
+}
+
+static void
+glamor_glyph_priv_get_edge_map(GlyphPtr glyph, struct glamor_glyph *priv,
+ PicturePtr glyph_picture)
+{
+ PixmapPtr glyph_pixmap = (PixmapPtr) glyph_picture->pDrawable;
+ int j;
+ unsigned long long left_x1_map = 0, left_x2_map = 0;
+ unsigned long long right_x1_map = 0, right_x2_map = 0;
+ int bitsPerPixel;
+ int stride;
+ void *bits;
+ int width;
+ unsigned int left_x1_data = 0, left_x2_data = 0;
+ unsigned int right_x1_data = 0, right_x2_data = 0;
+
+ bitsPerPixel = glyph_pixmap->drawable.bitsPerPixel;
+ stride = glyph_pixmap->devKind;
+ bits = glyph_pixmap->devPrivate.ptr;
+ width = glyph->info.width;
+
+ if (glyph_pixmap->drawable.width < 2
+ || !(glyph_pixmap->drawable.depth == 8
+ || glyph_pixmap->drawable.depth == 1
+ || glyph_pixmap->drawable.depth == 32)) {
+ priv->has_edge_map = FALSE;
+ return;
+ }
+
+ left_x1_map = left_x2_map = 0;
+ right_x1_map = right_x2_map = 0;
+
+ for(j = 0; j < glyph_pixmap->drawable.height; j++)
+ {
+ if (bitsPerPixel == 8) {
+ unsigned char *data;
+ data = (unsigned char*)((unsigned char*)bits + stride * j);
+ left_x1_data = *data++;
+ left_x2_data = *data;
+ data = (unsigned char*)((unsigned char*)bits + stride * j + width - 2);
+ right_x1_data = *data++;
+ right_x2_data = *data;
+ } else if (bitsPerPixel == 32) {
+ left_x1_data = *((unsigned int*)bits + stride/4 * j);
+ left_x2_data = *((unsigned int*)bits + stride/4 * j + 1);
+ right_x1_data = *((unsigned int*)bits + stride/4 * j + width - 2);
+ right_x2_data = *((unsigned int*)bits + stride/4 * j + width - 1);
+ } else if (bitsPerPixel == 1) {
+ unsigned char temp;
+ temp = *((unsigned char*)glyph_pixmap->devPrivate.ptr
+ + glyph_pixmap->devKind * j) & 0x3;
+ left_x1_data = temp & 0x1;
+ left_x2_data = temp & 0x2;
+
+ temp = *((unsigned char*)glyph_pixmap->devPrivate.ptr
+ + glyph_pixmap->devKind * j
+ + (glyph_pixmap->drawable.width - 2)/8);
+ right_x1_data = temp
+ & (1 << ((glyph_pixmap->drawable.width - 2) % 8));
+ temp = *((unsigned char*)glyph_pixmap->devPrivate.ptr
+ + glyph_pixmap->devKind * j
+ + (glyph_pixmap->drawable.width - 1)/8);
+ right_x2_data = temp
+ & (1 << ((glyph_pixmap->drawable.width - 1) % 8));
+ }
+ left_x1_map |= (left_x1_data !=0) << j;
+ left_x2_map |= (left_x2_data !=0) << j;
+ right_x1_map |= (right_x1_data !=0) << j;
+ right_x2_map |= (right_x2_data !=0) << j;
+ }
+
+ priv->left_x1_map = left_x1_map;
+ priv->left_x2_map = left_x2_map;
+ priv->right_x1_map = right_x1_map;
+ priv->right_x2_map = right_x2_map;
+ priv->has_edge_map = TRUE;
+ return;
+}
+
+/**
+ * Returns TRUE if the glyphs in the lists intersect. Only checks based on
+ * bounding box, which appears to be good enough to catch most cases at least.
+ */
+
+#define INTERSECTED_TYPE_MASK 1
+#define NON_INTERSECTED 0
+#define INTERSECTED 1
+
+struct glamor_glyph_list {
+ int nlist;
+ GlyphListPtr list;
+ GlyphPtr *glyphs;
+ int type;
+};
+
+static Bool
+glyph_new_fixed_list(struct glamor_glyph_list *fixed_list,
+ GlyphPtr *cur_glyphs,
+ GlyphPtr **head_glyphs,
+ GlyphListPtr cur_list,
+ int cur_pos, int cur_x, int cur_y,
+ int x1, int y1, int x2, int y2,
+ GlyphListPtr *head_list,
+ int *head_pos,
+ int *head_x,
+ int *head_y,
+ int *fixed_cnt,
+ int type,
+ BoxPtr prev_extents
+ )
+{
+ int x_off = 0;
+ int y_off = 0;
+ int n_off = 0;
+ int list_cnt;
+ if (type == NON_INTERSECTED) {
+ if (x1 < prev_extents->x2 && x2 > prev_extents->x1
+ && y1 < prev_extents->y2 && y2 > prev_extents->y1)
+ return FALSE;
+ x_off = (*(cur_glyphs-1))->info.xOff;
+ y_off = (*(cur_glyphs-1))->info.yOff;
+ n_off = 1;
+ }
+
+ list_cnt = cur_list - *head_list + 1;
+ if (cur_pos <= n_off) {
+ DEBUGF("break at %d n_off %d\n", cur_pos, n_off);
+ list_cnt--;
+ if (cur_pos < n_off) {
+ /* we overlap with previous list's last glyph. */
+ x_off += cur_list->xOff;
+ y_off += cur_list->yOff;
+ cur_list--;
+ cur_pos = cur_list->len;
+ if (cur_pos <= n_off) {
+ list_cnt--;
+ }
+ }
+ }
+ DEBUGF("got %d lists\n", list_cnt);
+ if (list_cnt != 0) {
+ fixed_list->list = malloc(list_cnt * sizeof(*cur_list));
+ memcpy(fixed_list->list, *head_list, list_cnt * sizeof(*cur_list));
+ fixed_list->list[0].xOff = *head_x;
+ fixed_list->list[0].yOff = *head_y;
+ fixed_list->glyphs = *head_glyphs;
+ fixed_list->type = type & INTERSECTED_TYPE_MASK;
+ fixed_list->nlist = list_cnt;
+ if (cur_list != *head_list) {
+ fixed_list->list[0].len = (*head_list)->len - *head_pos;
+ if (cur_pos != n_off)
+ fixed_list->list[list_cnt - 1].len = cur_pos - n_off;
+ } else
+ fixed_list->list[0].len = cur_pos - *head_pos - n_off;
+ (*fixed_cnt)++;
+ }
+
+ if (type <= INTERSECTED) {
+ *head_list = cur_list;
+ *head_pos = cur_pos - n_off;
+ *head_x = cur_x - x_off;
+ *head_y = cur_y - y_off;
+ *head_glyphs = cur_glyphs - n_off;
+ }
+ return TRUE;
+}
+
+/*
+ * This function detects glyph lists's overlapping.
+ *
+ * If check_fake_overlap is set, then it will check the glyph's left
+ * and right small boxes's real overlapping pixels. And if there is
+ * no real pixel overlapping, then it will not be treated as overlapped
+ * case. And we also can configured it to ignore less than 2 pixels
+ * overlappig.
+ *
+ * This function analyzes all the lists and split the list to multiple
+ * lists which are pure overlapped glyph lists or pure non-overlapped
+ * list if the overlapping only ocurr on the two adjacent glyphs.
+ * Otherwise, it return -1.
+ *
+ **/
+
+static int
+glamor_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr * glyphs,
+ PictFormatShort mask_format,
+ ScreenPtr screen, Bool check_fake_overlap,
+ struct glamor_glyph_list * fixed_list,
+ int fixed_size)
+{
+ int x1, x2, y1, y2;
+ int n;
+ int x, y;
+ BoxPtr extents;
+ BoxRec prev_extents;
+ Bool first = TRUE, first_list = TRUE;
+ Bool need_free_list_region = FALSE;
+ Bool need_free_fixed_list = FALSE;
+ struct glamor_glyph *priv = NULL;
+ Bool in_non_intersected_list = -1;
+ GlyphListPtr head_list;
+ int head_x, head_y, head_pos;
+ int fixed_cnt = 0;
+ GlyphPtr *head_glyphs;
+ GlyphListPtr cur_list = list;
+ RegionRec list_region;
+ RegionRec current_region;
+ BoxRec current_box;
+
+ if (nlist > 1) {
+ pixman_region_init(&list_region);
+ need_free_list_region = TRUE;
+ }
+
+ pixman_region_init(&current_region);
+
+ extents = pixman_region_extents(&current_region);
+
+ x = 0;
+ y = 0;
+ x1 = x2 = y1 = y2 = 0;
+ n = 0;
+ extents->x1 = 0;
+ extents->y1 = 0;
+ extents->x2 = 0;
+ extents->y2 = 0;
+
+ head_list = list;
+ DEBUGF("has %d lists.\n", nlist);
+ while (nlist--) {
+ BoxRec left_box, right_box = {0};
+ Bool has_left_edge_box = FALSE, has_right_edge_box = FALSE;
+ Bool left_to_right;
+ struct glamor_glyph *left_priv = NULL, *right_priv = NULL;
+
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ left_to_right = TRUE;
+ cur_list = list++;
+
+ if (unlikely(!first_list)) {
+ pixman_region_init_with_extents(&current_region, extents);
+ pixman_region_union(&list_region, &list_region, &current_region);
+ first = TRUE;
+ } else {
+ head_list = cur_list;
+ head_pos = cur_list->len - n;
+ head_x = x;
+ head_y = y;
+ head_glyphs = glyphs;
+ }
+
+ DEBUGF("current list %p has %d glyphs\n", cur_list, n);
+ while (n--) {
+ GlyphPtr glyph = *glyphs++;
+
+ DEBUGF("the %dth glyph\n", cur_list->len - n - 1);
+ if (glyph->info.width == 0
+ || glyph->info.height == 0) {
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ continue;
+ }
+ if (mask_format
+ && mask_format != GlyphPicture(glyph)[screen->myNum]->format) {
+ need_free_fixed_list = TRUE;
+ goto done;
+ }
+
+ x1 = x - glyph->info.x;
+ if (x1 < MINSHORT)
+ x1 = MINSHORT;
+ y1 = y - glyph->info.y;
+ if (y1 < MINSHORT)
+ y1 = MINSHORT;
+ if (check_fake_overlap)
+ priv = glamor_glyph_get_private(glyph);
+
+ x2 = x1 + glyph->info.width;
+ y2 = y1 + glyph->info.height;
+
+ if (x2 > MAXSHORT)
+ x2 = MAXSHORT;
+ if (y2 > MAXSHORT)
+ y2 = MAXSHORT;
+
+ if (first) {
+ extents->x1 = x1;
+ extents->y1 = y1;
+ extents->x2 = x2;
+ extents->y2 = y2;
+
+ prev_extents = *extents;
+
+ first = FALSE;
+ if (check_fake_overlap && priv
+ && priv->has_edge_map && glyph->info.yOff == 0) {
+ left_box.x1 = x1;
+ left_box.x2 = x1 + 1;
+ left_box.y1 = y1;
+
+ right_box.x1 = x2 - 2;
+ right_box.x2 = x2 - 1;
+ right_box.y1 = y1;
+ left_priv = right_priv = priv;
+ has_left_edge_box = TRUE;
+ has_right_edge_box = TRUE;
+ }
+ } else {
+ if (unlikely(!first_list)) {
+ current_box.x1 = x1;
+ current_box.y1 = y1;
+ current_box.x2 = x2;
+ current_box.y2 = y2;
+ if (pixman_region_contains_rectangle(&list_region, &current_box) != PIXMAN_REGION_OUT) {
+ need_free_fixed_list = TRUE;
+ goto done;
+ }
+ }
+
+ if (x1 < extents->x2 && x2 > extents->x1
+ && y1 < extents->y2
+ && y2 > extents->y1) {
+
+ if (check_fake_overlap && (has_left_edge_box || has_right_edge_box)
+ && priv->has_edge_map && glyph->info.yOff == 0) {
+ int left_dx, right_dx;
+ unsigned long long intersected;
+
+ left_dx = has_left_edge_box ? 1 : 0;
+ right_dx = has_right_edge_box ? 1 : 0;
+ if (x1 + 1 < extents->x2 - right_dx && x2 - 1 > extents->x1 + left_dx)
+ goto real_intersected;
+
+ if (left_to_right && has_right_edge_box) {
+ if (x1 == right_box.x1) {
+ intersected = ((priv->left_x1_map & right_priv->right_x1_map)
+ | (priv->left_x2_map & right_priv->right_x2_map));
+ if (intersected)
+ goto real_intersected;
+ } else if (x1 == right_box.x2) {
+ intersected = (priv->left_x1_map & right_priv->right_x2_map);
+ if (intersected) {
+ #ifdef GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK
+ /* tolerate with two pixels overlap. */
+ intersected &= ~(1<<__fls(intersected));
+ if ((intersected & (intersected - 1)))
+ #endif
+ goto real_intersected;
+ }
+ }
+ } else if (!left_to_right && has_left_edge_box) {
+ if (x2 - 1 == left_box.x1) {
+ intersected = (priv->right_x2_map & left_priv->left_x1_map);
+ if (intersected) {
+ #ifdef GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK
+ /* tolerate with two pixels overlap. */
+ intersected &= ~(1<<__fls(intersected));
+ if ((intersected & (intersected - 1)))
+ #endif
+ goto real_intersected;
+ }
+ } else if (x2 - 1 == right_box.x2) {
+ if ((priv->right_x1_map & left_priv->left_x1_map)
+ || (priv->right_x2_map & left_priv->left_x2_map))
+ goto real_intersected;
+ }
+ } else {
+ if (x1 < extents->x2 && x1 + 2 > extents->x1)
+ goto real_intersected;
+ }
+ goto non_intersected;
+ } else {
+real_intersected:
+ DEBUGF("overlap with previous glyph.\n");
+ if (in_non_intersected_list == 1) {
+ if (fixed_cnt >= fixed_size) {
+ need_free_fixed_list = TRUE;
+ goto done;
+ }
+ if (!glyph_new_fixed_list(&fixed_list[fixed_cnt],
+ glyphs - 1,
+ &head_glyphs,
+ cur_list,
+ cur_list->len - (n + 1), x, y,
+ x1, y1, x2, y2,
+ &head_list,
+ &head_pos,
+ &head_x,
+ &head_y, &fixed_cnt,
+ NON_INTERSECTED,
+ &prev_extents
+ )){
+ need_free_fixed_list = TRUE;
+ goto done;
+ }
+ }
+
+ in_non_intersected_list = 0;
+
+ }
+ } else {
+non_intersected:
+ DEBUGF("doesn't overlap with previous glyph.\n");
+ if (in_non_intersected_list == 0) {
+ if (fixed_cnt >= fixed_size) {
+ need_free_fixed_list = TRUE;
+ goto done;
+ }
+ if (!glyph_new_fixed_list(&fixed_list[fixed_cnt],
+ glyphs - 1,
+ &head_glyphs,
+ cur_list,
+ cur_list->len - (n + 1), x, y,
+ x1, y1, x2, y2,
+ &head_list,
+ &head_pos,
+ &head_x,
+ &head_y, &fixed_cnt,
+ INTERSECTED,
+ &prev_extents
+ )) {
+ need_free_fixed_list = TRUE;
+ goto done;
+ }
+ }
+ in_non_intersected_list = 1;
+ }
+ prev_extents = *extents;
+ }
+
+ if (check_fake_overlap && priv
+ && priv->has_edge_map && glyph->info.yOff == 0) {
+ if (!has_left_edge_box || x1 < extents->x1) {
+ left_box.x1 = x1;
+ left_box.x2 = x1 + 1;
+ left_box.y1 = y1;
+ has_left_edge_box = TRUE;
+ left_priv = priv;
+ }
+
+ if (!has_right_edge_box || x2 > extents->x2) {
+ right_box.x1 = x2 - 2;
+ right_box.x2 = x2 - 1;
+ right_box.y1 = y1;
+ has_right_edge_box = TRUE;
+ right_priv = priv;
+ }
+ }
+
+ if (x1 < extents->x1)
+ extents->x1 = x1;
+ if (x2 > extents->x2)
+ extents->x2 = x2;
+
+ if (y1 < extents->y1)
+ extents->y1 = y1;
+ if (y2 > extents->y2)
+ extents->y2 = y2;
+
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ first_list = FALSE;
+ }
+
+ if (in_non_intersected_list == 0 && fixed_cnt == 0) {
+ fixed_cnt = -1;
+ goto done;
+ }
+
+ if ((in_non_intersected_list != -1
+ || head_pos != n) && (fixed_cnt > 0)) {
+ if (fixed_cnt >= fixed_size) {
+ need_free_fixed_list = TRUE;
+ goto done;
+ }
+ if (!glyph_new_fixed_list(&fixed_list[fixed_cnt],
+ glyphs - 1,
+ &head_glyphs,
+ cur_list,
+ cur_list->len - (n + 1), x, y,
+ x1, y1, x2, y2,
+ &head_list,
+ &head_pos,
+ &head_x,
+ &head_y, &fixed_cnt,
+ (!in_non_intersected_list) | 0x80,
+ &prev_extents
+ )) {
+ need_free_fixed_list = TRUE;
+ goto done;
+ }
+ }
+
+done:
+ if (need_free_list_region)
+ pixman_region_fini(&list_region);
+ pixman_region_fini(&current_region);
+
+ if (need_free_fixed_list && fixed_cnt >= 0) {
+ while(fixed_cnt--) {
+ free(fixed_list[fixed_cnt].list);
+ }
+ }
+
+ DEBUGF("Got %d fixed list \n", fixed_cnt);
+ return fixed_cnt;
+}
+
+static inline unsigned int
+glamor_glyph_size_to_count(int size)
+{
+ size /= GLYPH_MIN_SIZE;
+ return size * size;
+}
+
+static inline unsigned int
+glamor_glyph_count_to_mask(int count)
+{
+ return ~(count - 1);
+}
+
+static inline unsigned int
+glamor_glyph_size_to_mask(int size)
+{
+ return
+ glamor_glyph_count_to_mask(glamor_glyph_size_to_count(size));
+}
+
+static PicturePtr
+glamor_glyph_cache(glamor_screen_private *glamor, GlyphPtr glyph, int *out_x,
+ int *out_y)
+{
+ ScreenPtr screen = glamor->screen;
+ PicturePtr glyph_picture = GlyphPicture(glyph)[screen->myNum];
+ glamor_glyph_cache_t *cache =
+ &glamor->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) !=
+ 0];
+ struct glamor_glyph *priv = NULL, *evicted_priv = NULL;
+ int size, mask, pos, s;
+
+ if (glyph->info.width > GLYPH_MAX_SIZE
+ || glyph->info.height > GLYPH_MAX_SIZE)
+ return NULL;
+
+ for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2)
+ if (glyph->info.width <= size
+ && glyph->info.height <= size)
+ break;
+
+ s = glamor_glyph_size_to_count(size);
+ mask = glamor_glyph_count_to_mask(s);
+ pos = (cache->count + s - 1) & mask;
+
+ priv = glamor_glyph_get_private(glyph);
+ if (pos < GLYPH_CACHE_SIZE) {
+ cache->count = pos + s;
+ } else {
+ for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) {
+ int i =
+ cache->evict & glamor_glyph_size_to_mask(s);
+ GlyphPtr evicted = cache->glyphs[i];
+ if (evicted == NULL)
+ continue;
+
+ evicted_priv = glamor_glyph_get_private(evicted);
+ assert(evicted_priv->pos == i);
+ if (evicted_priv->size >= s) {
+ cache->glyphs[i] = NULL;
+ evicted_priv->cached = FALSE;
+ pos = cache->evict &
+ glamor_glyph_size_to_mask(size);
+ } else
+ evicted_priv = NULL;
+ break;
+ }
+ if (evicted_priv == NULL) {
+ int count = glamor_glyph_size_to_count(size);
+ mask = glamor_glyph_count_to_mask(count);
+ pos = cache->evict & mask;
+ for (s = 0; s < count; s++) {
+ GlyphPtr evicted = cache->glyphs[pos + s];
+ if (evicted != NULL) {
+
+ evicted_priv =
+ glamor_glyph_get_private
+ (evicted);
+
+ assert(evicted_priv->pos == pos + s);
+ evicted_priv->cached = FALSE;
+ cache->glyphs[pos + s] = NULL;
+ }
+ }
+
+ }
+ /* And pick a new eviction position */
+ cache->evict = rand() % GLYPH_CACHE_SIZE;
+ }
+
+
+ cache->glyphs[pos] = glyph;
+
+ priv->cache = cache;
+ priv->size = size;
+ priv->pos = pos;
+ s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) *
+ (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE));
+ priv->x =
+ s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE;
+ priv->y =
+ (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE;
+ for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) {
+ if (pos & 1)
+ priv->x += s;
+ if (pos & 2)
+ priv->y += s;
+ pos >>= 2;
+ }
+
+ glamor_glyph_cache_upload_glyph(screen, cache, glyph, priv->x,
+ priv->y);
+#ifndef GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK
+ if (priv->has_edge_map == FALSE && glyph->info.width >= 2)
+ glamor_glyph_priv_get_edge_map(glyph, priv, glyph_picture);
+#endif
+ priv->cached = TRUE;
+
+ *out_x = priv->x;
+ *out_y = priv->y;
+ return cache->picture;
+}
+typedef void (*glyphs_flush_func)(void * arg);
+struct glyphs_flush_dst_arg {
+ CARD8 op;
+ PicturePtr src;
+ PicturePtr dst;
+ glamor_glyph_buffer_t * buffer;
+ int x_src,y_src;
+ int x_dst, y_dst;
+};
+
+static struct glyphs_flush_dst_arg dst_arg;
+static struct glyphs_flush_mask_arg mask_arg;
+static glamor_glyph_buffer_t dst_buffer;
+static glamor_glyph_buffer_t mask_buffer;
+unsigned long long mask_glyphs_cnt = 0;
+unsigned long long dst_glyphs_cnt = 0;
+#define GLYPHS_DST_MODE_VIA_MASK 0
+#define GLYPHS_DST_MODE_VIA_MASK_CACHE 1
+#define GLYPHS_DST_MODE_TO_DST 2
+#define GLYPHS_DST_MODE_MASK_TO_DST 3
+
+struct glyphs_flush_mask_arg {
+ PicturePtr mask;
+ glamor_glyph_buffer_t *buffer;
+ struct glamor_glyph_mask_cache *maskcache;
+ unsigned int used_bitmap;
+};
+
+static void
+glamor_glyphs_flush_mask(struct glyphs_flush_mask_arg *arg)
+{
+ if (arg->buffer->count>0) {
+#ifdef RENDER
+ glamor_composite_glyph_rects(PictOpAdd, arg->buffer->source,
+ NULL, arg->mask,
+ arg->buffer->count,
+ arg->buffer->rects);
+#endif
+ }
+ arg->buffer->count = 0;
+ arg->buffer->source = NULL;
+
+}
+
+static void
+glamor_glyphs_flush_dst(struct glyphs_flush_dst_arg * arg)
+{
+ if (!arg->buffer)
+ return;
+
+ if (mask_buffer.count > 0) {
+ glamor_glyphs_flush_mask(&mask_arg);
+ }
+ if (mask_arg.used_bitmap) {
+ put_mask_cache_bitmap(mask_arg.maskcache, mask_arg.used_bitmap);
+ mask_arg.used_bitmap = 0;
+ }
+
+ if (arg->buffer->count > 0) {
+ glamor_composite_glyph_rects(arg->op, arg->src,
+ arg->buffer->source, arg->dst,
+ arg->buffer->count,
+ &arg->buffer->rects[0]);
+ arg->buffer->count = 0;
+ arg->buffer->source = NULL;
+ }
+}
+
+
+static glamor_glyph_cache_result_t
+glamor_buffer_glyph(glamor_screen_private *glamor_priv,
+ glamor_glyph_buffer_t * buffer,
+ PictFormatShort format,
+ GlyphPtr glyph, struct glamor_glyph *priv,
+ int x_glyph, int y_glyph,
+ int dx, int dy, int w, int h,
+ int glyphs_dst_mode,
+ glyphs_flush_func glyphs_flush, void *flush_arg)
+{
+ ScreenPtr screen = glamor_priv->screen;
+ glamor_composite_rect_t *rect;
+ PicturePtr source;
+ int x, y;
+ glamor_glyph_cache_t *cache;
+
+ if (glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST)
+ priv = glamor_glyph_get_private(glyph);
+
+ if (PICT_FORMAT_BPP(format) == 1)
+ format = PICT_a8;
+
+ cache =
+ &glamor_priv->glyphCaches[PICT_FORMAT_RGB(format) != 0];
+
+ if (buffer->source
+ && buffer->source != cache->picture
+ && glyphs_flush) {
+ (*glyphs_flush)(flush_arg);
+ glyphs_flush = NULL;
+ }
+
+ if (buffer->count == GLYPH_BUFFER_SIZE
+ && glyphs_flush) {
+ (*glyphs_flush)(flush_arg);
+ glyphs_flush = NULL;
+ }
+
+ if (priv && priv->cached) {
+ rect = &buffer->rects[buffer->count++];
+ rect->x_src = priv->x + dx;
+ rect->y_src = priv->y + dy;
+ if (buffer->source == NULL)
+ buffer->source = priv->cache->picture;
+ if (glyphs_dst_mode <= GLYPHS_DST_MODE_VIA_MASK_CACHE)
+ assert(priv->cache->glyphs[priv->pos] == glyph);
+ } else {
+ assert(glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST);
+ if (glyphs_flush)
+ (*glyphs_flush)(flush_arg);
+ source = glamor_glyph_cache(glamor_priv, glyph, &x, &y);
+
+ if (source != NULL) {
+ rect = &buffer->rects[buffer->count++];
+ rect->x_src = x + dx;
+ rect->y_src = y + dy;
+ if (buffer->source == NULL)
+ buffer->source = source;
+ if (glyphs_dst_mode == GLYPHS_DST_MODE_VIA_MASK_CACHE) {
+ glamor_gl_dispatch *dispatch;
+ /* mode 1 means we are using global mask cache,
+ * thus we have to composite from the cache picture
+ * to the cache picture, we need a flush here to make
+ * sure latter we get the corret glyphs data.*/
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glFlush();
+ glamor_put_dispatch(glamor_priv);
+ }
+ } else {
+ /* Couldn't find the glyph in the cache, use the glyph picture directly */
+ source = GlyphPicture(glyph)[screen->myNum];
+ if (buffer->source
+ && buffer->source != source
+ && glyphs_flush)
+ (*glyphs_flush)(flush_arg);
+ buffer->source = source;
+
+ rect = &buffer->rects[buffer->count++];
+ rect->x_src = 0 + dx;
+ rect->y_src = 0 + dy;
+ }
+ priv = glamor_glyph_get_private(glyph);
+ }
+
+ rect->x_dst = x_glyph;
+ rect->y_dst = y_glyph;
+ if (glyphs_dst_mode != GLYPHS_DST_MODE_MASK_TO_DST) {
+ rect->x_dst -= glyph->info.x;
+ rect->y_dst -= glyph->info.y;
+ }
+ rect->width = w;
+ rect->height = h;
+ if (glyphs_dst_mode > GLYPHS_DST_MODE_VIA_MASK_CACHE) {
+ rect->x_mask = rect->x_src;
+ rect->y_mask = rect->y_src;
+ rect->x_src = dst_arg.x_src + rect->x_dst - dst_arg.x_dst;
+ rect->y_src = dst_arg.y_src + rect->y_dst - dst_arg.y_dst;
+ }
+
+ return GLAMOR_GLYPH_SUCCESS;
+}
+
+
+static void
+glamor_buffer_glyph_clip(glamor_screen_private *glamor_priv,
+ BoxPtr rects,
+ int nrect, PictFormatShort format,
+ GlyphPtr glyph, struct glamor_glyph *priv,
+ int glyph_x, int glyph_y,
+ int glyph_dx, int glyph_dy,
+ int width, int height,
+ int glyphs_mode,
+ glyphs_flush_func flush_func,
+ void *arg
+ )
+{
+ int i;
+ for (i = 0; i < nrect; i++) {
+ int dst_x, dst_y;
+ int dx, dy;
+ int x2, y2;
+
+ dst_x = glyph_x - glyph_dx;
+ dst_y = glyph_y - glyph_dy;
+ x2 = dst_x + width;
+ y2 = dst_y + height;
+ dx = dy = 0;
+ if (rects[i].y1 >= y2)
+ break;
+
+ if (dst_x < rects[i].x1)
+ dx = rects[i].x1 - dst_x, dst_x = rects[i].x1;
+ if (x2 > rects[i].x2)
+ x2 = rects[i].x2;
+ if (dst_y < rects[i].y1)
+ dy = rects[i].y1 - dst_y, dst_y = rects[i].y1;
+ if (y2 > rects[i].y2)
+ y2 = rects[i].y2;
+ if (dst_x < x2 && dst_y < y2) {
+
+ glamor_buffer_glyph(glamor_priv,
+ &dst_buffer,
+ format,
+ glyph, priv,
+ dst_x + glyph_dx,
+ dst_y + glyph_dy,
+ dx, dy,
+ x2 - dst_x, y2 - dst_y,
+ glyphs_mode,
+ flush_func,
+ arg);
+ }
+ }
+}
+
+
+static void
+glamor_glyphs_via_mask(CARD8 op,
+ PicturePtr src,
+ PicturePtr dst,
+ PictFormatPtr mask_format,
+ INT16 x_src,
+ INT16 y_src,
+ int nlist, GlyphListPtr list, GlyphPtr * glyphs,
+ Bool use_mask_cache)
+{
+ PixmapPtr mask_pixmap = 0;
+ PicturePtr mask;
+ ScreenPtr screen = dst->pDrawable->pScreen;
+ int width = 0, height = 0;
+ int x, y;
+ int x_dst = list->xOff, y_dst = list->yOff;
+ int n;
+ GlyphPtr glyph;
+ int error;
+ BoxRec extents = { 0, 0, 0, 0 };
+ XID component_alpha;
+ glamor_screen_private *glamor_priv;
+ int need_free_mask = FALSE;
+ glamor_glyph_buffer_t buffer;
+ struct glyphs_flush_mask_arg arg;
+ glamor_glyph_buffer_t *pmask_buffer;
+ struct glyphs_flush_mask_arg *pmask_arg;
+ struct glamor_glyph_mask_cache_entry *mce = NULL;
+ struct glamor_glyph_mask_cache *maskcache;
+ glamor_glyph_cache_t *cache;
+ int glyphs_dst_mode;
+
+ glamor_glyph_extents(nlist, list, glyphs, &extents);
+
+ if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
+ return;
+ glamor_priv = glamor_get_screen_private(screen);
+ width = extents.x2 - extents.x1;
+ height = extents.y2 - extents.y1;
+
+ if (mask_format->depth == 1) {
+ PictFormatPtr a8Format =
+ PictureMatchFormat(screen, 8, PICT_a8);
+
+ if (a8Format)
+ mask_format = a8Format;
+ }
+
+ cache = &glamor_priv->glyphCaches
+ [PICT_FORMAT_RGB(mask_format->format) != 0];
+ maskcache = mask_cache[PICT_FORMAT_RGB(mask_format->format) != 0];
+
+ x = -extents.x1;
+ y = -extents.y1;
+ if (!use_mask_cache
+ || width > (CACHE_PICTURE_SIZE/4)
+ || height > MASK_CACHE_MAX_SIZE) {
+new_mask_pixmap:
+ mask_pixmap = glamor_create_pixmap(screen, width, height,
+ mask_format->depth,
+ CREATE_PIXMAP_USAGE_SCRATCH);
+ if (!mask_pixmap) {
+ glamor_destroy_pixmap(mask_pixmap);
+ return;
+ }
+ glamor_solid(mask_pixmap, 0, 0, width, height, GXcopy, 0xFFFFFFFF, 0);
+ component_alpha = NeedsComponent(mask_format->format);
+ mask = CreatePicture(0, &mask_pixmap->drawable,
+ mask_format, CPComponentAlpha,
+ &component_alpha, serverClient, &error);
+ if (!mask)
+ return;
+ need_free_mask = TRUE;
+ pmask_arg = &arg;
+ pmask_buffer = &buffer;
+ pmask_buffer->count = 0;
+ pmask_buffer->source = NULL;
+ pmask_arg->used_bitmap = 0;
+ glyphs_dst_mode = GLYPHS_DST_MODE_VIA_MASK;
+ } else {
+ int retry_cnt = 0;
+retry:
+ mce = get_mask_cache(maskcache,
+ (width + MASK_CACHE_MAX_SIZE - 1) / MASK_CACHE_MAX_SIZE);
+
+ if (mce == NULL) {
+ glamor_glyphs_flush_dst(&dst_arg);
+ retry_cnt++;
+ if (retry_cnt > 2) {
+ assert(0);
+ goto new_mask_pixmap;
+ }
+ goto retry;
+ }
+
+ mask = cache->picture;
+ x += mce->x;
+ y += mce->y;
+ mce->width = (width + MASK_CACHE_MAX_SIZE - 1) / MASK_CACHE_MAX_SIZE;
+ mce->height = 1;
+ if (mask_arg.mask && mask_arg.mask != mask
+ && mask_buffer.count != 0)
+ glamor_glyphs_flush_dst(&dst_arg);
+ pmask_arg = &mask_arg;
+ pmask_buffer = &mask_buffer;
+ pmask_arg->maskcache = maskcache;
+ glyphs_dst_mode = GLYPHS_DST_MODE_VIA_MASK_CACHE;
+ }
+ pmask_arg->mask = mask;
+ pmask_arg->buffer = pmask_buffer;
+ while (nlist--) {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ mask_glyphs_cnt += n;
+ while (n--) {
+ glyph = *glyphs++;
+ if (glyph->info.width > 0
+ && glyph->info.height > 0) {
+ glyphs_flush_func flush_func;
+ void *temp_arg;
+ if (need_free_mask) {
+ if (pmask_buffer->count)
+ flush_func = (glyphs_flush_func)glamor_glyphs_flush_mask;
+ else
+ flush_func = NULL;
+ temp_arg = pmask_arg;
+ } else {
+ /* If we are using global mask cache, then we need to
+ * flush dst instead of mask. As some dst depends on the
+ * previous mask result. Just flush mask can't get all previous's
+ * overlapped glyphs.*/
+ if (dst_buffer.count || mask_buffer.count)
+ flush_func = (glyphs_flush_func)glamor_glyphs_flush_dst;
+ else
+ flush_func = NULL;
+ temp_arg = &dst_arg;
+ }
+ glamor_buffer_glyph(glamor_priv, pmask_buffer,
+ mask_format->format,
+ glyph, NULL, x, y,
+ 0, 0,
+ glyph->info.width, glyph->info.height,
+ glyphs_dst_mode,
+ flush_func,
+ (void*)temp_arg);
+ }
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ list++;
+ }
+
+ x = extents.x1;
+ y = extents.y1;
+ if (need_free_mask) {
+ glamor_glyphs_flush_mask(pmask_arg);
+ CompositePicture(op,
+ src,
+ mask,
+ dst,
+ x_src + x - x_dst,
+ y_src + y - y_dst, 0, 0, x, y, width, height);
+ FreePicture(mask, 0);
+ glamor_destroy_pixmap(mask_pixmap);
+ } else {
+ struct glamor_glyph priv;
+ glyphs_flush_func flush_func;
+ BoxPtr rects;
+ int nrect;
+
+ priv.cache = cache;
+ priv.x = mce->x;
+ priv.y = mce->y;
+ priv.cached = TRUE;
+ rects = REGION_RECTS(dst->pCompositeClip);
+ nrect = REGION_NUM_RECTS(dst->pCompositeClip);
+
+ pmask_arg->used_bitmap |= ((1 << mce->width) - 1) << mce->idx;
+ dst_arg.op = op;
+ dst_arg.src = src;
+ dst_arg.dst = dst;
+ dst_arg.buffer = &dst_buffer;
+ dst_arg.x_src = x_src;
+ dst_arg.y_src = y_src;
+ dst_arg.x_dst = x_dst;
+ dst_arg.y_dst = y_dst;
+
+ if (dst_buffer.source == NULL) {
+ dst_buffer.source = cache->picture;
+ } else if (dst_buffer.source != cache->picture) {
+ glamor_glyphs_flush_dst(&dst_arg);
+ dst_buffer.source = cache->picture;
+ }
+
+ x += dst->pDrawable->x;
+ y += dst->pDrawable->y;
+
+ if (dst_buffer.count || mask_buffer.count)
+ flush_func = (glyphs_flush_func)glamor_glyphs_flush_dst;
+ else
+ flush_func = NULL;
+
+ glamor_buffer_glyph_clip(glamor_priv,
+ rects, nrect,
+ mask_format->format,
+ NULL, &priv,
+ x, y,
+ 0, 0,
+ width, height,
+ GLYPHS_DST_MODE_MASK_TO_DST,
+ flush_func,
+ (void *)&dst_arg
+ );
+ }
+}
+
+static void
+glamor_glyphs_to_dst(CARD8 op,
+ PicturePtr src,
+ PicturePtr dst,
+ INT16 x_src,
+ INT16 y_src,
+ int nlist, GlyphListPtr list,
+ GlyphPtr * glyphs)
+{
+ ScreenPtr screen = dst->pDrawable->pScreen;
+ int x = 0, y = 0;
+ int x_dst = list->xOff, y_dst = list->yOff;
+ int n;
+ GlyphPtr glyph;
+ BoxPtr rects;
+ int nrect;
+ glamor_screen_private *glamor_priv;
+
+ rects = REGION_RECTS(dst->pCompositeClip);
+ nrect = REGION_NUM_RECTS(dst->pCompositeClip);
+
+ glamor_priv = glamor_get_screen_private(screen);
+
+ dst_arg.op = op;
+ dst_arg.src = src;
+ dst_arg.dst = dst;
+ dst_arg.buffer = &dst_buffer;
+ dst_arg.x_src = x_src;
+ dst_arg.y_src = y_src;
+ dst_arg.x_dst = x_dst;
+ dst_arg.y_dst = y_dst;
+
+ x = dst->pDrawable->x;
+ y = dst->pDrawable->y;
+
+ while (nlist--) {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ dst_glyphs_cnt += n;
+ while (n--) {
+ glyph = *glyphs++;
+
+ if (glyph->info.width > 0
+ && glyph->info.height > 0) {
+ glyphs_flush_func flush_func;
+
+ if (dst_buffer.count || mask_buffer.count)
+ flush_func = (glyphs_flush_func)glamor_glyphs_flush_dst;
+ else
+ flush_func = NULL;
+ glamor_buffer_glyph_clip(glamor_priv,
+ rects, nrect,
+ (GlyphPicture(glyph)[screen->myNum])->format,
+ glyph, NULL,
+ x, y,
+ glyph->info.x, glyph->info.y,
+ glyph->info.width, glyph->info.height,
+ GLYPHS_DST_MODE_TO_DST,
+ flush_func,
+ (void *)&dst_arg
+ );
+ }
+
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ list++;
+ }
+}
+#define MAX_FIXED_SIZE
+static void
+glamor_glyphs_reset_buffer(glamor_glyph_buffer_t *buffer)
+{
+ buffer->count = 0;
+ buffer->source = NULL;
+}
+
+static Bool
+_glamor_glyphs(CARD8 op,
+ PicturePtr src,
+ PicturePtr dst,
+ PictFormatPtr mask_format,
+ INT16 x_src,
+ INT16 y_src, int nlist, GlyphListPtr list,
+ GlyphPtr * glyphs, Bool fallback)
+{
+ PictFormatShort format;
+ int fixed_size, fixed_cnt = 0;
+ struct glamor_glyph_list *fixed_list = NULL;
+ Bool need_free_list = FALSE;
+#ifndef GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK
+ Bool check_fake_overlap = TRUE;
+ if (!(op == PictOpOver
+ || op == PictOpAdd
+ || op == PictOpXor)) {
+ /* C = (0,0,0,0) D = glyphs , SRC = A, DEST = B (faked overlapped glyphs, overlapped with (0,0,0,0)).
+ * For those op, (A IN (C ADD D)) OP B != (A IN D) OP ((A IN C) OP B)
+ * or (A IN (D ADD C)) OP B != (A IN C) OP ((A IN D) OP B)
+ * We need to split the faked regions to three or two, and composite the disoverlapped small
+ * boxes one by one. For other Ops, it's safe to composite the whole box. */
+ check_fake_overlap = FALSE;
+ }
+#else
+ Bool check_fake_overlap = FALSE;
+#endif
+ if (mask_format)
+ format = mask_format->depth << 24 | mask_format->format;
+ else
+ format = 0;
+
+ fixed_size = 32;
+ glamor_glyphs_reset_buffer(&dst_buffer);
+
+ if (!mask_format || (((nlist == 1 && list->len == 1) || op == PictOpAdd)
+ && (dst->format == ((mask_format->depth << 24) | mask_format->format)))) {
+ glamor_glyphs_to_dst(op, src, dst, x_src, y_src, nlist,
+ list, glyphs);
+ goto last_flush;
+ }
+
+ glamor_glyphs_reset_buffer(&mask_buffer);
+
+ /* We have mask_format. Need to check the real overlap or not.*/
+ format = mask_format->depth << 24 | mask_format->format;
+
+ fixed_list = calloc(fixed_size, sizeof(*fixed_list));
+ if (unlikely(fixed_list == NULL))
+ fixed_size = 0;
+ fixed_cnt = glamor_glyphs_intersect(nlist, list, glyphs,
+ format, dst->pDrawable->pScreen,
+ check_fake_overlap,
+ fixed_list, fixed_size);
+ if (fixed_cnt == 0)
+ mask_format = NULL;
+ need_free_list = TRUE;
+
+ if (fixed_cnt <= 0) {
+ if (mask_format == NULL) {
+ glamor_glyphs_to_dst(op, src, dst, x_src, y_src, nlist,
+ list, glyphs);
+ goto last_flush;
+ } else {
+ glamor_glyphs_via_mask(op, src, dst, mask_format,
+ x_src, y_src, nlist, list, glyphs,
+ FALSE);
+ goto free_fixed_list;
+ }
+ } else {
+
+ /* We have splitted the original list to serval list, some are overlapped
+ * and some are non-overlapped. For the non-overlapped, we render it to
+ * dst directly. For the overlapped, we render it to mask picture firstly,
+ * then render the mask to dst. If we can use mask cache which is in the
+ * glyphs cache's last row, we can accumulate the rendering of mask to dst
+ * with the other dst_buffer's rendering operations thus can reduce the call
+ * of glDrawElements.
+ *
+ * */
+ struct glamor_glyph_list *saved_list;
+
+ saved_list = fixed_list;
+ mask_arg.used_bitmap = 0;
+ while(fixed_cnt--) {
+ if (fixed_list->type == NON_INTERSECTED) {
+ glamor_glyphs_to_dst(op, src, dst,
+ x_src, y_src,
+ fixed_list->nlist,
+ fixed_list->list,
+ fixed_list->glyphs);
+ }
+ else
+ glamor_glyphs_via_mask(op, src, dst,
+ mask_format, x_src, y_src,
+ fixed_list->nlist,
+ fixed_list->list,
+ fixed_list->glyphs, TRUE);
+
+ free(fixed_list->list);
+ fixed_list++;
+ }
+ free(saved_list);
+ need_free_list = FALSE;
+ }
+
+last_flush:
+ if (dst_buffer.count || mask_buffer.count)
+ glamor_glyphs_flush_dst(&dst_arg);
+free_fixed_list:
+ if(need_free_list) {
+ assert(fixed_cnt <= 0);
+ free(fixed_list);
+ }
+ return TRUE;
+}
+
+void
+glamor_glyphs(CARD8 op,
+ PicturePtr src,
+ PicturePtr dst,
+ PictFormatPtr mask_format,
+ INT16 x_src,
+ INT16 y_src, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
+{
+ _glamor_glyphs(op, src, dst, mask_format, x_src,
+ y_src, nlist, list, glyphs, TRUE);
+}
+
+Bool
+glamor_glyphs_nf(CARD8 op,
+ PicturePtr src,
+ PicturePtr dst,
+ PictFormatPtr mask_format,
+ INT16 x_src,
+ INT16 y_src, int nlist,
+ GlyphListPtr list, GlyphPtr * glyphs)
+{
+ return _glamor_glyphs(op, src, dst, mask_format, x_src,
+ y_src, nlist, list, glyphs, FALSE);
+}
+
diff --git a/glamor/glamor_gradient.c b/glamor/glamor_gradient.c
new file mode 100644
index 000000000..4abc82d74
--- /dev/null
+++ b/glamor/glamor_gradient.c
@@ -0,0 +1,1584 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * 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:
+ * Junyan He <junyan.he@linux.intel.com>
+ *
+ */
+
+/** @file glamor_gradient.c
+ *
+ * Gradient acceleration implementation
+ */
+
+#include "glamor_priv.h"
+
+#ifdef RENDER
+
+#define LINEAR_SMALL_STOPS (6 + 2)
+#define LINEAR_LARGE_STOPS (16 + 2)
+
+#define RADIAL_SMALL_STOPS (6 + 2)
+#define RADIAL_LARGE_STOPS (16 + 2)
+
+#ifdef GLAMOR_GRADIENT_SHADER
+
+static GLint
+_glamor_create_getcolor_fs_program(ScreenPtr screen, int stops_count, int use_array)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+
+ char *gradient_fs = NULL;
+ GLint fs_getcolor_prog;
+
+ #define gradient_fs_getcolor\
+ GLAMOR_DEFAULT_PRECISION\
+ "uniform int n_stop;\n"\
+ "uniform float stops[%d];\n"\
+ "uniform vec4 stop_colors[%d];\n"\
+ "vec4 get_color(float stop_len)\n"\
+ "{\n"\
+ " int i = 0;\n"\
+ " float new_alpha; \n"\
+ " vec4 gradient_color;\n"\
+ " float percentage; \n"\
+ " for(i = 0; i < n_stop - 1; i++) {\n"\
+ " if(stop_len < stops[i])\n"\
+ " break; \n"\
+ " }\n"\
+ " \n"\
+ " if(stops[i] - stops[i-1] > 2.0)\n"\
+ " percentage = 0.0;\n" /*For comply with pixman, walker->stepper overflow.*/\
+ " else if(stops[i] - stops[i-1] < 0.000001)\n"\
+ " percentage = 0.0;\n"\
+ " else \n"\
+ " percentage = (stop_len - stops[i-1])/(stops[i] - stops[i-1]);\n"\
+ " new_alpha = percentage * stop_colors[i].a + \n"\
+ " (1.0-percentage) * stop_colors[i-1].a; \n"\
+ " gradient_color = vec4((percentage * stop_colors[i].rgb \n"\
+ " + (1.0-percentage) * stop_colors[i-1].rgb)*new_alpha, \n"\
+ " new_alpha);\n"\
+ " \n"\
+ " return gradient_color;\n"\
+ "}\n"
+
+ /* Because the array access for shader is very slow, the performance is very low
+ if use array. So use global uniform to replace for it if the number of n_stops is small.*/
+ const char *gradient_fs_getcolor_no_array =
+ GLAMOR_DEFAULT_PRECISION
+ "uniform int n_stop;\n"
+ "uniform float stop0;\n"
+ "uniform float stop1;\n"
+ "uniform float stop2;\n"
+ "uniform float stop3;\n"
+ "uniform float stop4;\n"
+ "uniform float stop5;\n"
+ "uniform float stop6;\n"
+ "uniform float stop7;\n"
+ "uniform vec4 stop_color0;\n"
+ "uniform vec4 stop_color1;\n"
+ "uniform vec4 stop_color2;\n"
+ "uniform vec4 stop_color3;\n"
+ "uniform vec4 stop_color4;\n"
+ "uniform vec4 stop_color5;\n"
+ "uniform vec4 stop_color6;\n"
+ "uniform vec4 stop_color7;\n"
+ "\n"
+ "vec4 get_color(float stop_len)\n"
+ "{\n"
+ " float stop_after;\n"
+ " float stop_before;\n"
+ " vec4 stop_color_before;\n"
+ " vec4 stop_color_after;\n"
+ " float new_alpha; \n"
+ " vec4 gradient_color;\n"
+ " float percentage; \n"
+ " \n"
+ " if((stop_len < stop0) && (n_stop >= 1)) {\n"
+ " stop_color_before = stop_color0;\n"
+ " stop_color_after = stop_color0;\n"
+ " stop_after = stop0;\n"
+ " stop_before = stop0;\n"
+ " } else if((stop_len < stop1) && (n_stop >= 2)) {\n"
+ " stop_color_before = stop_color0;\n"
+ " stop_color_after = stop_color1;\n"
+ " stop_after = stop1;\n"
+ " stop_before = stop0;\n"
+ " } else if((stop_len < stop2) && (n_stop >= 3)) {\n"
+ " stop_color_before = stop_color1;\n"
+ " stop_color_after = stop_color2;\n"
+ " stop_after = stop2;\n"
+ " stop_before = stop1;\n"
+ " } else if((stop_len < stop3) && (n_stop >= 4)){\n"
+ " stop_color_before = stop_color2;\n"
+ " stop_color_after = stop_color3;\n"
+ " stop_after = stop3;\n"
+ " stop_before = stop2;\n"
+ " } else if((stop_len < stop4) && (n_stop >= 5)){\n"
+ " stop_color_before = stop_color3;\n"
+ " stop_color_after = stop_color4;\n"
+ " stop_after = stop4;\n"
+ " stop_before = stop3;\n"
+ " } else if((stop_len < stop5) && (n_stop >= 6)){\n"
+ " stop_color_before = stop_color4;\n"
+ " stop_color_after = stop_color5;\n"
+ " stop_after = stop5;\n"
+ " stop_before = stop4;\n"
+ " } else if((stop_len < stop6) && (n_stop >= 7)){\n"
+ " stop_color_before = stop_color5;\n"
+ " stop_color_after = stop_color6;\n"
+ " stop_after = stop6;\n"
+ " stop_before = stop5;\n"
+ " } else if((stop_len < stop7) && (n_stop >= 8)){\n"
+ " stop_color_before = stop_color6;\n"
+ " stop_color_after = stop_color7;\n"
+ " stop_after = stop7;\n"
+ " stop_before = stop6;\n"
+ " } else {\n"
+ " stop_color_before = stop_color7;\n"
+ " stop_color_after = stop_color7;\n"
+ " stop_after = stop7;\n"
+ " stop_before = stop7;\n"
+ " }\n"
+ " if(stop_after - stop_before > 2.0)\n"
+ " percentage = 0.0;\n"//For comply with pixman, walker->stepper overflow.
+ " else if(stop_after - stop_before < 0.000001)\n"
+ " percentage = 0.0;\n"
+ " else \n"
+ " percentage = (stop_len - stop_before)/(stop_after - stop_before);\n"
+ " new_alpha = percentage * stop_color_after.a + \n"
+ " (1.0-percentage) * stop_color_before.a; \n"
+ " gradient_color = vec4((percentage * stop_color_after.rgb \n"
+ " + (1.0-percentage) * stop_color_before.rgb)*new_alpha, \n"
+ " new_alpha);\n"
+ " \n"
+ " return gradient_color;\n"
+ "}\n";
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+ if(use_array) {
+ XNFasprintf(&gradient_fs,
+ gradient_fs_getcolor, stops_count, stops_count);
+ fs_getcolor_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER,
+ gradient_fs);
+ free(gradient_fs);
+ } else {
+ fs_getcolor_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER,
+ gradient_fs_getcolor_no_array);
+ }
+
+ return fs_getcolor_prog;
+}
+
+static void
+_glamor_create_radial_gradient_program(ScreenPtr screen, int stops_count, int dyn_gen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ int index;
+
+ GLint gradient_prog = 0;
+ char *gradient_fs = NULL;
+ GLint fs_main_prog, fs_getcolor_prog, vs_prog;
+
+ const char *gradient_vs =
+ GLAMOR_DEFAULT_PRECISION
+ "attribute vec4 v_position;\n"
+ "attribute vec4 v_texcoord;\n"
+ "varying vec2 source_texture;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = v_position;\n"
+ " source_texture = v_texcoord.xy;\n"
+ "}\n";
+
+ /*
+ * Refer to pixman radial gradient.
+ *
+ * The problem is given the two circles of c1 and c2 with the radius of r1 and
+ * r1, we need to caculate the t, which is used to do interpolate with stops,
+ * using the fomula:
+ * length((1-t)*c1 + t*c2 - p) = (1-t)*r1 + t*r2
+ * expand the fomula with xy coond, get the following:
+ * sqrt(sqr((1-t)*c1.x + t*c2.x - p.x) + sqr((1-t)*c1.y + t*c2.y - p.y))
+ * = (1-t)r1 + t*r2
+ * <====> At*t- 2Bt + C = 0
+ * where A = sqr(c2.x - c1.x) + sqr(c2.y - c1.y) - sqr(r2 -r1)
+ * B = (p.x - c1.x)*(c2.x - c1.x) + (p.y - c1.y)*(c2.y - c1.y) + r1*(r2 -r1)
+ * C = sqr(p.x - c1.x) + sqr(p.y - c1.y) - r1*r1
+ *
+ * solve the fomula and we get the result of
+ * t = (B + sqrt(B*B - A*C)) / A or
+ * t = (B - sqrt(B*B - A*C)) / A (quadratic equation have two solutions)
+ *
+ * The solution we are going to prefer is the bigger one, unless the
+ * radius associated to it is negative (or it falls outside the valid t range)
+ */
+
+ #define gradient_radial_fs_template\
+ GLAMOR_DEFAULT_PRECISION\
+ "uniform mat3 transform_mat;\n"\
+ "uniform int repeat_type;\n"\
+ "uniform float A_value;\n"\
+ "uniform vec2 c1;\n"\
+ "uniform float r1;\n"\
+ "uniform vec2 c2;\n"\
+ "uniform float r2;\n"\
+ "varying vec2 source_texture;\n"\
+ "\n"\
+ "vec4 get_color(float stop_len);\n"\
+ "\n"\
+ "int t_invalid;\n"\
+ "\n"\
+ "float get_stop_len()\n"\
+ "{\n"\
+ " float t = 0.0;\n"\
+ " float sqrt_value;\n"\
+ " int revserse = 0;\n"\
+ " t_invalid = 0;\n"\
+ " \n"\
+ " vec3 tmp = vec3(source_texture.x, source_texture.y, 1.0);\n"\
+ " vec3 source_texture_trans = transform_mat * tmp;\n"\
+ " source_texture_trans.xy = source_texture_trans.xy/source_texture_trans.z;\n"\
+ " float B_value = (source_texture_trans.x - c1.x) * (c2.x - c1.x)\n"\
+ " + (source_texture_trans.y - c1.y) * (c2.y - c1.y)\n"\
+ " + r1 * (r2 - r1);\n"\
+ " float C_value = (source_texture_trans.x - c1.x) * (source_texture_trans.x - c1.x)\n"\
+ " + (source_texture_trans.y - c1.y) * (source_texture_trans.y - c1.y)\n"\
+ " - r1*r1;\n"\
+ " if(abs(A_value) < 0.00001) {\n"\
+ " if(B_value == 0.0) {\n"\
+ " t_invalid = 1;\n"\
+ " return t;\n"\
+ " }\n"\
+ " t = 0.5 * C_value / B_value;"\
+ " } else {\n"\
+ " sqrt_value = B_value * B_value - A_value * C_value;\n"\
+ " if(sqrt_value < 0.0) {\n"\
+ " t_invalid = 1;\n"\
+ " return t;\n"\
+ " }\n"\
+ " sqrt_value = sqrt(sqrt_value);\n"\
+ " t = (B_value + sqrt_value) / A_value;\n"\
+ " }\n"\
+ " if(repeat_type == %d) {\n" /* RepeatNone case. */\
+ " if((t <= 0.0) || (t > 1.0))\n"\
+ /* try another if first one invalid*/\
+ " t = (B_value - sqrt_value) / A_value;\n"\
+ " \n"\
+ " if((t <= 0.0) || (t > 1.0)) {\n" /*still invalid, return.*/\
+ " t_invalid = 1;\n"\
+ " return t;\n"\
+ " }\n"\
+ " } else {\n"\
+ " if(t * (r2 - r1) <= -1.0 * r1)\n"\
+ /* try another if first one invalid*/\
+ " t = (B_value - sqrt_value) / A_value;\n"\
+ " \n"\
+ " if(t * (r2 -r1) <= -1.0 * r1) {\n" /*still invalid, return.*/\
+ " t_invalid = 1;\n"\
+ " return t;\n"\
+ " }\n"\
+ " }\n"\
+ " \n"\
+ " if(repeat_type == %d){\n" /* repeat normal*/\
+ " while(t > 1.0) \n"\
+ " t = t - 1.0; \n"\
+ " while(t < 0.0) \n"\
+ " t = t + 1.0; \n"\
+ " }\n"\
+ " \n"\
+ " if(repeat_type == %d) {\n" /* repeat reflect*/\
+ " while(t > 1.0) {\n"\
+ " t = t - 1.0; \n"\
+ " if(revserse == 0)\n"\
+ " revserse = 1;\n"\
+ " else\n"\
+ " revserse = 0;\n"\
+ " }\n"\
+ " while(t < 0.0) {\n"\
+ " t = t + 1.0; \n"\
+ " if(revserse == 0)\n"\
+ " revserse = 1;\n"\
+ " else\n"\
+ " revserse = 0;\n"\
+ " }\n"\
+ " if(revserse == 1) {\n"\
+ " t = 1.0 - t; \n"\
+ " }\n"\
+ " }\n"\
+ " \n"\
+ " return t;\n"\
+ "}\n"\
+ "\n"\
+ "void main()\n"\
+ "{\n"\
+ " float stop_len = get_stop_len();\n"\
+ " if(t_invalid == 1) {\n"\
+ " gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n"\
+ " } else {\n"\
+ " gl_FragColor = get_color(stop_len);\n"\
+ " }\n"\
+ "}\n"
+
+ glamor_priv = glamor_get_screen_private(screen);
+
+ if ((glamor_priv->radial_max_nstops >= stops_count) && (dyn_gen)) {
+ /* Very Good, not to generate again. */
+ return;
+ }
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+ if (dyn_gen && glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][2]) {
+ dispatch->glDeleteShader(
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_VS_PROG][2]);
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_VS_PROG][2] = 0;
+
+ dispatch->glDeleteShader(
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_FS_MAIN_PROG][2]);
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_FS_MAIN_PROG][2] = 0;
+
+ dispatch->glDeleteShader(
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_FS_GETCOLOR_PROG][2]);
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_FS_GETCOLOR_PROG][2] = 0;
+
+ dispatch->glDeleteProgram(glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][2]);
+ glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][2] = 0;
+ }
+
+ gradient_prog = dispatch->glCreateProgram();
+
+ vs_prog = glamor_compile_glsl_prog(dispatch,
+ GL_VERTEX_SHADER, gradient_vs);
+
+ XNFasprintf(&gradient_fs,
+ gradient_radial_fs_template,
+ PIXMAN_REPEAT_NONE, PIXMAN_REPEAT_NORMAL, PIXMAN_REPEAT_REFLECT);
+
+ fs_main_prog = glamor_compile_glsl_prog(dispatch,
+ GL_FRAGMENT_SHADER, gradient_fs);
+
+ free(gradient_fs);
+
+ fs_getcolor_prog =
+ _glamor_create_getcolor_fs_program(screen, stops_count, (stops_count > 0));
+
+ dispatch->glAttachShader(gradient_prog, vs_prog);
+ dispatch->glAttachShader(gradient_prog, fs_getcolor_prog);
+ dispatch->glAttachShader(gradient_prog, fs_main_prog);
+
+ dispatch->glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_POS, "v_positionsition");
+ dispatch->glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_SOURCE, "v_texcoord");
+
+ glamor_link_glsl_prog(dispatch, gradient_prog);
+
+ dispatch->glUseProgram(0);
+
+ if (dyn_gen) {
+ index = 2;
+ glamor_priv->radial_max_nstops = stops_count;
+ } else if (stops_count) {
+ index = 1;
+ } else {
+ index = 0;
+ }
+
+ glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][index] = gradient_prog;
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_VS_PROG][index] = vs_prog;
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_FS_MAIN_PROG][index] = fs_main_prog;
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_FS_GETCOLOR_PROG][index] = fs_getcolor_prog;
+
+ glamor_put_dispatch(glamor_priv);
+}
+
+static void
+_glamor_create_linear_gradient_program(ScreenPtr screen, int stops_count, int dyn_gen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+
+ int index = 0;
+ GLint gradient_prog = 0;
+ char *gradient_fs = NULL;
+ GLint fs_main_prog, fs_getcolor_prog, vs_prog;
+
+ const char *gradient_vs =
+ GLAMOR_DEFAULT_PRECISION
+ "attribute vec4 v_position;\n"
+ "attribute vec4 v_texcoord;\n"
+ "varying vec2 source_texture;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = v_position;\n"
+ " source_texture = v_texcoord.xy;\n"
+ "}\n";
+
+ /*
+ * |
+ * |\
+ * | \
+ * | \
+ * | \
+ * |\ \
+ * | \ \
+ * cos_val = |\ p1d \ /
+ * sqrt(1/(slope*slope+1.0)) ------>\ \ \ /
+ * | \ \ \
+ * | \ \ / \
+ * | \ *Pt1\
+ * *p1 | \ \ *P
+ * \ | / \ \ /
+ * \ | / \ \ /
+ * \ | pd \
+ * \ | \ / \
+ * p2* | \ / \ /
+ * slope = (p2.y - p1.y) / | / p2d /
+ * (p2.x - p1.x) | / \ /
+ * | / \ /
+ * | / /
+ * | / /
+ * | / *Pt2
+ * | /
+ * | /
+ * | /
+ * | /
+ * | /
+ * -------+---------------------------------
+ * O|
+ * |
+ * |
+ *
+ * step 1: compute the distance of p, pt1 and pt2 in the slope direction.
+ * Caculate the distance on Y axis first and multiply cos_val to
+ * get the value on slope direction(pd, p1d and p2d represent the
+ * distance of p, pt1, and pt2 respectively).
+ *
+ * step 2: caculate the percentage of (pd - p1d)/(p2d - p1d).
+ * If (pd - p1d) > (p2d - p1d) or < 0, then sub or add (p2d - p1d)
+ * to make it in the range of [0, (p2d - p1d)].
+ *
+ * step 3: compare the percentage to every stop and find the stpos just
+ * before and after it. Use the interpolation fomula to compute RGBA.
+ */
+
+ #define gradient_fs_template \
+ GLAMOR_DEFAULT_PRECISION\
+ "uniform mat3 transform_mat;\n"\
+ "uniform int repeat_type;\n"\
+ "uniform int hor_ver;\n"\
+ "uniform float pt_slope;\n"\
+ "uniform float cos_val;\n"\
+ "uniform float p1_distance;\n"\
+ "uniform float pt_distance;\n"\
+ "varying vec2 source_texture;\n"\
+ "\n"\
+ "vec4 get_color(float stop_len);\n"\
+ "\n"\
+ "float get_stop_len()\n"\
+ "{\n"\
+ " vec3 tmp = vec3(source_texture.x, source_texture.y, 1.0);\n"\
+ " float len_percentage;\n"\
+ " float distance;\n"\
+ " float _p1_distance;\n"\
+ " float _pt_distance;\n"\
+ " float y_dist;\n"\
+ " float stop_after;\n"\
+ " float stop_before;\n"\
+ " vec4 stop_color_before;\n"\
+ " vec4 stop_color_after;\n"\
+ " float new_alpha; \n"\
+ " int revserse = 0;\n"\
+ " vec4 gradient_color;\n"\
+ " float percentage; \n"\
+ " vec3 source_texture_trans = transform_mat * tmp;\n"\
+ " \n"\
+ " if(hor_ver == 0) { \n" /*Normal case.*/\
+ " y_dist = source_texture_trans.y - source_texture_trans.x*pt_slope;\n"\
+ " distance = y_dist * cos_val;\n"\
+ " _p1_distance = p1_distance * source_texture_trans.z;\n"\
+ " _pt_distance = pt_distance * source_texture_trans.z;\n"\
+ " \n"\
+ " } else if (hor_ver == 1) {\n"/*horizontal case.*/\
+ " distance = source_texture_trans.x;\n"\
+ " _p1_distance = p1_distance * source_texture_trans.z;\n"\
+ " _pt_distance = pt_distance * source_texture_trans.z;\n"\
+ " } \n"\
+ " \n"\
+ " distance = distance - _p1_distance; \n"\
+ " \n"\
+ " if(repeat_type == %d){\n" /* repeat normal*/\
+ " while(distance > _pt_distance) \n"\
+ " distance = distance - (_pt_distance); \n"\
+ " while(distance < 0.0) \n"\
+ " distance = distance + (_pt_distance); \n"\
+ " }\n"\
+ " \n"\
+ " if(repeat_type == %d) {\n" /* repeat reflect*/\
+ " while(distance > _pt_distance) {\n"\
+ " distance = distance - (_pt_distance); \n"\
+ " if(revserse == 0)\n"\
+ " revserse = 1;\n"\
+ " else\n"\
+ " revserse = 0;\n"\
+ " }\n"\
+ " while(distance < 0.0) {\n"\
+ " distance = distance + (_pt_distance); \n"\
+ " if(revserse == 0)\n"\
+ " revserse = 1;\n"\
+ " else\n"\
+ " revserse = 0;\n"\
+ " }\n"\
+ " if(revserse == 1) {\n"\
+ " distance = (_pt_distance) - distance; \n"\
+ " }\n"\
+ " }\n"\
+ " \n"\
+ " len_percentage = distance/(_pt_distance);\n"\
+ " \n"\
+ " return len_percentage;\n"\
+ "}\n"\
+ "\n"\
+ "void main()\n"\
+ "{\n"\
+ " float stop_len = get_stop_len();\n"\
+ " gl_FragColor = get_color(stop_len);\n"\
+ "}\n"
+
+ glamor_priv = glamor_get_screen_private(screen);
+
+ if ((glamor_priv->linear_max_nstops >= stops_count) && (dyn_gen)) {
+ /* Very Good, not to generate again. */
+ return;
+ }
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ if (dyn_gen && glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][2]) {
+ dispatch->glDeleteShader(
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_VS_PROG][2]);
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_VS_PROG][2] = 0;
+
+ dispatch->glDeleteShader(
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_FS_MAIN_PROG][2]);
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_FS_MAIN_PROG][2] = 0;
+
+ dispatch->glDeleteShader(
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_FS_GETCOLOR_PROG][2]);
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_FS_GETCOLOR_PROG][2] = 0;
+
+ dispatch->glDeleteProgram(glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][2]);
+ glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][2] = 0;
+ }
+
+ gradient_prog = dispatch->glCreateProgram();
+
+ vs_prog = glamor_compile_glsl_prog(dispatch,
+ GL_VERTEX_SHADER, gradient_vs);
+
+ XNFasprintf(&gradient_fs,
+ gradient_fs_template,
+ PIXMAN_REPEAT_NORMAL, PIXMAN_REPEAT_REFLECT);
+
+ fs_main_prog = glamor_compile_glsl_prog(dispatch,
+ GL_FRAGMENT_SHADER, gradient_fs);
+ free(gradient_fs);
+
+ fs_getcolor_prog =
+ _glamor_create_getcolor_fs_program(screen, stops_count, (stops_count > 0));
+
+ dispatch->glAttachShader(gradient_prog, vs_prog);
+ dispatch->glAttachShader(gradient_prog, fs_getcolor_prog);
+ dispatch->glAttachShader(gradient_prog, fs_main_prog);
+
+ dispatch->glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_POS, "v_position");
+ dispatch->glBindAttribLocation(gradient_prog, GLAMOR_VERTEX_SOURCE, "v_texcoord");
+
+ glamor_link_glsl_prog(dispatch, gradient_prog);
+
+ dispatch->glUseProgram(0);
+
+ if (dyn_gen) {
+ index = 2;
+ glamor_priv->linear_max_nstops = stops_count;
+ } else if (stops_count) {
+ index = 1;
+ } else {
+ index = 0;
+ }
+
+ glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][index] = gradient_prog;
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_VS_PROG][index] = vs_prog;
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_FS_MAIN_PROG][index] = fs_main_prog;
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_FS_GETCOLOR_PROG][index] = fs_getcolor_prog;
+
+ glamor_put_dispatch(glamor_priv);
+}
+
+void
+glamor_init_gradient_shader(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ int i;
+
+ glamor_priv = glamor_get_screen_private(screen);
+
+ for (i = 0; i < 3; i++) {
+ glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][i] = 0;
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_VS_PROG][i] = 0;
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_FS_MAIN_PROG][i] = 0;
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_FS_GETCOLOR_PROG][i] = 0;
+
+ glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][i] = 0;
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_VS_PROG][i] = 0;
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_FS_MAIN_PROG][i] = 0;
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_FS_GETCOLOR_PROG][i] = 0;
+ }
+ glamor_priv->linear_max_nstops = 0;
+ glamor_priv->radial_max_nstops = 0;
+
+ _glamor_create_linear_gradient_program(screen, 0, 0);
+ _glamor_create_linear_gradient_program(screen, LINEAR_LARGE_STOPS, 0);
+
+ _glamor_create_radial_gradient_program(screen, 0, 0);
+ _glamor_create_radial_gradient_program(screen, RADIAL_LARGE_STOPS, 0);
+}
+
+void
+glamor_fini_gradient_shader(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ int i = 0;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+ for (i = 0; i < 3; i++) {
+ /* Linear Gradient */
+ if (glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_VS_PROG][i])
+ dispatch->glDeleteShader(
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_VS_PROG][i]);
+
+ if (glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_FS_MAIN_PROG][i])
+ dispatch->glDeleteShader(
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_FS_MAIN_PROG][i]);
+
+ if (glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_FS_GETCOLOR_PROG][i])
+ dispatch->glDeleteShader(
+ glamor_priv->linear_gradient_shaders[SHADER_GRADIENT_FS_GETCOLOR_PROG][i]);
+
+ if (glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][i])
+ dispatch->glDeleteProgram(glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][i]);
+
+ /* Radial Gradient */
+ if (glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_VS_PROG][i])
+ dispatch->glDeleteShader(
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_VS_PROG][i]);
+
+ if (glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_FS_MAIN_PROG][i])
+ dispatch->glDeleteShader(
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_FS_MAIN_PROG][i]);
+
+ if (glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_FS_GETCOLOR_PROG][i])
+ dispatch->glDeleteShader(
+ glamor_priv->radial_gradient_shaders[SHADER_GRADIENT_FS_GETCOLOR_PROG][i]);
+
+ if (glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][i])
+ dispatch->glDeleteProgram(glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][i]);
+ }
+
+ glamor_put_dispatch(glamor_priv);
+}
+
+static void
+_glamor_gradient_convert_trans_matrix(PictTransform *from, float to[3][3],
+ int width, int height, int normalize)
+{
+ /*
+ * Because in the shader program, we normalize all the pixel cood to [0, 1],
+ * so with the transform matrix, the correct logic should be:
+ * v_s = A*T*v
+ * v_s: point vector in shader after normalized.
+ * A: The transition matrix from width X height --> 1.0 X 1.0
+ * T: The transform matrix.
+ * v: point vector in width X height space.
+ *
+ * result is OK if we use this fomula. But for every point in width X height space,
+ * we can just use their normalized point vector in shader, namely we can just
+ * use the result of A*v in shader. So we have no chance to insert T in A*v.
+ * We can just convert v_s = A*T*v to v_s = A*T*inv(A)*A*v, where inv(A) is the
+ * inverse matrix of A. Now, v_s = (A*T*inv(A)) * (A*v)
+ * So, to get the correct v_s, we need to cacula1 the matrix: (A*T*inv(A)), and
+ * we name this matrix T_s.
+ *
+ * Firstly, because A is for the scale convertion, we find
+ * -- --
+ * |1/w 0 0 |
+ * A = | 0 1/h 0 |
+ * | 0 0 1.0|
+ * -- --
+ * so T_s = A*T*inv(a) and result
+ *
+ * -- --
+ * | t11 h*t12/w t13/w|
+ * T_s = | w*t21/h t22 t23/h|
+ * | w*t31 h*t32 t33 |
+ * -- --
+ */
+
+ to[0][0] = (float)pixman_fixed_to_double(from->matrix[0][0]);
+ to[0][1] = (float)pixman_fixed_to_double(from->matrix[0][1])
+ * (normalize ? (((float)height) / ((float)width)) : 1.0);
+ to[0][2] = (float)pixman_fixed_to_double(from->matrix[0][2])
+ / (normalize ? ((float)width) : 1.0);
+
+ to[1][0] = (float)pixman_fixed_to_double(from->matrix[1][0])
+ * (normalize ? (((float)width) / ((float)height)) : 1.0);
+ to[1][1] = (float)pixman_fixed_to_double(from->matrix[1][1]);
+ to[1][2] = (float)pixman_fixed_to_double(from->matrix[1][2])
+ / (normalize ? ((float)height) : 1.0);
+
+ to[2][0] = (float)pixman_fixed_to_double(from->matrix[2][0])
+ * (normalize ? ((float)width) : 1.0);
+ to[2][1] = (float)pixman_fixed_to_double(from->matrix[2][1])
+ * (normalize ? ((float)height) : 1.0);
+ to[2][2] = (float)pixman_fixed_to_double(from->matrix[2][2]);
+
+ DEBUGF("the transform matrix is:\n%f\t%f\t%f\n%f\t%f\t%f\n%f\t%f\t%f\n",
+ to[0][0], to[0][1], to[0][2],
+ to[1][0], to[1][1], to[1][2],
+ to[2][0], to[2][1], to[2][2]);
+}
+
+static int
+_glamor_gradient_set_pixmap_destination(ScreenPtr screen,
+ glamor_screen_private *glamor_priv,
+ PicturePtr dst_picture,
+ GLfloat *xscale, GLfloat *yscale,
+ int x_source, int y_source,
+ float vertices[8],
+ float tex_vertices[8],
+ int tex_normalize)
+{
+ glamor_pixmap_private *pixmap_priv;
+ PixmapPtr pixmap = NULL;
+ glamor_gl_dispatch *dispatch = NULL;
+
+ pixmap = glamor_get_drawable_pixmap(dst_picture->pDrawable);
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) { /* should always have here. */
+ return 0;
+ }
+
+ glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+
+ pixmap_priv_get_dest_scale(pixmap_priv, xscale, yscale);
+
+ DEBUGF("xscale = %f, yscale = %f,"
+ " x_source = %d, y_source = %d, width = %d, height = %d\n",
+ *xscale, *yscale, x_source, y_source,
+ dst_picture->pDrawable->width, dst_picture->pDrawable->height);
+
+ glamor_set_normalize_vcoords_tri_strip(*xscale, *yscale,
+ 0, 0,
+ (INT16)(dst_picture->pDrawable->width),
+ (INT16)(dst_picture->pDrawable->height),
+ glamor_priv->yInverted, vertices);
+
+ if (tex_normalize) {
+ glamor_set_normalize_tcoords_tri_stripe(*xscale, *yscale,
+ x_source, y_source,
+ (INT16)(dst_picture->pDrawable->width + x_source),
+ (INT16)(dst_picture->pDrawable->height + y_source),
+ glamor_priv->yInverted, tex_vertices);
+ } else {
+ glamor_set_tcoords_tri_strip((INT16)(dst_picture->pDrawable->width),
+ (INT16)(dst_picture->pDrawable->height),
+ x_source, y_source,
+ (INT16)(dst_picture->pDrawable->width) + x_source,
+ (INT16)(dst_picture->pDrawable->height) + y_source,
+ glamor_priv->yInverted, tex_vertices);
+ }
+
+ DEBUGF("vertices --> leftup : %f X %f, rightup: %f X %f,"
+ "rightbottom: %f X %f, leftbottom : %f X %f\n",
+ vertices[0], vertices[1], vertices[2], vertices[3],
+ vertices[4], vertices[5], vertices[6], vertices[7]);
+ DEBUGF("tex_vertices --> leftup : %f X %f, rightup: %f X %f,"
+ "rightbottom: %f X %f, leftbottom : %f X %f\n",
+ tex_vertices[0], tex_vertices[1], tex_vertices[2], tex_vertices[3],
+ tex_vertices[4], tex_vertices[5], tex_vertices[6], tex_vertices[7]);
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
+ GL_FALSE, 0, vertices);
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT,
+ GL_FALSE, 0, tex_vertices);
+
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+
+ glamor_put_dispatch(glamor_priv);
+
+ return 1;
+}
+
+static int
+_glamor_gradient_set_stops(PicturePtr src_picture, PictGradient * pgradient,
+ GLfloat *stop_colors, GLfloat *n_stops)
+{
+ int i;
+ int count = 1;
+
+ for (i = 0; i < pgradient->nstops; i++) {
+ stop_colors[count*4] = pixman_fixed_to_double(
+ pgradient->stops[i].color.red);
+ stop_colors[count*4+1] = pixman_fixed_to_double(
+ pgradient->stops[i].color.green);
+ stop_colors[count*4+2] = pixman_fixed_to_double(
+ pgradient->stops[i].color.blue);
+ stop_colors[count*4+3] = pixman_fixed_to_double(
+ pgradient->stops[i].color.alpha);
+
+ n_stops[count] = (GLfloat)pixman_fixed_to_double(
+ pgradient->stops[i].x);
+ count++;
+ }
+
+ /* for the end stop. */
+ count++;
+
+ switch (src_picture->repeatType) {
+#define REPEAT_FILL_STOPS(m, n) \
+ stop_colors[(m)*4 + 0] = stop_colors[(n)*4 + 0]; \
+ stop_colors[(m)*4 + 1] = stop_colors[(n)*4 + 1]; \
+ stop_colors[(m)*4 + 2] = stop_colors[(n)*4 + 2]; \
+ stop_colors[(m)*4 + 3] = stop_colors[(n)*4 + 3];
+
+ default:
+ case PIXMAN_REPEAT_NONE:
+ stop_colors[0] = 0.0; //R
+ stop_colors[1] = 0.0; //G
+ stop_colors[2] = 0.0; //B
+ stop_colors[3] = 0.0; //Alpha
+ n_stops[0] = -(float)INT_MAX; //should be small enough.
+
+ stop_colors[0 + (count-1)*4] = 0.0; //R
+ stop_colors[1 + (count-1)*4] = 0.0; //G
+ stop_colors[2 + (count-1)*4] = 0.0; //B
+ stop_colors[3 + (count-1)*4] = 0.0; //Alpha
+ n_stops[count-1] = (float)INT_MAX; //should be large enough.
+ break;
+ case PIXMAN_REPEAT_NORMAL:
+ REPEAT_FILL_STOPS(0, count - 2);
+ n_stops[0] = n_stops[count-2] - 1.0;
+
+ REPEAT_FILL_STOPS(count - 1, 1);
+ n_stops[count-1] = n_stops[1] + 1.0;
+ break;
+ case PIXMAN_REPEAT_REFLECT:
+ REPEAT_FILL_STOPS(0, 1);
+ n_stops[0] = -n_stops[1];
+
+ REPEAT_FILL_STOPS(count - 1, count - 2);
+ n_stops[count-1] = 1.0 + 1.0 - n_stops[count-2];
+ break;
+ case PIXMAN_REPEAT_PAD:
+ REPEAT_FILL_STOPS(0, 1);
+ n_stops[0] = -(float)INT_MAX;
+
+ REPEAT_FILL_STOPS(count - 1, count - 2);
+ n_stops[count-1] = (float)INT_MAX;
+ break;
+#undef REPEAT_FILL_STOPS
+ }
+
+ for (i = 0; i < count; i++) {
+ DEBUGF("n_stops[%d] = %f, color = r:%f g:%f b:%f a:%f\n",
+ i, n_stops[i],
+ stop_colors[i*4], stop_colors[i*4+1],
+ stop_colors[i*4+2], stop_colors[i*4+3]);
+ }
+
+ return count;
+}
+
+PicturePtr
+glamor_generate_radial_gradient_picture(ScreenPtr screen,
+ PicturePtr src_picture,
+ int x_source, int y_source,
+ int width, int height,
+ PictFormatShort format)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ PicturePtr dst_picture = NULL;
+ PixmapPtr pixmap = NULL;
+ GLint gradient_prog = 0;
+ int error;
+ float tex_vertices[8];
+ int stops_count = 0;
+ int count = 0;
+ GLfloat *stop_colors = NULL;
+ GLfloat *n_stops = NULL;
+ GLfloat xscale, yscale;
+ float vertices[8];
+ float transform_mat[3][3];
+ static const float identity_mat[3][3] = {{1.0, 0.0, 0.0},
+ {0.0, 1.0, 0.0},
+ {0.0, 0.0, 1.0}};
+ GLfloat stop_colors_st[RADIAL_SMALL_STOPS*4];
+ GLfloat n_stops_st[RADIAL_SMALL_STOPS];
+ GLfloat A_value;
+ GLfloat cxy[4];
+ float c1x, c1y, c2x, c2y, r1, r2;
+
+ GLint transform_mat_uniform_location = 0;
+ GLint repeat_type_uniform_location = 0;
+ GLint n_stop_uniform_location = 0;
+ GLint stops_uniform_location = 0;
+ GLint stop_colors_uniform_location = 0;
+ GLint stop0_uniform_location = 0;
+ GLint stop1_uniform_location = 0;
+ GLint stop2_uniform_location = 0;
+ GLint stop3_uniform_location = 0;
+ GLint stop4_uniform_location = 0;
+ GLint stop5_uniform_location = 0;
+ GLint stop6_uniform_location = 0;
+ GLint stop7_uniform_location = 0;
+ GLint stop_color0_uniform_location = 0;
+ GLint stop_color1_uniform_location = 0;
+ GLint stop_color2_uniform_location = 0;
+ GLint stop_color3_uniform_location = 0;
+ GLint stop_color4_uniform_location = 0;
+ GLint stop_color5_uniform_location = 0;
+ GLint stop_color6_uniform_location = 0;
+ GLint stop_color7_uniform_location = 0;
+ GLint A_value_uniform_location = 0;
+ GLint c1_uniform_location = 0;
+ GLint r1_uniform_location = 0;
+ GLint c2_uniform_location = 0;
+ GLint r2_uniform_location = 0;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+ /* Create a pixmap with VBO. */
+ pixmap = glamor_create_pixmap(screen,
+ width, height,
+ PIXMAN_FORMAT_DEPTH(format),
+ 0);
+ if (!pixmap)
+ goto GRADIENT_FAIL;
+
+ dst_picture = CreatePicture(0, &pixmap->drawable,
+ PictureMatchFormat(screen,
+ PIXMAN_FORMAT_DEPTH(format), format),
+ 0, 0, serverClient, &error);
+
+ /* Release the reference, picture will hold the last one. */
+ glamor_destroy_pixmap(pixmap);
+
+ if (!dst_picture)
+ goto GRADIENT_FAIL;
+
+ ValidatePicture(dst_picture);
+
+ stops_count = src_picture->pSourcePict->radial.nstops + 2;
+
+ /* Because the max value of nstops is unkown, so create a program
+ when nstops > LINEAR_LARGE_STOPS.*/
+ if (stops_count <= RADIAL_SMALL_STOPS) {
+ gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][0];
+ } else if (stops_count <= RADIAL_LARGE_STOPS) {
+ gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][1];
+ } else {
+ _glamor_create_radial_gradient_program(screen,
+ src_picture->pSourcePict->linear.nstops + 2,
+ 1);
+ gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_RADIAL][2];
+ }
+
+ /* Bind all the uniform vars .*/
+ transform_mat_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "transform_mat");
+ repeat_type_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "repeat_type");
+ n_stop_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "n_stop");
+ A_value_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "A_value");
+ repeat_type_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "repeat_type");
+ c1_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "c1");
+ r1_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "r1");
+ c2_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "c2");
+ r2_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "r2");
+
+ if (src_picture->pSourcePict->radial.nstops + 2 <= RADIAL_SMALL_STOPS) {
+ stop0_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop0");
+ stop1_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop1");
+ stop2_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop2");
+ stop3_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop3");
+ stop4_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop4");
+ stop5_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop5");
+ stop6_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop6");
+ stop7_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop7");
+
+ stop_color0_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color0");
+ stop_color1_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color1");
+ stop_color2_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color2");
+ stop_color3_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color3");
+ stop_color4_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color4");
+ stop_color5_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color5");
+ stop_color6_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color6");
+ stop_color7_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color7");
+ } else {
+ stops_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stops");
+ stop_colors_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_colors");
+ }
+
+ dispatch->glUseProgram(gradient_prog);
+
+ dispatch->glUniform1i(repeat_type_uniform_location, src_picture->repeatType);
+
+
+ if (src_picture->transform) {
+ _glamor_gradient_convert_trans_matrix(src_picture->transform,
+ transform_mat,
+ width, height, 0);
+ dispatch->glUniformMatrix3fv(transform_mat_uniform_location,
+ 1, 1, &transform_mat[0][0]);
+ } else {
+ dispatch->glUniformMatrix3fv(transform_mat_uniform_location,
+ 1, 1, &identity_mat[0][0]);
+ }
+
+ if (!_glamor_gradient_set_pixmap_destination(screen, glamor_priv, dst_picture,
+ &xscale, &yscale, x_source, y_source,
+ vertices, tex_vertices, 0))
+ goto GRADIENT_FAIL;
+
+ /* Set all the stops and colors to shader. */
+ if (stops_count > RADIAL_SMALL_STOPS) {
+ stop_colors = malloc(4 * stops_count * sizeof(float));
+ if (stop_colors == NULL) {
+ ErrorF("Failed to allocate stop_colors memory.\n");
+ goto GRADIENT_FAIL;
+ }
+
+ n_stops = malloc(stops_count * sizeof(float));
+ if (n_stops == NULL) {
+ ErrorF("Failed to allocate n_stops memory.\n");
+ goto GRADIENT_FAIL;
+ }
+ } else {
+ stop_colors = stop_colors_st;
+ n_stops = n_stops_st;
+ }
+
+ count = _glamor_gradient_set_stops(src_picture, &src_picture->pSourcePict->gradient,
+ stop_colors, n_stops);
+
+ if (src_picture->pSourcePict->linear.nstops + 2 <= RADIAL_SMALL_STOPS) {
+ int j = 0;
+ dispatch->glUniform4f(stop_color0_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color1_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color2_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color3_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color4_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color5_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color6_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color7_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+
+ j = 0;
+ dispatch->glUniform1f(stop0_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop1_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop2_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop3_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop4_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop5_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop6_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop7_uniform_location, n_stops[j++]);
+ dispatch->glUniform1i(n_stop_uniform_location, count);
+ } else {
+ dispatch->glUniform4fv(stop_colors_uniform_location, count, stop_colors);
+ dispatch->glUniform1fv(stops_uniform_location, count, n_stops);
+ dispatch->glUniform1i(n_stop_uniform_location, count);
+ }
+
+ c1x = (float)pixman_fixed_to_double(src_picture->pSourcePict->radial.c1.x);
+ c1y = (float)pixman_fixed_to_double(src_picture->pSourcePict->radial.c1.y);
+ c2x = (float)pixman_fixed_to_double(src_picture->pSourcePict->radial.c2.x);
+ c2y = (float)pixman_fixed_to_double(src_picture->pSourcePict->radial.c2.y);
+
+ r1 = (float)pixman_fixed_to_double(src_picture->pSourcePict->radial.c1.radius);
+ r2 = (float)pixman_fixed_to_double(src_picture->pSourcePict->radial.c2.radius);
+
+ glamor_set_circle_centre(width, height, c1x, c1y, glamor_priv->yInverted, cxy);
+ dispatch->glUniform2fv(c1_uniform_location, 1, cxy);
+ dispatch->glUniform1f(r1_uniform_location, r1);
+
+ glamor_set_circle_centre(width, height, c2x, c2y, glamor_priv->yInverted, cxy);
+ dispatch->glUniform2fv(c2_uniform_location, 1, cxy);
+ dispatch->glUniform1f(r2_uniform_location, r2);
+
+ A_value = (c2x - c1x) * (c2x - c1x) + (c2y - c1y) * (c2y - c1y) - (r2 - r1) * (r2 - r1);
+ dispatch->glUniform1f(A_value_uniform_location, A_value);
+
+ DEBUGF("C1:(%f, %f) R1:%f\nC2:(%f, %f) R2:%f\nA = %f\n",
+ c1x, c1y, r1, c2x, c2y, r2, A_value);
+
+ /* Now rendering. */
+ dispatch->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ /* Do the clear logic.*/
+ if (stops_count > RADIAL_SMALL_STOPS) {
+ free(n_stops);
+ free(stop_colors);
+ }
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glUseProgram(0);
+
+ glamor_put_dispatch(glamor_priv);
+ return dst_picture;
+
+GRADIENT_FAIL:
+ if (dst_picture) {
+ FreePicture(dst_picture, 0);
+ }
+
+ if (stops_count > RADIAL_SMALL_STOPS) {
+ if (n_stops)
+ free(n_stops);
+ if (stop_colors)
+ free(stop_colors);
+ }
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glUseProgram(0);
+ glamor_put_dispatch(glamor_priv);
+ return NULL;
+}
+
+PicturePtr
+glamor_generate_linear_gradient_picture(ScreenPtr screen,
+ PicturePtr src_picture,
+ int x_source, int y_source,
+ int width, int height,
+ PictFormatShort format)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ PicturePtr dst_picture = NULL;
+ PixmapPtr pixmap = NULL;
+ GLint gradient_prog = 0;
+ int error;
+ float pt_distance;
+ float p1_distance;
+ GLfloat cos_val;
+ float tex_vertices[8];
+ int stops_count = 0;
+ GLfloat *stop_colors = NULL;
+ GLfloat *n_stops = NULL;
+ int count = 0;
+ float slope;
+ GLfloat xscale, yscale;
+ GLfloat pt1[2], pt2[2];
+ float vertices[8];
+ float transform_mat[3][3];
+ static const float identity_mat[3][3] = {{1.0, 0.0, 0.0},
+ {0.0, 1.0, 0.0},
+ {0.0, 0.0, 1.0}};
+ GLfloat stop_colors_st[LINEAR_SMALL_STOPS*4];
+ GLfloat n_stops_st[LINEAR_SMALL_STOPS];
+
+ GLint transform_mat_uniform_location = 0;
+ GLint n_stop_uniform_location = 0;
+ GLint stops_uniform_location = 0;
+ GLint stop0_uniform_location = 0;
+ GLint stop1_uniform_location = 0;
+ GLint stop2_uniform_location = 0;
+ GLint stop3_uniform_location = 0;
+ GLint stop4_uniform_location = 0;
+ GLint stop5_uniform_location = 0;
+ GLint stop6_uniform_location = 0;
+ GLint stop7_uniform_location = 0;
+ GLint stop_colors_uniform_location = 0;
+ GLint stop_color0_uniform_location = 0;
+ GLint stop_color1_uniform_location = 0;
+ GLint stop_color2_uniform_location = 0;
+ GLint stop_color3_uniform_location = 0;
+ GLint stop_color4_uniform_location = 0;
+ GLint stop_color5_uniform_location = 0;
+ GLint stop_color6_uniform_location = 0;
+ GLint stop_color7_uniform_location = 0;
+ GLint pt_slope_uniform_location = 0;
+ GLint repeat_type_uniform_location = 0;
+ GLint hor_ver_uniform_location = 0;
+ GLint cos_val_uniform_location = 0;
+ GLint p1_distance_uniform_location = 0;
+ GLint pt_distance_uniform_location = 0;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+ /* Create a pixmap with VBO. */
+ pixmap = glamor_create_pixmap(screen,
+ width, height,
+ PIXMAN_FORMAT_DEPTH(format),
+ 0);
+
+ if (!pixmap)
+ goto GRADIENT_FAIL;
+
+ dst_picture = CreatePicture(0, &pixmap->drawable,
+ PictureMatchFormat(screen,
+ PIXMAN_FORMAT_DEPTH(format), format),
+ 0, 0, serverClient, &error);
+
+ /* Release the reference, picture will hold the last one. */
+ glamor_destroy_pixmap(pixmap);
+
+ if (!dst_picture)
+ goto GRADIENT_FAIL;
+
+ ValidatePicture(dst_picture);
+
+ stops_count = src_picture->pSourcePict->linear.nstops + 2;
+
+ /* Because the max value of nstops is unkown, so create a program
+ when nstops > LINEAR_LARGE_STOPS.*/
+ if (stops_count <= LINEAR_SMALL_STOPS) {
+ gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][0];
+ } else if (stops_count <= LINEAR_LARGE_STOPS) {
+ gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][1];
+ } else {
+ _glamor_create_linear_gradient_program(screen,
+ src_picture->pSourcePict->linear.nstops + 2, 1);
+ gradient_prog = glamor_priv->gradient_prog[SHADER_GRADIENT_LINEAR][2];
+ }
+
+ /* Bind all the uniform vars .*/
+ n_stop_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "n_stop");
+ pt_slope_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "pt_slope");
+ repeat_type_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "repeat_type");
+ hor_ver_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "hor_ver");
+ transform_mat_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "transform_mat");
+ cos_val_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "cos_val");
+ p1_distance_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "p1_distance");
+ pt_distance_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "pt_distance");
+
+ if (src_picture->pSourcePict->linear.nstops + 2 <= LINEAR_SMALL_STOPS) {
+ stop0_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop0");
+ stop1_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop1");
+ stop2_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop2");
+ stop3_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop3");
+ stop4_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop4");
+ stop5_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop5");
+ stop6_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop6");
+ stop7_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop7");
+
+ stop_color0_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color0");
+ stop_color1_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color1");
+ stop_color2_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color2");
+ stop_color3_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color3");
+ stop_color4_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color4");
+ stop_color5_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color5");
+ stop_color6_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color6");
+ stop_color7_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_color7");
+ } else {
+ stops_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stops");
+ stop_colors_uniform_location =
+ dispatch->glGetUniformLocation(gradient_prog, "stop_colors");
+ }
+
+ dispatch->glUseProgram(gradient_prog);
+
+ dispatch->glUniform1i(repeat_type_uniform_location, src_picture->repeatType);
+
+ /* set the transform matrix. */
+ if (src_picture->transform) {
+ _glamor_gradient_convert_trans_matrix(src_picture->transform,
+ transform_mat,
+ width, height, 1);
+ dispatch->glUniformMatrix3fv(transform_mat_uniform_location,
+ 1, 1, &transform_mat[0][0]);
+ } else {
+ dispatch->glUniformMatrix3fv(transform_mat_uniform_location,
+ 1, 1, &identity_mat[0][0]);
+ }
+
+ if (!_glamor_gradient_set_pixmap_destination(screen, glamor_priv, dst_picture,
+ &xscale, &yscale, x_source, y_source,
+ vertices, tex_vertices, 1))
+ goto GRADIENT_FAIL;
+
+ /* Normalize the PTs. */
+ glamor_set_normalize_pt(xscale, yscale,
+ pixman_fixed_to_double(src_picture->pSourcePict->linear.p1.x),
+ pixman_fixed_to_double(src_picture->pSourcePict->linear.p1.y),
+ glamor_priv->yInverted,
+ pt1);
+ DEBUGF("pt1:(%f, %f) ---> (%f %f)\n", pixman_fixed_to_double(src_picture->pSourcePict->linear.p1.x),
+ pixman_fixed_to_double(src_picture->pSourcePict->linear.p1.y), pt1[0], pt1[1]);
+
+ glamor_set_normalize_pt(xscale, yscale,
+ pixman_fixed_to_double(src_picture->pSourcePict->linear.p2.x),
+ pixman_fixed_to_double(src_picture->pSourcePict->linear.p2.y),
+ glamor_priv->yInverted,
+ pt2);
+ DEBUGF("pt2:(%f, %f) ---> (%f %f)\n", pixman_fixed_to_double(src_picture->pSourcePict->linear.p2.x),
+ pixman_fixed_to_double(src_picture->pSourcePict->linear.p2.y), pt2[0], pt2[1]);
+
+ /* Set all the stops and colors to shader. */
+ if (stops_count > LINEAR_SMALL_STOPS) {
+ stop_colors = malloc(4 * stops_count * sizeof(float));
+ if (stop_colors == NULL) {
+ ErrorF("Failed to allocate stop_colors memory.\n");
+ goto GRADIENT_FAIL;
+ }
+
+ n_stops = malloc(stops_count * sizeof(float));
+ if (n_stops == NULL) {
+ ErrorF("Failed to allocate n_stops memory.\n");
+ goto GRADIENT_FAIL;
+ }
+ } else {
+ stop_colors = stop_colors_st;
+ n_stops = n_stops_st;
+ }
+
+ count = _glamor_gradient_set_stops(src_picture, &src_picture->pSourcePict->gradient,
+ stop_colors, n_stops);
+
+ if (src_picture->pSourcePict->linear.nstops + 2 <= LINEAR_SMALL_STOPS) {
+ int j = 0;
+ dispatch->glUniform4f(stop_color0_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color1_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color2_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color3_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color4_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color5_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color6_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+ j++;
+ dispatch->glUniform4f(stop_color7_uniform_location,
+ stop_colors[4*j+0], stop_colors[4*j+1],
+ stop_colors[4*j+2], stop_colors[4*j+3]);
+
+ j = 0;
+ dispatch->glUniform1f(stop0_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop1_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop2_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop3_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop4_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop5_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop6_uniform_location, n_stops[j++]);
+ dispatch->glUniform1f(stop7_uniform_location, n_stops[j++]);
+
+ dispatch->glUniform1i(n_stop_uniform_location, count);
+ } else {
+ dispatch->glUniform4fv(stop_colors_uniform_location, count, stop_colors);
+ dispatch->glUniform1fv(stops_uniform_location, count, n_stops);
+ dispatch->glUniform1i(n_stop_uniform_location, count);
+ }
+
+ if (src_picture->pSourcePict->linear.p2.y ==
+ src_picture->pSourcePict->linear.p1.y) { // The horizontal case.
+ dispatch->glUniform1i(hor_ver_uniform_location, 1);
+ DEBUGF("p1.y: %f, p2.y: %f, enter the horizontal case\n",
+ pt1[1], pt2[1]);
+
+ p1_distance = pt1[0];
+ pt_distance = (pt2[0] - p1_distance);
+ dispatch->glUniform1f(p1_distance_uniform_location, p1_distance);
+ dispatch->glUniform1f(pt_distance_uniform_location, pt_distance);
+ } else {
+ /* The slope need to compute here. In shader, the viewport set will change
+ the orginal slope and the slope which is vertical to it will not be correct.*/
+ slope = - (float)(src_picture->pSourcePict->linear.p2.x
+ - src_picture->pSourcePict->linear.p1.x) /
+ (float)(src_picture->pSourcePict->linear.p2.y
+ - src_picture->pSourcePict->linear.p1.y);
+ slope = slope * yscale / xscale;
+ dispatch->glUniform1f(pt_slope_uniform_location, slope);
+ dispatch->glUniform1i(hor_ver_uniform_location, 0);
+
+ cos_val = sqrt(1.0 / (slope * slope + 1.0));
+ dispatch->glUniform1f(cos_val_uniform_location, cos_val);
+
+ p1_distance = (pt1[1] - pt1[0] * slope) * cos_val;
+ pt_distance = (pt2[1] - pt2[0] * slope) * cos_val - p1_distance;
+ dispatch->glUniform1f(p1_distance_uniform_location, p1_distance);
+ dispatch->glUniform1f(pt_distance_uniform_location, pt_distance);
+ }
+
+ /* Now rendering. */
+ dispatch->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ /* Do the clear logic.*/
+ if (stops_count > LINEAR_SMALL_STOPS) {
+ free(n_stops);
+ free(stop_colors);
+ }
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glUseProgram(0);
+
+ glamor_put_dispatch(glamor_priv);
+ return dst_picture;
+
+GRADIENT_FAIL:
+ if (dst_picture) {
+ FreePicture(dst_picture, 0);
+ }
+
+ if (stops_count > LINEAR_SMALL_STOPS) {
+ if (n_stops)
+ free(n_stops);
+ if (stop_colors)
+ free(stop_colors);
+ }
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glUseProgram(0);
+ glamor_put_dispatch(glamor_priv);
+ return NULL;
+}
+
+#endif /* End of GLAMOR_GRADIENT_SHADER */
+
+#endif /* End of RENDER */
diff --git a/glamor/glamor_largepixmap.c b/glamor/glamor_largepixmap.c
new file mode 100644
index 000000000..91ee8f2df
--- /dev/null
+++ b/glamor/glamor_largepixmap.c
@@ -0,0 +1,1324 @@
+#include <stdlib.h>
+
+#include "glamor_priv.h"
+
+/**
+ * Clip the boxes regards to each pixmap's block array.
+ *
+ * Should translate the region to relative coords to the pixmap,
+ * start at (0,0).
+ */
+#if 0
+//#define DEBUGF(str, ...) do {} while(0)
+#define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__)
+//#define DEBUGRegionPrint(x) do {} while (0)
+#define DEBUGRegionPrint RegionPrint
+#endif
+
+static glamor_pixmap_clipped_regions *
+__glamor_compute_clipped_regions(int block_w,
+ int block_h,
+ int block_stride,
+ int x, int y,
+ int w, int h,
+ RegionPtr region,
+ int *n_region,
+ int reverse,
+ int upsidedown)
+{
+ glamor_pixmap_clipped_regions * clipped_regions;
+ BoxPtr extent;
+ int start_x, start_y, end_x, end_y;
+ int start_block_x, start_block_y;
+ int end_block_x, end_block_y;
+ int loop_start_block_x, loop_start_block_y;
+ int loop_end_block_x, loop_end_block_y;
+ int loop_block_stride;
+ int i, j, delta_i, delta_j;
+ RegionRec temp_region;
+ RegionPtr current_region;
+ int block_idx;
+ int k = 0;
+ int temp_block_idx;
+
+ extent = RegionExtents(region);
+ start_x = MAX(x, extent->x1);
+ start_y = MAX(y, extent->y1);
+ end_x = MIN(x + w, extent->x2);
+ end_y = MIN(y + h, extent->y2);
+
+ DEBUGF("start compute clipped regions:\n");
+ DEBUGF("block w %d h %d x %d y %d w %d h %d, block_stride %d \n",
+ block_w, block_h, x, y, w, h, block_stride);
+ DEBUGRegionPrint(region);
+
+ DEBUGF("start_x %d start_y %d end_x %d end_y %d \n", start_x, start_y, end_x, end_y);
+
+ if (start_x >= end_x || start_y >= end_y) {
+ *n_region = 0;
+ return NULL;
+ }
+
+ start_block_x = (start_x - x)/ block_w;
+ start_block_y = (start_y - y)/ block_h;
+ end_block_x = (end_x - x)/ block_w;
+ end_block_y = (end_y - y)/ block_h;
+
+ clipped_regions = calloc((end_block_x - start_block_x + 1)
+ * (end_block_y - start_block_y + 1),
+ sizeof(*clipped_regions));
+
+
+ DEBUGF("startx %d starty %d endx %d endy %d \n",
+ start_x, start_y, end_x, end_y);
+ DEBUGF("start_block_x %d end_block_x %d \n", start_block_x, end_block_x);
+ DEBUGF("start_block_y %d end_block_y %d \n", start_block_y, end_block_y);
+
+ if (!reverse) {
+ loop_start_block_x = start_block_x;
+ loop_end_block_x = end_block_x + 1;
+ delta_i = 1;
+ } else {
+ loop_start_block_x = end_block_x;
+ loop_end_block_x = start_block_x - 1;
+ delta_i = -1;
+ }
+
+ if (!upsidedown) {
+ loop_start_block_y = start_block_y;
+ loop_end_block_y = end_block_y + 1;
+ delta_j = 1;
+ } else {
+ loop_start_block_y = end_block_y;
+ loop_end_block_y = start_block_y - 1;
+ delta_j = -1;
+ }
+
+ loop_block_stride = delta_j * block_stride;
+ block_idx = (loop_start_block_y - delta_j) * block_stride;
+
+ for(j = loop_start_block_y; j != loop_end_block_y; j += delta_j)
+ {
+ block_idx += loop_block_stride;
+ temp_block_idx = block_idx + loop_start_block_x;
+ for(i = loop_start_block_x;
+ i != loop_end_block_x; i += delta_i, temp_block_idx += delta_i)
+ {
+ BoxRec temp_box;
+ temp_box.x1 = x + i * block_w;
+ temp_box.y1 = y + j * block_h;
+ temp_box.x2 = MIN(temp_box.x1 + block_w, end_x);
+ temp_box.y2 = MIN(temp_box.y1 + block_h, end_y);
+ RegionInitBoxes(&temp_region, &temp_box, 1);
+ DEBUGF("block idx %d \n",temp_block_idx);
+ DEBUGRegionPrint(&temp_region);
+ current_region = RegionCreate(NULL, 4);
+ RegionIntersect(current_region, &temp_region, region);
+ DEBUGF("i %d j %d region: \n",i ,j);
+ DEBUGRegionPrint(current_region);
+ if (RegionNumRects(current_region)) {
+ clipped_regions[k].region = current_region;
+ clipped_regions[k].block_idx = temp_block_idx;
+ k++;
+ } else
+ RegionDestroy(current_region);
+ RegionUninit(&temp_region);
+ }
+ }
+
+ *n_region = k;
+ return clipped_regions;
+}
+
+/**
+ * Do a two round clipping,
+ * first is to clip the region regard to current pixmap's
+ * block array. Then for each clipped region, do a inner
+ * block clipping. This is to make sure the final result
+ * will be shapped by inner_block_w and inner_block_h, and
+ * the final region also will not cross the pixmap's block
+ * boundary.
+ *
+ * This is mainly used by transformation support when do
+ * compositing.
+ */
+
+glamor_pixmap_clipped_regions *
+glamor_compute_clipped_regions_ext(glamor_pixmap_private *pixmap_priv,
+ RegionPtr region,
+ int *n_region,
+ int inner_block_w, int inner_block_h,
+ int reverse, int upsidedown)
+{
+ glamor_pixmap_clipped_regions * clipped_regions, *inner_regions, *result_regions;
+ int i, j, x, y, k, inner_n_regions;
+ int width, height;
+ glamor_pixmap_private_large_t *priv;
+ priv = &pixmap_priv->large;
+
+ DEBUGF("ext called \n");
+
+ if (pixmap_priv->type != GLAMOR_TEXTURE_LARGE) {
+ clipped_regions = calloc(1, sizeof(*clipped_regions));
+ if (clipped_regions == NULL) {
+ *n_region = 0;
+ return NULL;
+ }
+ clipped_regions[0].region = RegionCreate(NULL, 1);
+ clipped_regions[0].block_idx = 0;
+ RegionCopy(clipped_regions[0].region, region);
+ *n_region = 1;
+ priv->block_w = priv->base.pixmap->drawable.width;
+ priv->block_h = priv->base.pixmap->drawable.height;
+ priv->box_array = &priv->box;
+ priv->box.x1 = priv->box.y1 = 0;
+ priv->box.x2 = priv->block_w;
+ priv->box.y2 = priv->block_h;
+ } else {
+ clipped_regions = __glamor_compute_clipped_regions(priv->block_w,
+ priv->block_h,
+ priv->block_wcnt,
+ 0, 0,
+ priv->base.pixmap->drawable.width,
+ priv->base.pixmap->drawable.height,
+ region, n_region, reverse, upsidedown
+ );
+
+ if (clipped_regions == NULL) {
+ *n_region = 0;
+ return NULL;
+ }
+ }
+ if (inner_block_w >= priv->block_w
+ && inner_block_h >= priv->block_h)
+ return clipped_regions;
+ result_regions = calloc(*n_region
+ * ((priv->block_w + inner_block_w - 1)/inner_block_w)
+ * ((priv->block_h + inner_block_h - 1)/ inner_block_h),
+ sizeof(*result_regions));
+ k = 0;
+ for(i = 0; i < *n_region; i++)
+ {
+ x = priv->box_array[clipped_regions[i].block_idx].x1;
+ y = priv->box_array[clipped_regions[i].block_idx].y1;
+ width = priv->box_array[clipped_regions[i].block_idx].x2 - x;
+ height = priv->box_array[clipped_regions[i].block_idx].y2 - y;
+ inner_regions = __glamor_compute_clipped_regions(inner_block_w,
+ inner_block_h,
+ 0, x, y,
+ width,
+ height,
+ clipped_regions[i].region,
+ &inner_n_regions, reverse, upsidedown);
+ for(j = 0; j < inner_n_regions; j++)
+ {
+ result_regions[k].region = inner_regions[j].region;
+ result_regions[k].block_idx = clipped_regions[i].block_idx;
+ k++;
+ }
+ free(inner_regions);
+ }
+ *n_region = k;
+ free(clipped_regions);
+ return result_regions;
+}
+
+/*
+ *
+ * For the repeat pad mode, we can simply convert the region and
+ * let the out-of-box region can cover the needed edge of the source/mask
+ * Then apply a normal clip we can get what we want.
+ */
+static RegionPtr
+_glamor_convert_pad_region(RegionPtr region, int w, int h)
+{
+ RegionPtr pad_region;
+ int nrect;
+ BoxPtr box;
+ int overlap;
+
+ nrect = RegionNumRects(region);
+ box = RegionRects(region);
+ pad_region = RegionCreate(NULL, 4);
+ if (pad_region == NULL)
+ return NULL;
+ while(nrect--) {
+ BoxRec pad_box;
+ RegionRec temp_region;
+ pad_box = *box;
+ if (pad_box.x1 < 0 && pad_box.x2 <= 0)
+ pad_box.x2 = 1;
+ else if (pad_box.x1 >= w && pad_box.x2 > w)
+ pad_box.x1 = w - 1;
+ if (pad_box.y1 < 0 && pad_box.y2 <=0)
+ pad_box.y2 = 1;
+ else if (pad_box.y1 >= h && pad_box.y2 > h)
+ pad_box.y1 = h - 1;
+ RegionInitBoxes(&temp_region, &pad_box, 1);
+ RegionAppend(pad_region, &temp_region);
+ RegionUninit(&temp_region);
+ box++;
+ }
+ RegionValidate(pad_region, &overlap);
+ return pad_region;
+}
+
+/*
+ * For one type of large pixmap, its one direction is not exceed the
+ * size limitation, and in another word, on one direction it has only
+ * one block.
+ *
+ * This case of reflect repeating, we can optimize it and avoid repeat
+ * clip on that direction. We can just enlarge the repeat box and can
+ * cover all the dest region on that direction. But latter, we need to
+ * fixup the clipped result to get a correct coords for the subsequent
+ * processing. This function is to do the coords correction.
+ *
+ * */
+static void
+_glamor_largepixmap_reflect_fixup(short *xy1, short *xy2, int wh)
+{
+ int odd1, odd2;
+ int c1, c2;
+
+ if (*xy2 - *xy1 > wh) {
+ *xy1 = 0;
+ *xy2 = wh;
+ return;
+ }
+ modulus(*xy1, wh, c1);
+ odd1 = ((*xy1 - c1) / wh) & 0x1;
+ modulus(*xy2, wh, c2);
+ odd2 = ((*xy2 - c2) / wh) & 0x1;
+
+ if (odd1 && odd2) {
+ *xy1 = wh - c2;
+ *xy2 = wh - c1;
+ } else if (odd1 && !odd2) {
+ *xy1 = 0;
+ *xy2 = MAX(c2, wh - c1);
+ } else if (!odd1 && odd2) {
+ *xy2 = wh;
+ *xy1 = MIN(c1, wh - c2);
+ } else {
+ *xy1 = c1;
+ *xy2 = c2;
+ }
+}
+
+/**
+ * Clip the boxes regards to each pixmap's block array.
+ *
+ * Should translate the region to relative coords to the pixmap,
+ * start at (0,0).
+ *
+ * @is_transform: if it is set, it has a transform matrix.
+ *
+ */
+static glamor_pixmap_clipped_regions *
+_glamor_compute_clipped_regions(glamor_pixmap_private *pixmap_priv,
+ RegionPtr region, int *n_region,
+ int repeat_type, int is_transform,
+ int reverse, int upsidedown)
+{
+ glamor_pixmap_clipped_regions * clipped_regions;
+ BoxPtr extent;
+ int i, j;
+ RegionPtr current_region;
+ int pixmap_width, pixmap_height;
+ int m;
+ BoxRec repeat_box;
+ RegionRec repeat_region;
+ int right_shift = 0;
+ int down_shift = 0;
+ int x_center_shift = 0, y_center_shift = 0;
+ glamor_pixmap_private_large_t *priv;
+ priv = &pixmap_priv->large;
+
+ DEBUGRegionPrint(region);
+ if (pixmap_priv->type != GLAMOR_TEXTURE_LARGE) {
+ clipped_regions = calloc(1, sizeof(*clipped_regions));
+ clipped_regions[0].region = RegionCreate(NULL, 1);
+ clipped_regions[0].block_idx = 0;
+ RegionCopy(clipped_regions[0].region, region);
+ *n_region = 1;
+ return clipped_regions;
+ }
+
+ pixmap_width = priv->base.pixmap->drawable.width;
+ pixmap_height = priv->base.pixmap->drawable.height;
+ if (repeat_type == 0 || repeat_type == RepeatPad) {
+ RegionPtr saved_region = NULL;
+ if (repeat_type == RepeatPad) {
+ saved_region = region;
+ region = _glamor_convert_pad_region(saved_region, pixmap_width, pixmap_height);
+ if (region == NULL) {
+ *n_region = 0;
+ return NULL;
+ }
+ }
+ clipped_regions = __glamor_compute_clipped_regions(priv->block_w,
+ priv->block_h,
+ priv->block_wcnt,
+ 0, 0,
+ priv->base.pixmap->drawable.width,
+ priv->base.pixmap->drawable.height,
+ region, n_region, reverse, upsidedown
+ );
+ if (saved_region)
+ RegionDestroy(region);
+ return clipped_regions;
+ }
+ extent = RegionExtents(region);
+
+ x_center_shift = extent->x1 / pixmap_width;
+ if (x_center_shift < 0)
+ x_center_shift--;
+ if (abs(x_center_shift) & 1)
+ x_center_shift++;
+ y_center_shift = extent->y1 / pixmap_height;
+ if (y_center_shift < 0)
+ y_center_shift--;
+ if (abs(y_center_shift) & 1)
+ y_center_shift++;
+
+ if (extent->x1 < 0)
+ right_shift = ((-extent->x1 + pixmap_width - 1) / pixmap_width );
+ if (extent->y1 < 0)
+ down_shift = ((-extent->y1 + pixmap_height - 1) / pixmap_height );
+
+ if (right_shift != 0 || down_shift != 0) {
+ if (repeat_type == RepeatReflect) {
+ right_shift = (right_shift + 1)&~1;
+ down_shift = (down_shift + 1)&~1;
+ }
+ RegionTranslate(region, right_shift * pixmap_width, down_shift * pixmap_height);
+ }
+
+ extent = RegionExtents(region);
+ /* Tile a large pixmap to another large pixmap.
+ * We can't use the target large pixmap as the
+ * loop variable, instead we need to loop for all
+ * the blocks in the tile pixmap.
+ *
+ * simulate repeat each single block to cover the
+ * target's blocks. Two special case:
+ * a block_wcnt == 1 or block_hcnt ==1, then we
+ * only need to loop one direction as the other
+ * direction is fully included in the first block.
+ *
+ * For the other cases, just need to start
+ * from a proper shiftx/shifty, and then increase
+ * y by tile_height each time to walk trhough the
+ * target block and then walk trhough the target
+ * at x direction by increate tile_width each time.
+ *
+ * This way, we can consolidate all the sub blocks
+ * of the target boxes into one tile source's block.
+ *
+ * */
+ m = 0;
+ clipped_regions = calloc(priv->block_wcnt * priv->block_hcnt,
+ sizeof(*clipped_regions));
+ if (clipped_regions == NULL) {
+ *n_region = 0;
+ return NULL;
+ }
+ if (right_shift != 0 || down_shift != 0) {
+ DEBUGF("region to be repeated shifted \n");
+ DEBUGRegionPrint(region);
+ }
+ DEBUGF("repeat pixmap width %d height %d \n", pixmap_width, pixmap_height);
+ DEBUGF("extent x1 %d y1 %d x2 %d y2 %d \n", extent->x1, extent->y1, extent->x2, extent->y2);
+ for(j = 0; j < priv->block_hcnt; j++)
+ {
+ for(i = 0; i < priv->block_wcnt; i++)
+ {
+ int dx = pixmap_width;
+ int dy = pixmap_height;
+ int idx;
+ int shift_x;
+ int shift_y;
+ int saved_y1, saved_y2;
+ int x_idx = 0, y_idx = 0, saved_y_idx = 0;
+ RegionRec temp_region;
+ BoxRec reflect_repeat_box;
+ BoxPtr valid_repeat_box;
+
+ shift_x = (extent->x1 / pixmap_width) * pixmap_width;
+ shift_y = (extent->y1 / pixmap_height) * pixmap_height;
+ idx = j * priv->block_wcnt + i;
+ if (repeat_type == RepeatReflect) {
+ x_idx = (extent->x1 / pixmap_width);
+ y_idx = (extent->y1 / pixmap_height);
+ }
+
+ /* Construct a rect to clip the target region. */
+ repeat_box.x1 = shift_x + priv->box_array[idx].x1;
+ repeat_box.y1 = shift_y + priv->box_array[idx].y1;
+ if (priv->block_wcnt == 1) {
+ repeat_box.x2 = extent->x2;
+ dx = extent->x2 - repeat_box.x1;
+ } else
+ repeat_box.x2 = shift_x + priv->box_array[idx].x2;
+ if (priv->block_hcnt == 1) {
+ repeat_box.y2 = extent->y2;
+ dy = extent->y2 - repeat_box.y1;
+ } else
+ repeat_box.y2 = shift_y + priv->box_array[idx].y2;
+
+ current_region = RegionCreate(NULL, 4);
+ RegionInit(&temp_region, NULL, 4);
+ DEBUGF("init repeat box %d %d %d %d \n",
+ repeat_box.x1, repeat_box.y1, repeat_box.x2, repeat_box.y2);
+
+ if (repeat_type == RepeatNormal) {
+ saved_y1 = repeat_box.y1;
+ saved_y2 = repeat_box.y2;
+ for(; repeat_box.x1 < extent->x2;
+ repeat_box.x1 += dx, repeat_box.x2 += dx)
+ {
+ repeat_box.y1 = saved_y1;
+ repeat_box.y2 = saved_y2;
+ for( repeat_box.y1 = saved_y1, repeat_box.y2 = saved_y2;
+ repeat_box.y1 < extent->y2;
+ repeat_box.y1 += dy, repeat_box.y2 += dy)
+ {
+
+ RegionInitBoxes(&repeat_region, &repeat_box, 1);
+ DEBUGF("Start to clip repeat region: \n");
+ DEBUGRegionPrint(&repeat_region);
+ RegionIntersect(&temp_region, &repeat_region, region);
+ DEBUGF("clip result:\n");
+ DEBUGRegionPrint(&temp_region);
+ RegionAppend(current_region, &temp_region);
+ RegionUninit(&repeat_region);
+ }
+ }
+ } else if (repeat_type == RepeatReflect) {
+ saved_y1 = repeat_box.y1;
+ saved_y2 = repeat_box.y2;
+ saved_y_idx = y_idx;
+ for(; ; repeat_box.x1 += dx, repeat_box.x2 += dx)
+ {
+ repeat_box.y1 = saved_y1;
+ repeat_box.y2 = saved_y2;
+ y_idx = saved_y_idx;
+ reflect_repeat_box.x1 = (x_idx & 1) ?
+ ((2 * x_idx + 1) * dx - repeat_box.x2) : repeat_box.x1;
+ reflect_repeat_box.x2 = (x_idx & 1) ?
+ ((2 * x_idx + 1) * dx - repeat_box.x1) : repeat_box.x2;
+ valid_repeat_box = &reflect_repeat_box;
+
+ if (valid_repeat_box->x1 >= extent->x2)
+ break;
+ for( repeat_box.y1 = saved_y1, repeat_box.y2 = saved_y2;
+ ;
+ repeat_box.y1 += dy, repeat_box.y2 += dy)
+ {
+
+ DEBUGF("x_idx %d y_idx %d dx %d dy %d\n", x_idx, y_idx, dx, dy);
+ DEBUGF("repeat box %d %d %d %d \n",
+ repeat_box.x1, repeat_box.y1, repeat_box.x2, repeat_box.y2);
+
+ if (priv->block_hcnt > 1) {
+ reflect_repeat_box.y1 = (y_idx & 1) ?
+ ((2 * y_idx + 1) * dy - repeat_box.y2) : repeat_box.y1;
+ reflect_repeat_box.y2 = (y_idx & 1) ?
+ ((2 * y_idx + 1) * dy - repeat_box.y1) : repeat_box.y2;
+ } else {
+ reflect_repeat_box.y1 = repeat_box.y1;
+ reflect_repeat_box.y2 = repeat_box.y2;
+ }
+
+ DEBUGF("valid_repeat_box x1 %d y1 %d \n",
+ valid_repeat_box->x1, valid_repeat_box->y1);
+ if (valid_repeat_box->y1 >= extent->y2)
+ break;
+ RegionInitBoxes(&repeat_region, valid_repeat_box, 1);
+ DEBUGF("start to clip repeat[reflect] region: \n");
+ DEBUGRegionPrint(&repeat_region);
+ RegionIntersect(&temp_region, &repeat_region, region);
+ DEBUGF("result:\n");
+ DEBUGRegionPrint(&temp_region);
+ if (is_transform && RegionNumRects(&temp_region)) {
+ BoxRec temp_box;
+ BoxPtr temp_extent;
+ temp_extent = RegionExtents(&temp_region);
+ if (priv->block_wcnt > 1) {
+ if (x_idx & 1) {
+ temp_box.x1 = ((2 * x_idx + 1)*dx - temp_extent->x2);
+ temp_box.x2 = ((2 * x_idx + 1)*dx - temp_extent->x1);
+ } else {
+ temp_box.x1 = temp_extent->x1;
+ temp_box.x2 = temp_extent->x2;
+ }
+ modulus(temp_box.x1, pixmap_width, temp_box.x1);
+ modulus(temp_box.x2, pixmap_width, temp_box.x2);
+ if (temp_box.x2 == 0) temp_box.x2 = pixmap_width;
+ } else {
+ temp_box.x1 = temp_extent->x1;
+ temp_box.x2 = temp_extent->x2;
+ _glamor_largepixmap_reflect_fixup(&temp_box.x1, &temp_box.x2, pixmap_width);
+ }
+
+ if (priv->block_hcnt > 1) {
+ if (y_idx & 1) {
+ temp_box.y1 = ((2 * y_idx + 1)*dy - temp_extent->y2);
+ temp_box.y2 = ((2 * y_idx + 1)*dy - temp_extent->y1);
+ } else {
+ temp_box.y1 = temp_extent->y1;
+ temp_box.y2 = temp_extent->y2;
+ }
+
+ modulus(temp_box.y1, pixmap_height, temp_box.y1);
+ modulus(temp_box.y2, pixmap_height, temp_box.y2);
+ if (temp_box.y2 == 0) temp_box.y2 = pixmap_height;
+ } else {
+ temp_box.y1 = temp_extent->y1;
+ temp_box.y2 = temp_extent->y2;
+ _glamor_largepixmap_reflect_fixup(&temp_box.y1, &temp_box.y2, pixmap_height);
+ }
+
+ RegionInitBoxes(&temp_region, &temp_box, 1);
+ RegionTranslate(&temp_region, x_center_shift * pixmap_width, y_center_shift * pixmap_height);
+ DEBUGF("for transform result:\n");
+ DEBUGRegionPrint(&temp_region);
+ }
+ RegionAppend(current_region, &temp_region);
+ RegionUninit(&repeat_region);
+ y_idx++;
+ }
+ x_idx++;
+ }
+ }
+ DEBUGF("dx %d dy %d \n", dx, dy);
+
+ if (RegionNumRects(current_region)) {
+
+ if ((right_shift != 0 || down_shift != 0) && !(is_transform && repeat_type == RepeatReflect))
+ RegionTranslate(current_region,
+ -right_shift * pixmap_width,
+ -down_shift * pixmap_height);
+ clipped_regions[m].region = current_region;
+ clipped_regions[m].block_idx = idx;
+ m++;
+ } else
+ RegionDestroy(current_region);
+ RegionUninit(&temp_region);
+ }
+ }
+
+ if (right_shift != 0 || down_shift != 0)
+ RegionTranslate(region, -right_shift * pixmap_width, -down_shift * pixmap_height);
+ *n_region = m;
+
+ return clipped_regions;
+}
+
+glamor_pixmap_clipped_regions *
+glamor_compute_clipped_regions(glamor_pixmap_private *priv, RegionPtr region,
+ int *n_region, int repeat_type,
+ int reverse, int upsidedown)
+{
+ return _glamor_compute_clipped_regions(priv, region, n_region, repeat_type, 0, reverse, upsidedown);
+}
+
+/* XXX overflow still exist. maybe we need to change to use region32.
+ * by default. Or just use region32 for repeat cases?
+ **/
+glamor_pixmap_clipped_regions *
+glamor_compute_transform_clipped_regions(glamor_pixmap_private *priv, struct pixman_transform *transform,
+ RegionPtr region, int *n_region, int dx, int dy, int repeat_type,
+ int reverse, int upsidedown)
+{
+ BoxPtr temp_extent;
+ struct pixman_box32 temp_box;
+ struct pixman_box16 short_box;
+ RegionPtr temp_region;
+ glamor_pixmap_clipped_regions *ret;
+
+ temp_region = RegionCreate(NULL, 4);
+ temp_extent = RegionExtents(region);
+ DEBUGF("dest region \n");
+ DEBUGRegionPrint(region);
+ /* dx/dy may exceed MAX SHORT. we have to use
+ * a box32 to represent it.*/
+ temp_box.x1 = temp_extent->x1 + dx;
+ temp_box.x2 = temp_extent->x2 + dx;
+ temp_box.y1 = temp_extent->y1 + dy;
+ temp_box.y2 = temp_extent->y2 + dy;
+
+ DEBUGF("source box %d %d %d %d \n", temp_box.x1, temp_box.y1, temp_box.x2, temp_box.y2);
+ if (transform)
+ glamor_get_transform_extent_from_box(&temp_box, transform);
+ if (repeat_type == RepeatNone) {
+ if (temp_box.x1 < 0) temp_box.x1 = 0;
+ if (temp_box.y1 < 0) temp_box.y1 = 0;
+ temp_box.x2 = MIN(temp_box.x2, priv->base.pixmap->drawable.width);
+ temp_box.y2 = MIN(temp_box.y2, priv->base.pixmap->drawable.height);
+ }
+ /* Now copy back the box32 to a box16 box. */
+ short_box.x1 = temp_box.x1;
+ short_box.y1 = temp_box.y1;
+ short_box.x2 = temp_box.x2;
+ short_box.y2 = temp_box.y2;
+ RegionInitBoxes(temp_region, &short_box, 1);
+ DEBUGF("copy to temp source region \n");
+ DEBUGRegionPrint(temp_region);
+ ret = _glamor_compute_clipped_regions(priv,
+ temp_region,
+ n_region,
+ repeat_type,
+ 1, reverse,
+ upsidedown);
+ DEBUGF("n_regions = %d \n", *n_region);
+ RegionDestroy(temp_region);
+
+ return ret;
+}
+/*
+ * As transform and repeatpad mode.
+ * We may get a clipped result which in multipe regions.
+ * It's not easy to do a 2nd round clipping just as we do
+ * without transform/repeatPad. As it's not easy to reverse
+ * the 2nd round clipping result with a transform/repeatPad mode,
+ * or even impossible for some transformation.
+ *
+ * So we have to merge the fragmental region into one region
+ * if the clipped result cross the region boundary.
+ */
+static void
+glamor_merge_clipped_regions(glamor_pixmap_private *pixmap_priv, int repeat_type,
+ glamor_pixmap_clipped_regions *clipped_regions,
+ int *n_regions, int *need_clean_fbo)
+{
+ BoxPtr temp_extent;
+ BoxRec temp_box, copy_box;
+ RegionPtr temp_region;
+ glamor_pixmap_private *temp_priv;
+ PixmapPtr temp_pixmap;
+ int overlap;
+ int i;
+ int pixmap_width, pixmap_height;
+ glamor_pixmap_private_large_t *priv;
+
+ priv = &pixmap_priv->large;
+ pixmap_width = priv->base.pixmap->drawable.width;
+ pixmap_height = priv->base.pixmap->drawable.height;
+
+ temp_region = RegionCreate(NULL, 4);
+ for(i = 0; i < *n_regions; i++)
+ {
+ DEBUGF("Region %d:\n", i);
+ DEBUGRegionPrint(clipped_regions[i].region);
+ RegionAppend(temp_region, clipped_regions[i].region);
+ }
+
+ RegionValidate(temp_region, &overlap);
+ DEBUGF("temp region: \n");
+ DEBUGRegionPrint(temp_region);
+ temp_extent = RegionExtents(temp_region);
+
+ temp_box = *temp_extent;
+
+ DEBUGF("need copy region: \n");
+ DEBUGF("%d %d %d %d \n", temp_box.x1, temp_box.y1, temp_box.x2, temp_box.y2);
+ temp_pixmap = glamor_create_pixmap(priv->base.pixmap->drawable.pScreen,
+ temp_box.x2 - temp_box.x1,
+ temp_box.y2 - temp_box.y1,
+ priv->base.pixmap->drawable.depth,
+ GLAMOR_CREATE_PIXMAP_FIXUP);
+ if (temp_pixmap == NULL) {
+ assert(0);
+ return;
+ }
+
+ temp_priv = glamor_get_pixmap_private(temp_pixmap);
+ assert(temp_priv->type != GLAMOR_TEXTURE_LARGE);
+
+ priv->box = temp_box;
+ if (temp_extent->x1 >= 0 && temp_extent->x2 <= pixmap_width
+ && temp_extent->y1 >= 0 && temp_extent->y2 <= pixmap_height) {
+ int dx, dy;
+ copy_box.x1 = 0;
+ copy_box.y1 = 0;
+ copy_box.x2 = temp_extent->x2 - temp_extent->x1;
+ copy_box.y2 = temp_extent->y2 - temp_extent->y1;
+ dx = temp_extent->x1;
+ dy = temp_extent->y1;
+ glamor_copy_n_to_n(&priv->base.pixmap->drawable,
+ &temp_pixmap->drawable,
+ NULL, &copy_box, 1, dx,
+ dy, 0, 0, 0, NULL);
+// glamor_solid(temp_pixmap, 0, 0, temp_pixmap->drawable.width,
+// temp_pixmap->drawable.height, GXcopy, 0xffffffff, 0xff00);
+ } else {
+ for (i = 0; i < *n_regions; i++)
+ {
+ BoxPtr box;
+ int nbox;
+ box = REGION_RECTS(clipped_regions[i].region);
+ nbox = REGION_NUM_RECTS(clipped_regions[i].region);
+ while(nbox--) {
+ int dx, dy, c, d;
+ DEBUGF("box x1 %d y1 %d x2 %d y2 %d \n",
+ box->x1, box->y1, box->x2, box->y2);
+ modulus(box->x1, pixmap_width, c);
+ dx = c - (box->x1 - temp_box.x1);
+ copy_box.x1 = box->x1 - temp_box.x1;
+ copy_box.x2 = box->x2 - temp_box.x1;
+
+ modulus(box->y1, pixmap_height, d);
+ dy = d - (box->y1 - temp_box.y1);
+ copy_box.y1 = box->y1 - temp_box.y1;
+ copy_box.y2 = box->y2 - temp_box.y1;
+
+ DEBUGF("copying box %d %d %d %d, dx %d dy %d\n",
+ copy_box.x1, copy_box.y1, copy_box.x2,
+ copy_box.y2, dx, dy);
+
+ glamor_copy_n_to_n(&priv->base.pixmap->drawable,
+ &temp_pixmap->drawable,
+ NULL, &copy_box, 1, dx,
+ dy, 0, 0, 0, NULL);
+ box++;
+ }
+ }
+ //glamor_solid(temp_pixmap, 0, 0, temp_pixmap->drawable.width,
+ // temp_pixmap->drawable.height, GXcopy, 0xffffffff, 0xff);
+ }
+ /* The first region will be released at caller side. */
+ for(i = 1; i < *n_regions; i++)
+ RegionDestroy(clipped_regions[i].region);
+ RegionDestroy(temp_region);
+ priv->box = temp_box;
+ priv->base.fbo = glamor_pixmap_detach_fbo(temp_priv);
+ DEBUGF("priv box x1 %d y1 %d x2 %d y2 %d \n",
+ priv->box.x1, priv->box.y1, priv->box.x2, priv->box.y2);
+ glamor_destroy_pixmap(temp_pixmap);
+ *need_clean_fbo = 1;
+ *n_regions = 1;
+}
+
+
+
+/**
+ * Given an expected transformed block width and block height,
+ *
+ * This function calculate a new block width and height which
+ * guarantee the transform result will not exceed the given
+ * block width and height.
+ *
+ * For large block width and height (> 2048), we choose a
+ * smaller new width and height and to reduce the cross region
+ * boundary and can avoid some overhead.
+ *
+ **/
+Bool
+glamor_get_transform_block_size(struct pixman_transform *transform,
+ int block_w, int block_h,
+ int *transformed_block_w,
+ int *transformed_block_h)
+{
+ double a,b,c,d,e,f,g,h;
+ double scale;
+ int width, height;
+ a = pixman_fixed_to_double(transform->matrix[0][0]);
+ b = pixman_fixed_to_double(transform->matrix[0][1]);
+ c = pixman_fixed_to_double(transform->matrix[1][0]);
+ d = pixman_fixed_to_double(transform->matrix[1][1]);
+ scale = pixman_fixed_to_double(transform->matrix[2][2]);
+ if (block_w > 2048) {
+ /* For large block size, we shrink it to smaller box,
+ * thus latter we may get less cross boundary regions and
+ * thus can avoid some extra copy.
+ *
+ **/
+ width = block_w / 4;
+ height = block_h / 4;
+ } else {
+ width = block_w - 2;
+ height = block_h - 2;
+ }
+ e = a + b;
+ f = c + d;
+
+ g = a - b;
+ h = c - d;
+
+ e = MIN(block_w, floor(width * scale) / MAX(fabs(e), fabs(g)));
+ f = MIN(block_h, floor(height * scale) / MAX(fabs(f), fabs(h)));
+ *transformed_block_w = MIN(e, f) - 1;
+ *transformed_block_h = *transformed_block_w;
+ if (*transformed_block_w <= 0 || *transformed_block_h <= 0)
+ return FALSE;
+ DEBUGF("original block_w/h %d %d, fixed %d %d \n", block_w, block_h,
+ *transformed_block_w, *transformed_block_h);
+ return TRUE;
+}
+
+#define VECTOR_FROM_POINT(p, x, y) \
+ p.v[0] = x; \
+ p.v[1] = y; \
+ p.v[2] = 1.0;
+void
+glamor_get_transform_extent_from_box(struct pixman_box32 *box,
+ struct pixman_transform *transform)
+{
+ struct pixman_f_vector p0, p1, p2, p3;
+ float min_x, min_y, max_x, max_y;
+
+ struct pixman_f_transform ftransform;
+
+ VECTOR_FROM_POINT(p0, box->x1, box->y1)
+ VECTOR_FROM_POINT(p1, box->x2, box->y1)
+ VECTOR_FROM_POINT(p2, box->x2, box->y2)
+ VECTOR_FROM_POINT(p3, box->x1, box->y2)
+
+ pixman_f_transform_from_pixman_transform(&ftransform, transform);
+ pixman_f_transform_point(&ftransform, &p0);
+ pixman_f_transform_point(&ftransform, &p1);
+ pixman_f_transform_point(&ftransform, &p2);
+ pixman_f_transform_point(&ftransform, &p3);
+
+ min_x = MIN(p0.v[0], p1.v[0]);
+ min_x = MIN(min_x, p2.v[0]);
+ min_x = MIN(min_x, p3.v[0]);
+
+ min_y = MIN(p0.v[1], p1.v[1]);
+ min_y = MIN(min_y, p2.v[1]);
+ min_y = MIN(min_y, p3.v[1]);
+
+ max_x = MAX(p0.v[0], p1.v[0]);
+ max_x = MAX(max_x, p2.v[0]);
+ max_x = MAX(max_x, p3.v[0]);
+
+ max_y = MAX(p0.v[1], p1.v[1]);
+ max_y = MAX(max_y, p2.v[1]);
+ max_y = MAX(max_y, p3.v[1]);
+ box->x1 = floor(min_x) - 1;
+ box->y1 = floor(min_y) - 1;
+ box->x2 = ceil(max_x) + 1;
+ box->y2 = ceil(max_y) + 1;
+}
+
+static void
+_glamor_process_transformed_clipped_region(glamor_pixmap_private *priv,
+ int repeat_type,
+ glamor_pixmap_clipped_regions *clipped_regions,
+ int *n_regions, int *need_clean_fbo)
+{
+ int shift_x, shift_y;
+ if (*n_regions != 1) {
+ /* Merge all source regions into one region. */
+ glamor_merge_clipped_regions(priv, repeat_type,
+ clipped_regions, n_regions,
+ need_clean_fbo);
+ } else {
+ SET_PIXMAP_FBO_CURRENT(priv,
+ clipped_regions[0].block_idx);
+ if (repeat_type == RepeatReflect || repeat_type == RepeatNormal) {
+ /* The required source areas are in one region,
+ * we need to shift the corresponding box's coords to proper position,
+ * thus we can calculate the relative coords correctly.*/
+ BoxPtr temp_box;
+ int rem;
+ temp_box = RegionExtents(clipped_regions[0].region);
+ modulus(temp_box->x1, priv->base.pixmap->drawable.width, rem);
+ shift_x = (temp_box->x1 - rem) / priv->base.pixmap->drawable.width;
+ modulus(temp_box->y1, priv->base.pixmap->drawable.height, rem);
+ shift_y = (temp_box->y1 - rem) / priv->base.pixmap->drawable.height;
+
+ if (shift_x != 0) {
+ priv->large.box.x1 += shift_x * priv->base.pixmap->drawable.width;
+ priv->large.box.x2 += shift_x * priv->base.pixmap->drawable.width;
+ }
+ if (shift_y != 0) {
+ priv->large.box.y1 += shift_y * priv->base.pixmap->drawable.height;
+ priv->large.box.y2 += shift_y * priv->base.pixmap->drawable.height;
+ }
+ }
+ }
+}
+
+
+Bool
+glamor_composite_largepixmap_region(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ glamor_pixmap_private * source_pixmap_priv,
+ glamor_pixmap_private * mask_pixmap_priv,
+ glamor_pixmap_private * dest_pixmap_priv,
+ RegionPtr region, Bool force_clip,
+ INT16 x_source,
+ INT16 y_source,
+ INT16 x_mask,
+ INT16 y_mask,
+ INT16 x_dest, INT16 y_dest,
+ CARD16 width, CARD16 height)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_pixmap_clipped_regions *clipped_dest_regions;
+ glamor_pixmap_clipped_regions *clipped_source_regions;
+ glamor_pixmap_clipped_regions *clipped_mask_regions;
+ int n_dest_regions;
+ int n_mask_regions;
+ int n_source_regions;
+ int i,j,k;
+ int need_clean_source_fbo = 0;
+ int need_clean_mask_fbo = 0;
+ int is_normal_source_fbo = 0;
+ int is_normal_mask_fbo = 0;
+ int fixed_block_width, fixed_block_height;
+ int null_source, null_mask;
+ glamor_pixmap_private * need_free_source_pixmap_priv = NULL;
+ glamor_pixmap_private * need_free_mask_pixmap_priv = NULL;
+ int source_repeat_type = 0, mask_repeat_type = 0;
+ int ok = TRUE;
+
+ if (source->repeat)
+ source_repeat_type = source->repeatType;
+ else
+ source_repeat_type = RepeatNone;
+
+ if (mask && mask->repeat)
+ mask_repeat_type = mask->repeatType;
+ else
+ mask_repeat_type = RepeatNone;
+
+ glamor_priv = dest_pixmap_priv->base.glamor_priv;
+ fixed_block_width = glamor_priv->max_fbo_size;
+ fixed_block_height = glamor_priv->max_fbo_size;
+ /* If we got an totally out-of-box region for a source or mask
+ * region without repeat, we need to set it as null_source and
+ * give it a solid color (0,0,0,0). */
+ null_source = 0;
+ null_mask = 0;
+ RegionTranslate(region, -dest->pDrawable->x,
+ -dest->pDrawable->y);
+
+ /* need to transform the dest region to the correct sourcei/mask region.
+ * it's a little complex, as one single edge of the
+ * target region may be transformed to cross a block boundary of the
+ * source or mask. Then it's impossible to handle it as usual way.
+ * We may have to split the original dest region to smaller region, and
+ * make sure each region's transformed region can fit into one texture,
+ * and then continue this loop again, and each time when a transformed region
+ * cross the bound, we need to copy it to a single pixmap and do the composition
+ * with the new pixmap. If the transformed region doesn't cross a source/mask's
+ * boundary then we don't need to copy.
+ *
+ */
+ if (source_pixmap_priv
+ && source->transform
+ && source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ int source_transformed_block_width, source_transformed_block_height;
+ if (!glamor_get_transform_block_size(source->transform,
+ source_pixmap_priv->large.block_w,
+ source_pixmap_priv->large.block_h,
+ &source_transformed_block_width,
+ &source_transformed_block_height)) {
+ DEBUGF("source block size less than 1, fallback.\n");
+ RegionTranslate(region, dest->pDrawable->x,
+ dest->pDrawable->y);
+ return FALSE;
+ }
+ fixed_block_width = min(fixed_block_width , source_transformed_block_width);
+ fixed_block_height = min(fixed_block_height , source_transformed_block_height);
+ DEBUGF("new source block size %d x %d \n", fixed_block_width, fixed_block_height);
+ }
+
+ if (mask_pixmap_priv
+ && mask->transform
+ && mask_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ int mask_transformed_block_width, mask_transformed_block_height;
+ if (!glamor_get_transform_block_size(mask->transform,
+ mask_pixmap_priv->large.block_w,
+ mask_pixmap_priv->large.block_h,
+ &mask_transformed_block_width,
+ &mask_transformed_block_height)) {
+ DEBUGF("mask block size less than 1, fallback.\n");
+ RegionTranslate(region, dest->pDrawable->x,
+ dest->pDrawable->y);
+ return FALSE;
+ }
+ fixed_block_width = min(fixed_block_width , mask_transformed_block_width);
+ fixed_block_height = min(fixed_block_height , mask_transformed_block_height);
+ DEBUGF("new mask block size %d x %d \n", fixed_block_width, fixed_block_height);
+ }
+
+ /*compute the correct block width and height whose transformed source/mask
+ *region can fit into one texture.*/
+ if (force_clip || fixed_block_width < glamor_priv->max_fbo_size
+ || fixed_block_height < glamor_priv->max_fbo_size)
+ clipped_dest_regions = glamor_compute_clipped_regions_ext(dest_pixmap_priv,
+ region,
+ &n_dest_regions,
+ fixed_block_width,
+ fixed_block_height,
+ 0, 0);
+ else
+ clipped_dest_regions = glamor_compute_clipped_regions(dest_pixmap_priv,
+ region,
+ &n_dest_regions,
+ 0, 0, 0);
+ DEBUGF("dest clipped result %d region: \n", n_dest_regions);
+ if (source_pixmap_priv
+ && (source_pixmap_priv == dest_pixmap_priv || source_pixmap_priv == mask_pixmap_priv)
+ && source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ /* XXX self-copy...*/
+ need_free_source_pixmap_priv = source_pixmap_priv;
+ source_pixmap_priv = malloc(sizeof(*source_pixmap_priv));
+ *source_pixmap_priv = *need_free_source_pixmap_priv;
+ need_free_source_pixmap_priv = source_pixmap_priv;
+ }
+ assert(mask_pixmap_priv != dest_pixmap_priv);
+
+ for(i = 0; i < n_dest_regions; i++)
+ {
+ DEBUGF("dest region %d idx %d\n", i, clipped_dest_regions[i].block_idx);
+ DEBUGRegionPrint(clipped_dest_regions[i].region);
+ SET_PIXMAP_FBO_CURRENT(dest_pixmap_priv, clipped_dest_regions[i].block_idx);
+ if ( source_pixmap_priv && source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ if (!source->transform && source_repeat_type != RepeatPad) {
+ RegionTranslate(clipped_dest_regions[i].region,
+ x_source - x_dest,
+ y_source - y_dest);
+ clipped_source_regions = glamor_compute_clipped_regions(source_pixmap_priv,
+ clipped_dest_regions[i].region,
+ &n_source_regions, source_repeat_type,
+ 0, 0);
+ is_normal_source_fbo = 1;
+ }
+ else {
+ clipped_source_regions = glamor_compute_transform_clipped_regions(source_pixmap_priv,
+ source->transform,
+ clipped_dest_regions[i].region,
+ &n_source_regions,
+ x_source - x_dest, y_source - y_dest,
+ source_repeat_type, 0, 0);
+ is_normal_source_fbo = 0;
+ if (n_source_regions == 0) {
+ /* Pad the out-of-box region to (0,0,0,0). */
+ null_source = 1;
+ n_source_regions = 1;
+ } else
+ _glamor_process_transformed_clipped_region(source_pixmap_priv,
+ source_repeat_type, clipped_source_regions, &n_source_regions,
+ &need_clean_source_fbo);
+ }
+ DEBUGF("source clipped result %d region: \n", n_source_regions);
+ for(j = 0; j < n_source_regions; j++)
+ {
+ if (is_normal_source_fbo)
+ SET_PIXMAP_FBO_CURRENT(source_pixmap_priv,
+ clipped_source_regions[j].block_idx);
+
+ if (mask_pixmap_priv && mask_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ if (is_normal_mask_fbo && is_normal_source_fbo) {
+ /* both mask and source are normal fbo box without transform or repeatpad.
+ * The region is clipped against source and then we clip it against mask here.*/
+ DEBUGF("source region %d idx %d\n", j, clipped_source_regions[j].block_idx);
+ DEBUGRegionPrint(clipped_source_regions[j].region);
+ RegionTranslate(clipped_source_regions[j].region,
+ - x_source + x_mask,
+ - y_source + y_mask);
+ clipped_mask_regions = glamor_compute_clipped_regions(mask_pixmap_priv,
+ clipped_source_regions[j].region,
+ &n_mask_regions, mask_repeat_type,
+ 0, 0);
+ is_normal_mask_fbo = 1;
+ } else if (is_normal_mask_fbo && !is_normal_source_fbo) {
+ assert(n_source_regions == 1);
+ /* The source fbo is not a normal fbo box, it has transform or repeatpad.
+ * the valid clip region should be the clip dest region rather than the
+ * clip source region.*/
+ RegionTranslate(clipped_dest_regions[i].region,
+ - x_dest + x_mask,
+ - y_dest + y_mask);
+ clipped_mask_regions = glamor_compute_clipped_regions(mask_pixmap_priv,
+ clipped_dest_regions[i].region,
+ &n_mask_regions, mask_repeat_type,
+ 0, 0);
+ is_normal_mask_fbo = 1;
+ } else {
+ /* This mask region has transform or repeatpad, we need clip it agains the previous
+ * valid region rather than the mask region. */
+ if (!is_normal_source_fbo)
+ clipped_mask_regions = glamor_compute_transform_clipped_regions(mask_pixmap_priv,
+ mask->transform,
+ clipped_dest_regions[i].region,
+ &n_mask_regions,
+ x_mask - x_dest,
+ y_mask - y_dest,
+ mask_repeat_type, 0, 0);
+ else
+ clipped_mask_regions = glamor_compute_transform_clipped_regions(mask_pixmap_priv,
+ mask->transform,
+ clipped_source_regions[j].region,
+ &n_mask_regions,
+ x_mask - x_source, y_mask - y_source,
+ mask_repeat_type, 0, 0);
+ is_normal_mask_fbo = 0;
+ if (n_mask_regions == 0) {
+ /* Pad the out-of-box region to (0,0,0,0). */
+ null_mask = 1;
+ n_mask_regions = 1;
+ } else
+ _glamor_process_transformed_clipped_region(mask_pixmap_priv,
+ mask_repeat_type, clipped_mask_regions, &n_mask_regions,
+ &need_clean_mask_fbo);
+ }
+ DEBUGF("mask clipped result %d region: \n", n_mask_regions);
+
+#define COMPOSITE_REGION(region) do { \
+ if (!glamor_composite_clipped_region(op, \
+ null_source ? NULL : source, \
+ null_mask ? NULL : mask, dest, \
+ null_source ? NULL : source_pixmap_priv, \
+ null_mask ? NULL : mask_pixmap_priv, \
+ dest_pixmap_priv, region, \
+ x_source, y_source, x_mask, y_mask, \
+ x_dest, y_dest)) { \
+ assert(0); \
+ } \
+ } while(0)
+
+ for(k = 0; k < n_mask_regions; k++)
+ {
+ DEBUGF("mask region %d idx %d\n", k, clipped_mask_regions[k].block_idx);
+ DEBUGRegionPrint(clipped_mask_regions[k].region);
+ if (is_normal_mask_fbo) {
+ SET_PIXMAP_FBO_CURRENT(mask_pixmap_priv,
+ clipped_mask_regions[k].block_idx);
+ DEBUGF("mask fbo off %d %d \n",
+ mask_pixmap_priv->large.box.x1,
+ mask_pixmap_priv->large.box.y1);
+ DEBUGF("start composite mask hasn't transform.\n");
+ RegionTranslate(clipped_mask_regions[k].region,
+ x_dest - x_mask + dest->pDrawable->x,
+ y_dest - y_mask + dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_mask_regions[k].region);
+ } else if (!is_normal_mask_fbo && !is_normal_source_fbo) {
+ DEBUGF("start composite both mask and source have transform.\n");
+ RegionTranslate(clipped_dest_regions[i].region,
+ dest->pDrawable->x,
+ dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_dest_regions[i].region);
+ } else {
+ DEBUGF("start composite only mask has transform.\n");
+ RegionTranslate(clipped_source_regions[j].region,
+ x_dest - x_source + dest->pDrawable->x,
+ y_dest - y_source + dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_source_regions[j].region);
+ }
+ RegionDestroy(clipped_mask_regions[k].region);
+ }
+ free(clipped_mask_regions);
+ if (null_mask) null_mask = 0;
+ if (need_clean_mask_fbo) {
+ assert(is_normal_mask_fbo == 0);
+ glamor_destroy_fbo(mask_pixmap_priv->base.fbo);
+ mask_pixmap_priv->base.fbo = NULL;
+ need_clean_mask_fbo = 0;
+ }
+ } else {
+ if (is_normal_source_fbo) {
+ RegionTranslate(clipped_source_regions[j].region,
+ -x_source + x_dest + dest->pDrawable->x,
+ -y_source + y_dest + dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_source_regions[j].region);
+ } else {
+ /* Source has transform or repeatPad. dest regions is the right
+ * region to do the composite. */
+ RegionTranslate(clipped_dest_regions[i].region,
+ dest->pDrawable->x,
+ dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_dest_regions[i].region);
+ }
+ }
+ if (clipped_source_regions && clipped_source_regions[j].region)
+ RegionDestroy(clipped_source_regions[j].region);
+ }
+ free(clipped_source_regions);
+ if (null_source) null_source = 0;
+ if (need_clean_source_fbo) {
+ assert(is_normal_source_fbo == 0);
+ glamor_destroy_fbo(source_pixmap_priv->base.fbo);
+ source_pixmap_priv->base.fbo = NULL;
+ need_clean_source_fbo = 0;
+ }
+ }
+ else {
+ if (mask_pixmap_priv && mask_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ if (!mask->transform && mask_repeat_type != RepeatPad) {
+ RegionTranslate(clipped_dest_regions[i].region,
+ x_mask - x_dest,
+ y_mask - y_dest);
+ clipped_mask_regions = glamor_compute_clipped_regions(mask_pixmap_priv,
+ clipped_dest_regions[i].region,
+ &n_mask_regions, mask_repeat_type, 0, 0);
+ is_normal_mask_fbo = 1;
+ }
+ else {
+ clipped_mask_regions = glamor_compute_transform_clipped_regions(mask_pixmap_priv,
+ mask->transform,
+ clipped_dest_regions[i].region,
+ &n_mask_regions,
+ x_mask - x_dest, y_mask - y_dest,
+ mask_repeat_type, 0, 0);
+ is_normal_mask_fbo = 0;
+ if (n_mask_regions == 0) {
+ /* Pad the out-of-box region to (0,0,0,0). */
+ null_mask = 1;
+ n_mask_regions = 1;
+ } else
+ _glamor_process_transformed_clipped_region(mask_pixmap_priv,
+ mask_repeat_type, clipped_mask_regions, &n_mask_regions,
+ &need_clean_mask_fbo);
+ }
+
+ for(k = 0; k < n_mask_regions; k++)
+ {
+ DEBUGF("mask region %d idx %d\n", k, clipped_mask_regions[k].block_idx);
+ DEBUGRegionPrint(clipped_mask_regions[k].region);
+ if (is_normal_mask_fbo) {
+ SET_PIXMAP_FBO_CURRENT(mask_pixmap_priv,
+ clipped_mask_regions[k].block_idx);
+ RegionTranslate(clipped_mask_regions[k].region,
+ x_dest - x_mask + dest->pDrawable->x,
+ y_dest - y_mask + dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_mask_regions[k].region);
+ } else {
+ RegionTranslate(clipped_dest_regions[i].region,
+ dest->pDrawable->x,
+ dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_dest_regions[i].region);
+ }
+ RegionDestroy(clipped_mask_regions[k].region);
+ }
+ free(clipped_mask_regions);
+ if (null_mask) null_mask = 0;
+ if (need_clean_mask_fbo) {
+ glamor_destroy_fbo(mask_pixmap_priv->base.fbo);
+ mask_pixmap_priv->base.fbo = NULL;
+ need_clean_mask_fbo = 0;
+ }
+ }
+ else {
+ RegionTranslate(clipped_dest_regions[i].region,
+ dest->pDrawable->x,
+ dest->pDrawable->y);
+ COMPOSITE_REGION(clipped_dest_regions[i].region);
+ }
+ }
+ RegionDestroy(clipped_dest_regions[i].region);
+ }
+ free(clipped_dest_regions);
+ free(need_free_source_pixmap_priv);
+ free(need_free_mask_pixmap_priv);
+ ok = TRUE;
+ return ok;
+}
diff --git a/glamor/glamor_picture.c b/glamor/glamor_picture.c
new file mode 100644
index 000000000..7d5ffbb76
--- /dev/null
+++ b/glamor/glamor_picture.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@gmail.com>
+ *
+ */
+
+#include <stdlib.h>
+
+#include "glamor_priv.h"
+#include "mipict.h"
+
+/* Upload picture to texture. We may need to flip the y axis or
+ * wire alpha to 1. So we may conditional create fbo for the picture.
+ * */
+enum glamor_pixmap_status
+glamor_upload_picture_to_texture(PicturePtr picture)
+{
+ PixmapPtr pixmap;
+ assert(picture->pDrawable);
+ pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
+
+ return glamor_upload_pixmap_to_texture(pixmap);
+}
+
+
+Bool
+glamor_prepare_access_picture(PicturePtr picture, glamor_access_t access)
+{
+ if (!picture || !picture->pDrawable)
+ return TRUE;
+
+ return glamor_prepare_access(picture->pDrawable, access);
+}
+
+void
+glamor_finish_access_picture(PicturePtr picture, glamor_access_t access)
+{
+ if (!picture || !picture->pDrawable)
+ return;
+
+ glamor_finish_access(picture->pDrawable, access);
+}
+
+/*
+ * We should already have drawable attached to it, if it has one.
+ * Then set the attached pixmap to is_picture format, and set
+ * the pict format.
+ * */
+int
+glamor_create_picture(PicturePtr picture)
+{
+ PixmapPtr pixmap;
+ glamor_pixmap_private *pixmap_priv;
+
+ if (!picture || !picture->pDrawable)
+ return 0;
+
+ pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ if (!pixmap_priv) {
+ /* We must create a pixmap priv to track the picture format even
+ * if the pixmap is a pure in memory pixmap. The reason is that
+ * we may need to upload this pixmap to a texture on the fly. During
+ * the uploading, we need to know the picture format. */
+ glamor_set_pixmap_type(pixmap, GLAMOR_MEMORY);
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ } else {
+ if (GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) {
+ /* If the picture format is not compatible with glamor fbo format,
+ * we have to mark this pixmap as a separated texture, and don't
+ * fallback to DDX layer. */
+ if (pixmap_priv->type == GLAMOR_TEXTURE_DRM
+ && !glamor_pict_format_is_compatible(picture->format,
+ pixmap->drawable.depth))
+ glamor_set_pixmap_type(pixmap, GLAMOR_SEPARATE_TEXTURE);
+ }
+ }
+
+ pixmap_priv->base.is_picture = 1;
+ pixmap_priv->base.picture = picture;
+
+ return miCreatePicture(picture);
+}
+
+void
+glamor_destroy_picture(PicturePtr picture)
+{
+ PixmapPtr pixmap;
+ glamor_pixmap_private *pixmap_priv;
+
+ if (!picture || !picture->pDrawable)
+ return;
+
+ pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ if (pixmap_priv) {
+ pixmap_priv->base.is_picture = 0;
+ pixmap_priv->base.picture = NULL;
+ }
+ miDestroyPicture(picture);
+}
+
+void
+glamor_picture_format_fixup(PicturePtr picture,
+ glamor_pixmap_private * pixmap_priv)
+{
+ pixmap_priv->base.picture = picture;
+}
diff --git a/glamor/glamor_pixmap.c b/glamor/glamor_pixmap.c
new file mode 100644
index 000000000..84694ec3c
--- /dev/null
+++ b/glamor/glamor_pixmap.c
@@ -0,0 +1,1433 @@
+/*
+ * Copyright © 2001 Keith Packard
+ * Copyright © 2008 Intel Corporation
+ *
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ *
+ */
+
+#include <stdlib.h>
+
+#include "glamor_priv.h"
+/**
+ * Sets the offsets to add to coordinates to make them address the same bits in
+ * the backing drawable. These coordinates are nonzero only for redirected
+ * windows.
+ */
+void
+glamor_get_drawable_deltas(DrawablePtr drawable, PixmapPtr pixmap,
+ int *x, int *y)
+{
+#ifdef COMPOSITE
+ if (drawable->type == DRAWABLE_WINDOW) {
+ *x = -pixmap->screen_x;
+ *y = -pixmap->screen_y;
+ return;
+ }
+#endif
+
+ *x = 0;
+ *y = 0;
+}
+
+
+void
+glamor_pixmap_init(ScreenPtr screen)
+{
+
+}
+
+void
+glamor_pixmap_fini(ScreenPtr screen)
+{
+}
+
+void
+glamor_set_destination_pixmap_fbo(glamor_pixmap_fbo * fbo, int x0, int y0, int width, int height)
+{
+ glamor_gl_dispatch *dispatch = glamor_get_dispatch(fbo->glamor_priv);
+ dispatch->glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
+#ifndef GLAMOR_GLES2
+ dispatch->glMatrixMode(GL_PROJECTION);
+ dispatch->glLoadIdentity();
+ dispatch->glMatrixMode(GL_MODELVIEW);
+ dispatch->glLoadIdentity();
+#endif
+ dispatch->glViewport(x0, y0,
+ width, height);
+
+ glamor_put_dispatch(fbo->glamor_priv);
+}
+
+void
+glamor_set_destination_pixmap_priv_nc(glamor_pixmap_private * pixmap_priv)
+{
+ int w,h;
+
+ PIXMAP_PRIV_GET_ACTUAL_SIZE(pixmap_priv, w, h);
+ glamor_set_destination_pixmap_fbo(pixmap_priv->base.fbo, 0, 0,
+ w, h);
+}
+
+int
+glamor_set_destination_pixmap_priv(glamor_pixmap_private * pixmap_priv)
+{
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ return -1;
+
+ glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+ return 0;
+}
+
+int
+glamor_set_destination_pixmap(PixmapPtr pixmap)
+{
+ int err;
+ glamor_pixmap_private *pixmap_priv =
+ glamor_get_pixmap_private(pixmap);
+
+ err = glamor_set_destination_pixmap_priv(pixmap_priv);
+ return err;
+}
+
+Bool
+glamor_set_planemask(PixmapPtr pixmap, unsigned long planemask)
+{
+ if (glamor_pm_is_solid(&pixmap->drawable, planemask)) {
+ return GL_TRUE;
+ }
+
+ glamor_fallback("unsupported planemask %lx\n", planemask);
+ return GL_FALSE;
+}
+
+Bool
+glamor_set_alu(struct glamor_gl_dispatch *dispatch, unsigned char alu)
+{
+#ifndef GLAMOR_GLES2
+ if (alu == GXcopy) {
+ dispatch->glDisable(GL_COLOR_LOGIC_OP);
+ return TRUE;
+ }
+ dispatch->glEnable(GL_COLOR_LOGIC_OP);
+ switch (alu) {
+ case GXclear:
+ dispatch->glLogicOp(GL_CLEAR);
+ break;
+ case GXand:
+ dispatch->glLogicOp(GL_AND);
+ break;
+ case GXandReverse:
+ dispatch->glLogicOp(GL_AND_REVERSE);
+ break;
+ case GXandInverted:
+ dispatch->glLogicOp(GL_AND_INVERTED);
+ break;
+ case GXnoop:
+ dispatch->glLogicOp(GL_NOOP);
+ break;
+ case GXxor:
+ dispatch->glLogicOp(GL_XOR);
+ break;
+ case GXor:
+ dispatch->glLogicOp(GL_OR);
+ break;
+ case GXnor:
+ dispatch->glLogicOp(GL_NOR);
+ break;
+ case GXequiv:
+ dispatch->glLogicOp(GL_EQUIV);
+ break;
+ case GXinvert:
+ dispatch->glLogicOp(GL_INVERT);
+ break;
+ case GXorReverse:
+ dispatch->glLogicOp(GL_OR_REVERSE);
+ break;
+ case GXcopyInverted:
+ dispatch->glLogicOp(GL_COPY_INVERTED);
+ break;
+ case GXorInverted:
+ dispatch->glLogicOp(GL_OR_INVERTED);
+ break;
+ case GXnand:
+ dispatch->glLogicOp(GL_NAND);
+ break;
+ case GXset:
+ dispatch->glLogicOp(GL_SET);
+ break;
+ default:
+ glamor_fallback("unsupported alu %x\n", alu);
+ return FALSE;
+ }
+#else
+ if (alu != GXcopy)
+ return FALSE;
+#endif
+ return TRUE;
+}
+
+static void *
+_glamor_color_convert_a1_a8(void *src_bits, void *dst_bits, int w, int h, int stride, int revert)
+{
+ PictFormatShort dst_format, src_format;
+ pixman_image_t *dst_image;
+ pixman_image_t *src_image;
+ int src_stride;
+
+ if (revert == REVERT_UPLOADING_A1) {
+ src_format = PICT_a1;
+ dst_format = PICT_a8;
+ src_stride = PixmapBytePad(w, 1);
+ } else {
+ dst_format = PICT_a1;
+ src_format = PICT_a8;
+ src_stride = (((w * 8 + 7) / 8) + 3) & ~3;
+ }
+
+ dst_image = pixman_image_create_bits(dst_format,
+ w, h,
+ dst_bits,
+ stride);
+ if (dst_image == NULL) {
+ return NULL;
+ }
+
+ src_image = pixman_image_create_bits(src_format,
+ w, h,
+ src_bits,
+ src_stride);
+
+ if (src_image == NULL) {
+ pixman_image_unref(dst_image);
+ return NULL;
+ }
+
+ pixman_image_composite(PictOpSrc, src_image, NULL, dst_image,
+ 0, 0, 0, 0, 0, 0,
+ w,h);
+
+ pixman_image_unref(src_image);
+ pixman_image_unref(dst_image);
+ return dst_bits;
+}
+
+#define ADJUST_BITS(d, src_bits, dst_bits) (((dst_bits) == (src_bits)) ? (d) : \
+ (((dst_bits) > (src_bits)) ? \
+ (((d) << ((dst_bits) - (src_bits))) \
+ + (( 1 << ((dst_bits) - (src_bits))) >> 1)) \
+ : ((d) >> ((src_bits) - (dst_bits)))))
+
+#define GLAMOR_DO_CONVERT(src, dst, no_alpha, swap, \
+ a_shift_src, a_bits_src, \
+ b_shift_src, b_bits_src, \
+ g_shift_src, g_bits_src, \
+ r_shift_src, r_bits_src, \
+ a_shift, a_bits, \
+ b_shift, b_bits, \
+ g_shift, g_bits, \
+ r_shift, r_bits) \
+ { \
+ typeof(src) a,b,g,r; \
+ typeof(src) a_mask_src, b_mask_src, g_mask_src, r_mask_src;\
+ a_mask_src = (((1 << (a_bits_src)) - 1) << a_shift_src);\
+ b_mask_src = (((1 << (b_bits_src)) - 1) << b_shift_src);\
+ g_mask_src = (((1 << (g_bits_src)) - 1) << g_shift_src);\
+ r_mask_src = (((1 << (r_bits_src)) - 1) << r_shift_src);\
+ if (no_alpha) \
+ a = (a_mask_src) >> (a_shift_src); \
+ else \
+ a = ((src) & (a_mask_src)) >> (a_shift_src); \
+ b = ((src) & (b_mask_src)) >> (b_shift_src); \
+ g = ((src) & (g_mask_src)) >> (g_shift_src); \
+ r = ((src) & (r_mask_src)) >> (r_shift_src); \
+ a = ADJUST_BITS(a, a_bits_src, a_bits); \
+ b = ADJUST_BITS(b, b_bits_src, b_bits); \
+ g = ADJUST_BITS(g, g_bits_src, g_bits); \
+ r = ADJUST_BITS(r, r_bits_src, r_bits); \
+ if (swap == 0) \
+ (*dst) = ((a) << (a_shift)) | ((b) << (b_shift)) | ((g) << (g_shift)) | ((r) << (r_shift)); \
+ else \
+ (*dst) = ((a) << (a_shift)) | ((r) << (b_shift)) | ((g) << (g_shift)) | ((b) << (r_shift)); \
+ }
+
+static void *
+_glamor_color_revert_x2b10g10r10(void *src_bits, void *dst_bits, int w, int h, int stride, int no_alpha, int revert, int swap_rb)
+{
+ int x,y;
+ unsigned int *words, *saved_words, *source_words;
+ int swap = !(swap_rb == SWAP_NONE_DOWNLOADING || swap_rb == SWAP_NONE_UPLOADING);
+
+ source_words = src_bits;
+ words = dst_bits;
+ saved_words = words;
+
+ for (y = 0; y < h; y++)
+ {
+ DEBUGF("Line %d : ", y);
+ for (x = 0; x < w; x++)
+ {
+ unsigned int pixel = source_words[x];
+
+ if (revert == REVERT_DOWNLOADING_2_10_10_10)
+ GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
+ 24, 8, 16, 8, 8, 8, 0, 8,
+ 30, 2, 20, 10, 10, 10, 0, 10)
+ else
+ GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
+ 30, 2, 20, 10, 10, 10, 0, 10,
+ 24, 8, 16, 8, 8, 8, 0, 8);
+ DEBUGF("%x:%x ", pixel, words[x]);
+ }
+ DEBUGF("\n");
+ words += stride / sizeof(*words);
+ source_words += stride / sizeof(*words);
+ }
+ DEBUGF("\n");
+ return saved_words;
+
+}
+
+static void *
+_glamor_color_revert_x1b5g5r5(void *src_bits, void *dst_bits, int w, int h, int stride, int no_alpha, int revert, int swap_rb)
+{
+ int x,y;
+ unsigned short *words, *saved_words, *source_words;
+ int swap = !(swap_rb == SWAP_NONE_DOWNLOADING || swap_rb == SWAP_NONE_UPLOADING);
+
+ words = dst_bits;
+ source_words = src_bits;
+ saved_words = words;
+
+ for (y = 0; y < h; y++)
+ {
+ DEBUGF("Line %d : ", y);
+ for (x = 0; x < w; x++)
+ {
+ unsigned short pixel = source_words[x];
+
+ if (revert == REVERT_DOWNLOADING_1_5_5_5)
+ GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
+ 0, 1, 1, 5, 6, 5, 11, 5,
+ 15, 1, 10, 5, 5, 5, 0, 5)
+ else
+ GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap,
+ 15, 1, 10, 5, 5, 5, 0, 5,
+ 0, 1, 1, 5, 6, 5, 11, 5);
+ DEBUGF("%04x:%04x ", pixel, words[x]);
+ }
+ DEBUGF("\n");
+ words += stride / sizeof(*words);
+ source_words += stride / sizeof(*words);
+ }
+ DEBUGF("\n");
+ return saved_words;
+}
+
+/*
+ * This function is to convert an unsupported color format to/from a
+ * supported GL format.
+ * Here are the current scenarios:
+ *
+ * @no_alpha:
+ * If it is set, then we need to wire the alpha value to 1.
+ * @revert:
+ REVERT_DOWNLOADING_A1 : convert an Alpha8 buffer to a A1 buffer.
+ REVERT_UPLOADING_A1 : convert an A1 buffer to an Alpha8 buffer
+ REVERT_DOWNLOADING_2_10_10_10 : convert r10G10b10X2 to X2B10G10R10
+ REVERT_UPLOADING_2_10_10_10 : convert X2B10G10R10 to R10G10B10X2
+ REVERT_DOWNLOADING_1_5_5_5 : convert B5G5R5X1 to X1R5G5B5
+ REVERT_UPLOADING_1_5_5_5 : convert X1R5G5B5 to B5G5R5X1
+ @swap_rb: if we have the swap_rb set, then we need to swap the R and B's position.
+ *
+ */
+
+static void *
+glamor_color_convert_to_bits(void *src_bits, void *dst_bits, int w, int h, int stride, int no_alpha, int revert, int swap_rb)
+{
+ if (revert == REVERT_DOWNLOADING_A1 || revert == REVERT_UPLOADING_A1) {
+ return _glamor_color_convert_a1_a8(src_bits, dst_bits, w, h, stride, revert);
+ } else if (revert == REVERT_DOWNLOADING_2_10_10_10 || revert == REVERT_UPLOADING_2_10_10_10) {
+ return _glamor_color_revert_x2b10g10r10(src_bits, dst_bits, w, h, stride, no_alpha, revert, swap_rb);
+ } else if (revert == REVERT_DOWNLOADING_1_5_5_5 || revert == REVERT_UPLOADING_1_5_5_5) {
+ return _glamor_color_revert_x1b5g5r5(src_bits, dst_bits, w, h, stride, no_alpha, revert, swap_rb);
+ } else
+ ErrorF("convert a non-supported mode %x.\n", revert);
+
+ return NULL;
+}
+
+/**
+ * Upload pixmap to a specified texture.
+ * This texture may not be the one attached to it.
+ **/
+int in_restore = 0;
+static void
+__glamor_upload_pixmap_to_texture(PixmapPtr pixmap, unsigned int *tex,
+ GLenum format,
+ GLenum type,
+ int x, int y, int w, int h,
+ void *bits, int pbo)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(pixmap->drawable.pScreen);
+ glamor_gl_dispatch *dispatch;
+ int non_sub = 0;
+ unsigned int iformat = 0;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ if (*tex == 0) {
+ dispatch->glGenTextures(1, tex);
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
+ gl_iformat_for_depth(pixmap->drawable.depth, &iformat);
+ else
+ iformat = format;
+ non_sub = 1;
+ assert(x == 0 && y == 0);
+ }
+
+ dispatch->glBindTexture(GL_TEXTURE_2D, *tex);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ dispatch->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+ if (bits == NULL)
+ dispatch->glBindBuffer(GL_PIXEL_UNPACK_BUFFER,
+ pbo);
+ if (non_sub)
+ dispatch->glTexImage2D(GL_TEXTURE_2D,
+ 0, iformat, w, h, 0,
+ format, type,
+ bits);
+ else
+ dispatch->glTexSubImage2D(GL_TEXTURE_2D,
+ 0, x, y, w, h,
+ format, type,
+ bits);
+
+ if (bits == NULL)
+ dispatch->glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ glamor_put_dispatch(glamor_priv);
+}
+
+static Bool
+_glamor_upload_bits_to_pixmap_texture(PixmapPtr pixmap, GLenum format, GLenum type,
+ int no_alpha, int revert,
+ int swap_rb, int x, int y, int w, int h,
+ int stride, void* bits, int pbo)
+{
+ glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
+ glamor_gl_dispatch *dispatch;
+ static float vertices[8];
+ static float texcoords[8] = { 0, 1,
+ 1, 1,
+ 1, 0,
+ 0, 0
+ };
+ static float texcoords_inv[8] = { 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1
+ };
+ float *ptexcoords;
+ float dst_xscale, dst_yscale;
+ GLuint tex = 0;
+ int need_flip;
+ int need_free_bits = 0;
+
+ need_flip = !glamor_priv->yInverted;
+
+ if (bits == NULL)
+ goto ready_to_upload;
+
+ if (revert > REVERT_NORMAL) {
+ /* XXX if we are restoring the pixmap, then we may not need to allocate
+ * new buffer */
+ void *converted_bits;
+
+ if (pixmap->drawable.depth == 1)
+ stride = (((w * 8 + 7) / 8) + 3) & ~3;
+
+ converted_bits = malloc(h * stride);
+
+ if (converted_bits == NULL)
+ return FALSE;
+ bits = glamor_color_convert_to_bits(bits, converted_bits, w, h,
+ stride,
+ no_alpha, revert, swap_rb);
+ if (bits == NULL) {
+ ErrorF("Failed to convert pixmap no_alpha %d,"
+ "revert mode %d, swap mode %d\n", no_alpha, revert, swap_rb);
+ return FALSE;
+ }
+ no_alpha = 0;
+ revert = REVERT_NONE;
+ swap_rb = SWAP_NONE_UPLOADING;
+ need_free_bits = TRUE;
+ }
+
+ready_to_upload:
+
+ /* Try fast path firstly, upload the pixmap to the texture attached
+ * to the fbo directly. */
+ if (no_alpha == 0
+ && revert == REVERT_NONE
+ && swap_rb == SWAP_NONE_UPLOADING
+ && !need_flip
+#ifdef WALKAROUND_LARGE_TEXTURE_MAP
+ && pixmap_priv->type != GLAMOR_TEXTURE_LARGE
+#endif
+ ) {
+ int fbo_x_off, fbo_y_off;
+ assert(pixmap_priv->base.fbo->tex);
+ pixmap_priv_get_fbo_off(pixmap_priv, &fbo_x_off, &fbo_y_off);
+
+ assert(x + fbo_x_off >= 0 && y + fbo_y_off >= 0);
+ assert(x + fbo_x_off + w <= pixmap_priv->base.fbo->width);
+ assert(y + fbo_y_off + h <= pixmap_priv->base.fbo->height);
+ __glamor_upload_pixmap_to_texture(pixmap, &pixmap_priv->base.fbo->tex,
+ format, type,
+ x + fbo_x_off, y + fbo_y_off, w, h,
+ bits, pbo);
+ return TRUE;
+ }
+
+ if (need_flip)
+ ptexcoords = texcoords;
+ else
+ ptexcoords = texcoords_inv;
+
+ pixmap_priv_get_dest_scale(pixmap_priv, &dst_xscale, &dst_yscale);
+ glamor_set_normalize_vcoords(pixmap_priv, dst_xscale,
+ dst_yscale,
+ x, y,
+ x + w, y + h,
+ glamor_priv->yInverted,
+ vertices);
+ /* Slow path, we need to flip y or wire alpha to 1. */
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
+ GL_FALSE, 2 * sizeof(float),
+ vertices);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT,
+ GL_FALSE, 2 * sizeof(float),
+ ptexcoords);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+
+ glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+ __glamor_upload_pixmap_to_texture(pixmap, &tex,
+ format, type,
+ 0, 0, w, h,
+ bits, pbo);
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glBindTexture(GL_TEXTURE_2D, tex);
+
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+#ifndef GLAMOR_GLES2
+ dispatch->glEnable(GL_TEXTURE_2D);
+#endif
+ dispatch->glUseProgram(glamor_priv->finish_access_prog[no_alpha]);
+ dispatch->glUniform1i(glamor_priv->
+ finish_access_revert[no_alpha],
+ revert);
+ dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha],
+ swap_rb);
+
+ dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+#ifndef GLAMOR_GLES2
+ dispatch->glDisable(GL_TEXTURE_2D);
+#endif
+ dispatch->glUseProgram(0);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glDeleteTextures(1, &tex);
+ dispatch->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ glamor_put_dispatch(glamor_priv);
+
+ if (need_free_bits)
+ free(bits);
+ return TRUE;
+}
+
+/*
+ * Prepare to upload a pixmap to texture memory.
+ * no_alpha equals 1 means the format needs to wire alpha to 1.
+ * Two condtion need to setup a fbo for a pixmap
+ * 1. !yInverted, we need to do flip if we are not yInverted.
+ * 2. no_alpha != 0, we need to wire the alpha.
+ * */
+static int
+glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha, int revert, int swap_rb)
+{
+ int flag = 0;
+ glamor_pixmap_private *pixmap_priv;
+ glamor_screen_private *glamor_priv;
+ glamor_pixmap_fbo *fbo;
+ GLenum iformat;
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
+
+ if (pixmap_priv->base.gl_fbo)
+ return 0;
+
+ if (pixmap_priv->base.fbo
+ && (pixmap_priv->base.fbo->width < pixmap->drawable.width
+ || pixmap_priv->base.fbo->height < pixmap->drawable.height)) {
+ fbo = glamor_pixmap_detach_fbo(pixmap_priv);
+ glamor_destroy_fbo(fbo);
+ }
+
+ if (pixmap_priv->base.fbo && pixmap_priv->base.fbo->fb)
+ return 0;
+
+ if (!(no_alpha
+ || (revert == REVERT_NORMAL)
+ || (swap_rb != SWAP_NONE_UPLOADING)
+ || !glamor_priv->yInverted)) {
+ /* We don't need a fbo, a simple texture uploading should work. */
+
+ flag = GLAMOR_CREATE_FBO_NO_FBO;
+ }
+
+ if ((flag == GLAMOR_CREATE_FBO_NO_FBO
+ && pixmap_priv->base.fbo && pixmap_priv->base.fbo->tex)
+ || (flag == 0
+ && pixmap_priv->base.fbo && pixmap_priv->base.fbo->fb))
+ return 0;
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
+ gl_iformat_for_depth(pixmap->drawable.depth, &iformat);
+ else
+ iformat = format;
+
+ if (!glamor_pixmap_ensure_fbo(pixmap, iformat, flag))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * upload sub region to a large region.
+ * */
+static void
+glamor_put_bits(char *dst_bits, int dst_stride, char *src_bits,
+ int src_stride, int bpp,
+ int x, int y, int w, int h)
+{
+ int j;
+ int byte_per_pixel;
+
+ byte_per_pixel = bpp / 8;
+ src_bits += y * src_stride + (x * byte_per_pixel);
+
+ for(j = y; j < y + h; j++)
+ {
+ memcpy(dst_bits, src_bits, w * byte_per_pixel);
+ src_bits += src_stride;
+ dst_bits += dst_stride;
+ }
+}
+/*
+ * download sub region from a large region.
+ */
+static void
+glamor_get_bits(char *dst_bits, int dst_stride, char *src_bits,
+ int src_stride, int bpp,
+ int x, int y, int w, int h)
+{
+ int j;
+ int byte_per_pixel;
+
+ byte_per_pixel = bpp / 8;
+ dst_bits += y * dst_stride + x * byte_per_pixel;
+
+ for(j = y; j < y + h; j++)
+ {
+ memcpy(dst_bits, src_bits, w * byte_per_pixel);
+ src_bits += src_stride;
+ dst_bits += dst_stride;
+ }
+}
+
+
+Bool
+glamor_upload_sub_pixmap_to_texture(PixmapPtr pixmap, int x, int y, int w, int h,
+ int stride, void *bits, int pbo)
+{
+ GLenum format, type;
+ int no_alpha, revert, swap_rb;
+ glamor_pixmap_private *pixmap_priv;
+ Bool force_clip;
+
+ if (glamor_get_tex_format_type_from_pixmap(pixmap,
+ &format,
+ &type,
+ &no_alpha,
+ &revert,
+ &swap_rb, 1)) {
+ glamor_fallback("Unknown pixmap depth %d.\n",
+ pixmap->drawable.depth);
+ return TRUE;
+ }
+ if (glamor_pixmap_upload_prepare(pixmap, format, no_alpha, revert, swap_rb))
+ return FALSE;
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ force_clip = pixmap_priv->base.glamor_priv->gl_flavor != GLAMOR_GL_DESKTOP
+ && !glamor_check_fbo_size(pixmap_priv->base.glamor_priv, w, h);
+
+ if (pixmap_priv->type == GLAMOR_TEXTURE_LARGE || force_clip) {
+ RegionRec region;
+ BoxRec box;
+ int n_region;
+ glamor_pixmap_clipped_regions *clipped_regions;
+ void *sub_bits;
+ int i,j;
+
+ sub_bits = malloc(h * stride);
+ if (sub_bits == NULL)
+ return FALSE;
+ box.x1 = x;
+ box.y1 = y;
+ box.x2 = x + w;
+ box.y2 = y + h;
+ RegionInitBoxes(&region, &box, 1);
+ if (!force_clip)
+ clipped_regions = glamor_compute_clipped_regions(pixmap_priv, &region, &n_region, 0, 0, 0);
+ else
+ clipped_regions = glamor_compute_clipped_regions_ext(pixmap_priv, &region, &n_region,
+ pixmap_priv->base.glamor_priv->max_fbo_size,
+ pixmap_priv->base.glamor_priv->max_fbo_size, 0, 0);
+ DEBUGF("prepare upload %dx%d to a large pixmap %p\n", w, h, pixmap);
+ for(i = 0; i < n_region; i++)
+ {
+ BoxPtr boxes;
+ int nbox;
+ int temp_stride;
+ void *temp_bits;
+
+ assert(pbo == 0);
+
+ SET_PIXMAP_FBO_CURRENT(pixmap_priv, clipped_regions[i].block_idx);
+
+ boxes = RegionRects(clipped_regions[i].region);
+ nbox = RegionNumRects(clipped_regions[i].region);
+ DEBUGF("split to %d boxes\n", nbox);
+ for(j = 0; j < nbox; j++)
+ {
+ temp_stride = PixmapBytePad(boxes[j].x2 - boxes[j].x1,
+ pixmap->drawable.depth);
+
+ if (boxes[j].x1 == x && temp_stride == stride) {
+ temp_bits = (char*)bits + (boxes[j].y1 - y) * stride;
+ } else {
+ temp_bits = sub_bits;
+ glamor_put_bits(temp_bits, temp_stride, bits, stride,
+ pixmap->drawable.bitsPerPixel,
+ boxes[j].x1 - x, boxes[j].y1 - y,
+ boxes[j].x2 - boxes[j].x1,
+ boxes[j].y2 - boxes[j].y1);
+ }
+ DEBUGF("upload x %d y %d w %d h %d temp stride %d \n",
+ boxes[j].x1 - x, boxes[j].y1 - y,
+ boxes[j].x2 - boxes[j].x1,
+ boxes[j].y2 - boxes[j].y1, temp_stride);
+ if (_glamor_upload_bits_to_pixmap_texture(pixmap, format, type, no_alpha,
+ revert, swap_rb, boxes[j].x1, boxes[j].y1,
+ boxes[j].x2 - boxes[j].x1,
+ boxes[j].y2 - boxes[j].y1,
+ temp_stride, temp_bits, pbo) == FALSE) {
+ RegionUninit(&region);
+ free(sub_bits);
+ assert(0);
+ return FALSE;
+ }
+ }
+ RegionDestroy(clipped_regions[i].region);
+ }
+ free(sub_bits);
+ free(clipped_regions);
+ RegionUninit(&region);
+ return TRUE;
+ } else
+ return _glamor_upload_bits_to_pixmap_texture(pixmap, format, type, no_alpha, revert, swap_rb,
+ x, y, w, h, stride, bits, pbo);
+}
+
+enum glamor_pixmap_status
+glamor_upload_pixmap_to_texture(PixmapPtr pixmap)
+{
+ glamor_pixmap_private *pixmap_priv;
+ void *data;
+ int pbo;
+ int ret;
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ if ((pixmap_priv->base.fbo)
+ && (pixmap_priv->base.fbo->pbo_valid)) {
+ data = NULL;
+ pbo = pixmap_priv->base.fbo->pbo;
+ } else {
+ data = pixmap->devPrivate.ptr;
+ pbo = 0;
+ }
+
+ if (glamor_upload_sub_pixmap_to_texture(pixmap, 0, 0,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ pixmap->devKind,
+ data, pbo))
+ ret = GLAMOR_UPLOAD_DONE;
+ else
+ ret = GLAMOR_UPLOAD_FAILED;
+
+ return ret;
+}
+
+void
+glamor_restore_pixmap_to_texture(PixmapPtr pixmap)
+{
+ if (glamor_upload_pixmap_to_texture(pixmap) != GLAMOR_UPLOAD_DONE)
+ LogMessage(X_WARNING, "Failed to restore pixmap to texture.\n");
+}
+
+/*
+ * as gles2 only support a very small set of color format and
+ * type when do glReadPixel,
+ * Before we use glReadPixels to get back a textured pixmap,
+ * Use shader to convert it to a supported format and thus
+ * get a new temporary pixmap returned.
+ * */
+
+glamor_pixmap_fbo *
+glamor_es2_pixmap_read_prepare(PixmapPtr source, int x, int y, int w, int h, GLenum format,
+ GLenum type, int no_alpha, int revert, int swap_rb)
+
+{
+ glamor_pixmap_private *source_priv;
+ glamor_screen_private *glamor_priv;
+ ScreenPtr screen;
+ glamor_pixmap_fbo *temp_fbo;
+ glamor_gl_dispatch *dispatch;
+ float temp_xscale, temp_yscale, source_xscale, source_yscale;
+ static float vertices[8];
+ static float texcoords[8];
+
+ screen = source->drawable.pScreen;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ source_priv = glamor_get_pixmap_private(source);
+ temp_fbo = glamor_create_fbo(glamor_priv,
+ w, h,
+ format,
+ 0);
+ if (temp_fbo == NULL)
+ return NULL;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ temp_xscale = 1.0 / w;
+ temp_yscale = 1.0 / h;
+
+ glamor_set_normalize_vcoords((struct glamor_pixmap_private*)NULL,temp_xscale,
+ temp_yscale,
+ 0, 0,
+ w, h,
+ glamor_priv->yInverted,
+ vertices);
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
+ GL_FALSE, 2 * sizeof(float),
+ vertices);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+
+ pixmap_priv_get_scale(source_priv, &source_xscale, &source_yscale);
+ glamor_set_normalize_tcoords(source_priv, source_xscale,
+ source_yscale,
+ x, y,
+ x + w, y + h,
+ glamor_priv->yInverted,
+ texcoords);
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT,
+ GL_FALSE, 2 * sizeof(float),
+ texcoords);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glBindTexture(GL_TEXTURE_2D, source_priv->base.fbo->tex);
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+
+ glamor_set_destination_pixmap_fbo(temp_fbo, 0, 0, w, h);
+ dispatch->glUseProgram(glamor_priv->finish_access_prog[no_alpha]);
+ dispatch->glUniform1i(glamor_priv->
+ finish_access_revert[no_alpha],
+ revert);
+ dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha],
+ swap_rb);
+
+ dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glUseProgram(0);
+ glamor_put_dispatch(glamor_priv);
+ return temp_fbo;
+}
+
+/*
+ * Download a sub region of pixmap to a specified memory region.
+ * The pixmap must have a valid FBO, otherwise return a NULL.
+ * */
+
+static void *
+_glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, GLenum format,
+ GLenum type, int no_alpha,
+ int revert, int swap_rb,
+ int x, int y, int w, int h,
+ int stride, void *bits, int pbo, glamor_access_t access)
+{
+ glamor_pixmap_private *pixmap_priv;
+ GLenum gl_access = 0, gl_usage = 0;
+ void *data, *read;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(pixmap->drawable.pScreen);
+ glamor_gl_dispatch *dispatch;
+ glamor_pixmap_fbo *temp_fbo = NULL;
+ int need_post_conversion = 0;
+ int need_free_data = 0;
+ int fbo_x_off, fbo_y_off;
+
+ data = bits;
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ return NULL;
+
+ switch (access) {
+ case GLAMOR_ACCESS_RO:
+ gl_access = GL_READ_ONLY;
+ gl_usage = GL_STREAM_READ;
+ break;
+ case GLAMOR_ACCESS_WO:
+ return bits;
+ case GLAMOR_ACCESS_RW:
+ gl_access = GL_READ_WRITE;
+ gl_usage = GL_DYNAMIC_DRAW;
+ break;
+ default:
+ ErrorF("Glamor: Invalid access code. %d\n", access);
+ assert(0);
+ }
+
+ glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+
+ need_post_conversion = (revert > REVERT_NORMAL);
+ if (need_post_conversion) {
+ if (pixmap->drawable.depth == 1) {
+ int temp_stride;
+ temp_stride = (((w * 8 + 7) / 8) + 3) & ~3;
+ data = malloc(temp_stride * h);
+ if (data == NULL)
+ return NULL;
+ need_free_data = 1;
+ }
+ }
+
+ pixmap_priv_get_fbo_off(pixmap_priv, &fbo_x_off, &fbo_y_off);
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
+ && !need_post_conversion
+ && (swap_rb != SWAP_NONE_DOWNLOADING || revert != REVERT_NONE)) {
+ if (!(temp_fbo = glamor_es2_pixmap_read_prepare(pixmap, x, y, w, h,
+ format, type, no_alpha,
+ revert, swap_rb))) {
+ free(data);
+ return NULL;
+ }
+ x = 0;
+ y = 0;
+ fbo_x_off = 0;
+ fbo_y_off = 0;
+ }
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glPixelStorei(GL_PACK_ALIGNMENT, 4);
+
+ if (glamor_priv->has_pack_invert || glamor_priv->yInverted) {
+
+ if (!glamor_priv->yInverted) {
+ assert(glamor_priv->gl_flavor ==
+ GLAMOR_GL_DESKTOP);
+ dispatch->glPixelStorei(GL_PACK_INVERT_MESA, 1);
+ }
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP && data == NULL) {
+ assert(pbo > 0);
+ dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
+ dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
+ stride *
+ h,
+ NULL, gl_usage);
+ }
+
+ dispatch->glReadPixels(x + fbo_x_off, y + fbo_y_off, w, h, format, type, data);
+
+ if (!glamor_priv->yInverted) {
+ assert(glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP);
+ dispatch->glPixelStorei(GL_PACK_INVERT_MESA, 0);
+ }
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP && bits == NULL) {
+ bits = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
+ gl_access);
+ dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+ }
+ } else {
+ unsigned int temp_pbo;
+ int yy;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glGenBuffers(1, &temp_pbo);
+ dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER,
+ temp_pbo);
+ dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
+ stride *
+ h,
+ NULL, GL_STREAM_READ);
+ dispatch->glReadPixels(x + fbo_x_off, y + fbo_y_off, w, h,
+ format, type, 0);
+ read = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER,
+ GL_READ_ONLY);
+ for (yy = 0; yy < pixmap->drawable.height; yy++)
+ memcpy((char*)data + yy * stride,
+ (char*)read + (h - yy - 1) * stride, stride);
+ dispatch->glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
+ dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+ dispatch->glDeleteBuffers(1, &temp_pbo);
+ }
+
+ dispatch->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glamor_put_dispatch(glamor_priv);
+
+ if (need_post_conversion) {
+ /* As OpenGL desktop version never enters here.
+ * Don't need to consider if the pbo is valid.*/
+ bits = glamor_color_convert_to_bits(data, bits,
+ w, h,
+ stride,
+ no_alpha,
+ revert, swap_rb);
+ }
+
+ if (temp_fbo != NULL)
+ glamor_destroy_fbo(temp_fbo);
+ if (need_free_data)
+ free(data);
+
+ return bits;
+}
+
+void *
+glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
+ int stride, void *bits, int pbo, glamor_access_t access)
+{
+ GLenum format, type;
+ int no_alpha, revert, swap_rb;
+ glamor_pixmap_private *pixmap_priv;
+ Bool force_clip;
+
+ if (glamor_get_tex_format_type_from_pixmap(pixmap,
+ &format,
+ &type,
+ &no_alpha,
+ &revert,
+ &swap_rb, 0)) {
+ glamor_fallback("Unknown pixmap depth %d.\n",
+ pixmap->drawable.depth);
+ return NULL;
+ }
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ return NULL;
+
+ force_clip = pixmap_priv->base.glamor_priv->gl_flavor != GLAMOR_GL_DESKTOP
+ && !glamor_check_fbo_size(pixmap_priv->base.glamor_priv, w, h);
+
+ if (pixmap_priv->type == GLAMOR_TEXTURE_LARGE || force_clip) {
+
+ RegionRec region;
+ BoxRec box;
+ int n_region;
+ glamor_pixmap_clipped_regions *clipped_regions;
+ void *sub_bits;
+ int i,j;
+
+ sub_bits = malloc(h * stride);
+ if (sub_bits == NULL)
+ return FALSE;
+ box.x1 = x;
+ box.y1 = y;
+ box.x2 = x + w;
+ box.y2 = y + h;
+ RegionInitBoxes(&region, &box, 1);
+
+ if (!force_clip)
+ clipped_regions = glamor_compute_clipped_regions(pixmap_priv, &region, &n_region, 0, 0, 0);
+ else
+ clipped_regions = glamor_compute_clipped_regions_ext(pixmap_priv, &region, &n_region,
+ pixmap_priv->base.glamor_priv->max_fbo_size,
+ pixmap_priv->base.glamor_priv->max_fbo_size, 0, 0);
+
+ DEBUGF("start download large pixmap %p %dx%d \n", pixmap, w, h);
+ for(i = 0; i < n_region; i++)
+ {
+ BoxPtr boxes;
+ int nbox;
+ int temp_stride;
+ void *temp_bits;
+
+ assert(pbo == 0);
+ SET_PIXMAP_FBO_CURRENT(pixmap_priv, clipped_regions[i].block_idx);
+
+ boxes = RegionRects(clipped_regions[i].region);
+ nbox = RegionNumRects(clipped_regions[i].region);
+ for(j = 0; j < nbox; j++)
+ {
+ temp_stride = PixmapBytePad(boxes[j].x2 - boxes[j].x1,
+ pixmap->drawable.depth);
+
+ if (boxes[j].x1 == x && temp_stride == stride) {
+ temp_bits = (char*)bits + (boxes[j].y1 - y) * stride;
+ } else {
+ temp_bits = sub_bits;
+ }
+ DEBUGF("download x %d y %d w %d h %d temp stride %d \n",
+ boxes[j].x1, boxes[j].y1,
+ boxes[j].x2 - boxes[j].x1,
+ boxes[j].y2 - boxes[j].y1, temp_stride);
+
+ /* For large pixmap, we don't support pbo currently.*/
+ assert(pbo == 0);
+ if (_glamor_download_sub_pixmap_to_cpu(pixmap, format, type, no_alpha,
+ revert, swap_rb, boxes[j].x1, boxes[j].y1,
+ boxes[j].x2 - boxes[j].x1,
+ boxes[j].y2 - boxes[j].y1,
+ temp_stride, temp_bits, pbo, access) == FALSE) {
+ RegionUninit(&region);
+ free(sub_bits);
+ assert(0);
+ return NULL;
+ }
+ if (boxes[j].x1 != x || temp_stride != stride)
+ glamor_get_bits(bits, stride, temp_bits, temp_stride,
+ pixmap->drawable.bitsPerPixel,
+ boxes[j].x1 - x , boxes[j].y1 - y,
+ boxes[j].x2 - boxes[j].x1,
+ boxes[j].y2 - boxes[j].y1);
+ }
+
+ RegionDestroy(clipped_regions[i].region);
+ }
+ free(sub_bits);
+ free(clipped_regions);
+ RegionUninit(&region);
+ return bits;
+ } else
+ return _glamor_download_sub_pixmap_to_cpu(pixmap, format, type, no_alpha, revert, swap_rb,
+ x, y, w, h, stride,
+ bits, pbo, access);
+}
+
+
+/**
+ * Move a pixmap to CPU memory.
+ * The input data is the pixmap's fbo.
+ * The output data is at pixmap->devPrivate.ptr. We always use pbo
+ * to read the fbo and then map it to va. If possible, we will use
+ * it directly as devPrivate.ptr.
+ * If successfully download a fbo to cpu then return TRUE.
+ * Otherwise return FALSE.
+ **/
+Bool
+glamor_download_pixmap_to_cpu(PixmapPtr pixmap, glamor_access_t access)
+{
+ glamor_pixmap_private *pixmap_priv =
+ glamor_get_pixmap_private(pixmap);
+ unsigned int stride;
+ void *data = NULL, *dst;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(pixmap->drawable.pScreen);
+ glamor_gl_dispatch *dispatch;
+ int pbo = 0;
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ return TRUE;
+
+ glamor_debug_output(GLAMOR_DEBUG_TEXTURE_DOWNLOAD,
+ "Downloading pixmap %p %dx%d depth%d\n",
+ pixmap,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ pixmap->drawable.depth);
+
+ stride = pixmap->devKind;
+
+ if (access == GLAMOR_ACCESS_WO
+ || glamor_priv->gl_flavor == GLAMOR_GL_ES2
+ || (!glamor_priv->has_pack_invert && !glamor_priv->yInverted)
+ || pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ data = malloc(stride * pixmap->drawable.height);
+ } else {
+ dispatch = glamor_get_dispatch(glamor_priv);
+ if (pixmap_priv->base.fbo->pbo == 0)
+ dispatch->glGenBuffers(1,
+ &pixmap_priv->base.fbo->pbo);
+ glamor_put_dispatch(glamor_priv);
+ pbo = pixmap_priv->base.fbo->pbo;
+ }
+
+ if (pixmap_priv->type == GLAMOR_TEXTURE_DRM) {
+ stride = PixmapBytePad(pixmap->drawable.width, pixmap->drawable.depth);
+ pixmap_priv->base.drm_stride = pixmap->devKind;
+ pixmap->devKind = stride;
+ }
+
+ dst = glamor_download_sub_pixmap_to_cpu(pixmap, 0, 0,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ pixmap->devKind,
+ data, pbo, access);
+
+ if (!dst) {
+ if (data)
+ free(data);
+ return FALSE;
+ }
+
+ if (pbo != 0)
+ pixmap_priv->base.fbo->pbo_valid = 1;
+
+ pixmap_priv->base.gl_fbo = GLAMOR_FBO_DOWNLOADED;
+
+ pixmap->devPrivate.ptr = dst;
+
+ return TRUE;
+}
+
+/* fixup a fbo to the exact size as the pixmap. */
+/* XXX LARGE pixmap? */
+Bool
+glamor_fixup_pixmap_priv(ScreenPtr screen, glamor_pixmap_private *pixmap_priv)
+{
+ glamor_pixmap_fbo *old_fbo;
+ glamor_pixmap_fbo *new_fbo = NULL;
+ PixmapPtr scratch = NULL;
+ glamor_pixmap_private *scratch_priv;
+ DrawablePtr drawable;
+ GCPtr gc = NULL;
+ int ret = FALSE;
+
+ drawable = &pixmap_priv->base.pixmap->drawable;
+
+ if (!GLAMOR_PIXMAP_FBO_NOT_EAXCT_SIZE(pixmap_priv))
+ return TRUE;
+
+ old_fbo = pixmap_priv->base.fbo;
+
+ if (!old_fbo)
+ return FALSE;
+
+ gc = GetScratchGC(drawable->depth, screen);
+ if (!gc)
+ goto fail;
+
+ scratch = glamor_create_pixmap(screen, drawable->width, drawable->height,
+ drawable->depth,
+ GLAMOR_CREATE_PIXMAP_FIXUP);
+
+ scratch_priv = glamor_get_pixmap_private(scratch);
+
+ if (!scratch_priv->base.fbo)
+ goto fail;
+
+ ValidateGC(&scratch->drawable, gc);
+ glamor_copy_area(drawable,
+ &scratch->drawable,
+ gc, 0, 0,
+ drawable->width, drawable->height,
+ 0, 0);
+ old_fbo = glamor_pixmap_detach_fbo(pixmap_priv);
+ new_fbo = glamor_pixmap_detach_fbo(scratch_priv);
+ glamor_pixmap_attach_fbo(pixmap_priv->base.pixmap, new_fbo);
+ glamor_pixmap_attach_fbo(scratch, old_fbo);
+
+ DEBUGF("old %dx%d type %d\n",
+ drawable->width, drawable->height, pixmap_priv->type);
+ DEBUGF("copy tex %d %dx%d to tex %d %dx%d \n",
+ old_fbo->tex, old_fbo->width, old_fbo->height, new_fbo->tex, new_fbo->width, new_fbo->height);
+ ret = TRUE;
+fail:
+ if (gc)
+ FreeScratchGC(gc);
+ if (scratch)
+ glamor_destroy_pixmap(scratch);
+
+ return ret;
+}
+
+/*
+ * We may use this function to reduce a large pixmap to a small sub
+ * pixmap. Two scenarios currently:
+ * 1. When fallback a large textured pixmap to CPU but we do need to
+ * do rendering within a small sub region, then we can just get a
+ * sub region.
+ *
+ * 2. When uploading a large pixmap to texture but we only need to
+ * use part of the source/mask picture. As glTexImage2D will be more
+ * efficient to upload a contingent region rather than a sub block
+ * in a large buffer. We use this function to gather the sub region
+ * to a contingent sub pixmap.
+ *
+ * The sub-pixmap must have the same format as the source pixmap.
+ *
+ * */
+PixmapPtr
+glamor_get_sub_pixmap(PixmapPtr pixmap, int x, int y, int w, int h, glamor_access_t access)
+{
+ glamor_screen_private *glamor_priv;
+ PixmapPtr sub_pixmap;
+ glamor_pixmap_private *sub_pixmap_priv, *pixmap_priv;
+ void *data;
+ int pbo;
+ int flag;
+ if (x < 0 || y < 0)
+ return NULL;
+ w = (x + w) > pixmap->drawable.width ? (pixmap->drawable.width - x) : w;
+ h = (y + h) > pixmap->drawable.height ? (pixmap->drawable.height - y) : h;
+ if (access == GLAMOR_ACCESS_WO) {
+ sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h,
+ pixmap->drawable.depth, GLAMOR_CREATE_PIXMAP_CPU);
+ return sub_pixmap;
+ }
+
+ glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ return NULL;
+ if (glamor_priv->gl_flavor == GLAMOR_GL_ES2 || pixmap_priv->type == GLAMOR_TEXTURE_LARGE)
+ flag = GLAMOR_CREATE_PIXMAP_CPU;
+ else
+ flag = GLAMOR_CREATE_PIXMAP_MAP;
+
+ sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h,
+ pixmap->drawable.depth, flag);
+
+ if (sub_pixmap == NULL)
+ return NULL;
+
+ sub_pixmap_priv = glamor_get_pixmap_private(sub_pixmap);
+ pbo = sub_pixmap_priv ? (sub_pixmap_priv->base.fbo ? sub_pixmap_priv->base.fbo->pbo : 0): 0;
+
+ if (pixmap_priv->base.is_picture) {
+ sub_pixmap_priv->base.picture = pixmap_priv->base.picture;
+ sub_pixmap_priv->base.is_picture = pixmap_priv->base.is_picture;
+ }
+
+ if (pbo)
+ data = NULL;
+ else
+ data = sub_pixmap->devPrivate.ptr;
+
+ data = glamor_download_sub_pixmap_to_cpu(pixmap, x, y, w, h, sub_pixmap->devKind,
+ data, pbo, access);
+ if(data == NULL) {
+ fbDestroyPixmap(sub_pixmap);
+ return NULL;
+ }
+ if (pbo) {
+ assert(sub_pixmap->devPrivate.ptr == NULL);
+ sub_pixmap->devPrivate.ptr = data;
+ sub_pixmap_priv->base.fbo->pbo_valid = 1;
+ }
+#if 0
+ struct pixman_box16 box;
+ PixmapPtr new_sub_pixmap;
+ int dx, dy;
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = w;
+ box.y2 = h;
+
+ dx = x;
+ dy = y;
+
+ new_sub_pixmap = glamor_create_pixmap(pixmap->drawable.pScreen, w, h,
+ pixmap->drawable.depth, GLAMOR_CREATE_PIXMAP_CPU);
+ glamor_copy_n_to_n(&pixmap->drawable, &new_sub_pixmap->drawable, NULL, &box, 1, dx, dy, 0, 0, 0, NULL);
+ glamor_compare_pixmaps(new_sub_pixmap, sub_pixmap, 0, 0, w, h, 1, 1);
+#endif
+
+ return sub_pixmap;
+}
+
+void
+glamor_put_sub_pixmap(PixmapPtr sub_pixmap, PixmapPtr pixmap, int x, int y, int w, int h, glamor_access_t access)
+{
+ void *bits;
+ int pbo;
+ glamor_pixmap_private *sub_pixmap_priv;
+ if (access != GLAMOR_ACCESS_RO) {
+ sub_pixmap_priv = glamor_get_pixmap_private(sub_pixmap);
+ if (sub_pixmap_priv->base.fbo
+ && sub_pixmap_priv->base.fbo->pbo_valid) {
+ bits = NULL;
+ pbo = sub_pixmap_priv->base.fbo->pbo;
+ } else {
+ bits = sub_pixmap->devPrivate.ptr;
+ pbo = 0;
+ }
+
+ assert(x >= 0 && y >= 0);
+ w = (w > sub_pixmap->drawable.width) ? sub_pixmap->drawable.width : w;
+ h = (h > sub_pixmap->drawable.height) ? sub_pixmap->drawable.height : h;
+ glamor_upload_sub_pixmap_to_texture(pixmap, x, y, w, h, sub_pixmap->devKind, bits, pbo);
+ }
+ glamor_destroy_pixmap(sub_pixmap);
+}
diff --git a/glamor/glamor_polyfillrect.c b/glamor/glamor_polyfillrect.c
new file mode 100644
index 000000000..4e1f7b3a9
--- /dev/null
+++ b/glamor/glamor_polyfillrect.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include "glamor_priv.h"
+
+/** @file glamor_fillspans.c
+ *
+ * GC PolyFillRect implementation, taken straight from fb_fill.c
+ */
+
+static Bool
+_glamor_poly_fill_rect(DrawablePtr drawable,
+ GCPtr gc, int nrect, xRectangle * prect, Bool fallback)
+{
+ int fullX1, fullX2, fullY1, fullY2;
+ int xorg, yorg;
+ int n;
+ register BoxPtr pbox;
+ RegionPtr pClip = fbGetCompositeClip(gc);
+ Bool ret = FALSE;
+
+ xorg = drawable->x;
+ yorg = drawable->y;
+
+ while (nrect--) {
+ fullX1 = prect->x + xorg;
+ fullY1 = prect->y + yorg;
+ fullX2 = fullX1 + (int) prect->width;
+ fullY2 = fullY1 + (int) prect->height;
+
+ n = REGION_NUM_RECTS(pClip);
+ pbox = REGION_RECTS(pClip);
+ /*
+ * clip the rectangle to each box in the clip region
+ * this is logically equivalent to calling Intersect(),
+ * but rectangles may overlap each other here.
+ */
+ while (n--) {
+ int x1 = fullX1;
+ int x2 = fullX2;
+ int y1 = fullY1;
+ int y2 = fullY2;
+
+ if (pbox->x1 > x1)
+ x1 = pbox->x1;
+ if (pbox->x2 < x2)
+ x2 = pbox->x2;
+ if (pbox->y1 > y1)
+ y1 = pbox->y1;
+ if (pbox->y2 < y2)
+ y2 = pbox->y2;
+
+ pbox++;
+ if (x1 >= x2 || y1 >= y2)
+ continue;
+ if (!glamor_fill(drawable, gc, x1, y1, x2 - x1,
+ y2 - y1, fallback)) {
+ nrect++;
+ goto fail;
+ }
+ }
+ prect++;
+ }
+ ret = TRUE;
+ goto done;
+
+fail:
+
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(drawable)
+ && glamor_ddx_fallback_check_gc(gc))
+ goto done;
+
+ glamor_fallback(" to %p (%c)\n",
+ drawable, glamor_get_drawable_location(drawable));
+ if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW)) {
+ if (glamor_prepare_access_gc(gc)) {
+ fbPolyFillRect(drawable, gc, nrect, prect);
+ glamor_finish_access_gc(gc);
+ }
+ glamor_finish_access(drawable, GLAMOR_ACCESS_RW);
+ }
+ ret = TRUE;
+
+done:
+ return ret;
+}
+
+
+void
+glamor_poly_fill_rect(DrawablePtr drawable,
+ GCPtr gc, int nrect, xRectangle * prect)
+{
+ _glamor_poly_fill_rect(drawable, gc, nrect, prect, TRUE);
+}
+
+Bool
+glamor_poly_fill_rect_nf(DrawablePtr drawable,
+ GCPtr gc, int nrect, xRectangle * prect)
+{
+ return _glamor_poly_fill_rect(drawable, gc, nrect, prect, FALSE);
+}
diff --git a/glamor/glamor_polylines.c b/glamor/glamor_polylines.c
new file mode 100644
index 000000000..e723e9500
--- /dev/null
+++ b/glamor/glamor_polylines.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include "glamor_priv.h"
+
+/** @file glamor_polylines.c
+ *
+ * GC PolyFillRect implementation, taken straight from fb_fill.c
+ */
+
+/**
+ * glamor_poly_lines() checks if it can accelerate the lines as a group of
+ * horizontal or vertical lines (rectangles), and uses existing rectangle fill
+ * acceleration if so.
+ */
+static Bool
+_glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n,
+ DDXPointPtr points, Bool fallback)
+{
+ xRectangle *rects;
+ int x1, x2, y1, y2;
+ int i;
+
+ /* Don't try to do wide lines or non-solid fill style. */
+ if (gc->lineWidth != 0) {
+ /* This ends up in miSetSpans, which is accelerated as well as we
+ * can hope X wide lines will be.
+ */
+ goto wide_line;
+ }
+ if (gc->lineStyle != LineSolid) {
+ glamor_fallback
+ ("non-solid fill line style %d\n",
+ gc->lineStyle);
+ goto fail;
+ }
+ rects = malloc(sizeof(xRectangle) * (n - 1));
+ x1 = points[0].x;
+ y1 = points[0].y;
+ /* If we have any non-horizontal/vertical, fall back. */
+ for (i = 0; i < n - 1; i++) {
+ if (mode == CoordModePrevious) {
+ x2 = x1 + points[i + 1].x;
+ y2 = y1 + points[i + 1].y;
+ } else {
+ x2 = points[i + 1].x;
+ y2 = points[i + 1].y;
+ }
+ if (x1 != x2 && y1 != y2) {
+ free(rects);
+ glamor_fallback("stub diagonal poly_line\n");
+ goto fail;
+ }
+ if (x1 < x2) {
+ rects[i].x = x1;
+ rects[i].width = x2 - x1 + 1;
+ } else {
+ rects[i].x = x2;
+ rects[i].width = x1 - x2 + 1;
+ }
+ if (y1 < y2) {
+ rects[i].y = y1;
+ rects[i].height = y2 - y1 + 1;
+ } else {
+ rects[i].y = y2;
+ rects[i].height = y1 - y2 + 1;
+ }
+
+ x1 = x2;
+ y1 = y2;
+ }
+ gc->ops->PolyFillRect(drawable, gc, n - 1, rects);
+ free(rects);
+ return TRUE;
+
+ fail:
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(drawable)
+ && glamor_ddx_fallback_check_gc(gc))
+ return FALSE;
+
+ if (gc->lineWidth == 0) {
+ if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW)) {
+ if (glamor_prepare_access_gc(gc)) {
+ fbPolyLine(drawable, gc, mode, n, points);
+ glamor_finish_access_gc(gc);
+ }
+ glamor_finish_access(drawable, GLAMOR_ACCESS_RW);
+ }
+ } else {
+wide_line:
+ /* fb calls mi functions in the lineWidth != 0 case. */
+ fbPolyLine(drawable, gc, mode, n, points);
+ }
+ return TRUE;
+}
+
+void
+glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n,
+ DDXPointPtr points)
+{
+ _glamor_poly_lines(drawable, gc, mode, n, points, TRUE);
+}
+
+Bool
+glamor_poly_lines_nf(DrawablePtr drawable, GCPtr gc, int mode, int n,
+ DDXPointPtr points)
+{
+ return _glamor_poly_lines(drawable, gc, mode, n, points, FALSE);
+}
diff --git a/glamor/glamor_polyops.c b/glamor/glamor_polyops.c
new file mode 100644
index 000000000..59301784d
--- /dev/null
+++ b/glamor/glamor_polyops.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ *
+ */
+
+#include "glamor_priv.h"
+
+static Bool
+_glamor_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt, Bool fallback)
+{
+ if (!fallback
+ && glamor_ddx_fallback_check_gc(pGC)
+ && glamor_ddx_fallback_check_pixmap(pDrawable))
+ return FALSE;
+
+ miPolyPoint(pDrawable, pGC, mode, npt, ppt);
+
+ return TRUE;
+}
+
+void
+glamor_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt)
+{
+ _glamor_poly_point(pDrawable, pGC, mode, npt, ppt, TRUE);
+}
+
+Bool
+glamor_poly_point_nf(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt)
+{
+ return _glamor_poly_point(pDrawable, pGC, mode, npt, ppt, FALSE);
+}
+
+static Bool
+_glamor_poly_segment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
+ xSegment *pSeg, Bool fallback)
+{
+ if (!fallback
+ && glamor_ddx_fallback_check_gc(pGC)
+ && glamor_ddx_fallback_check_pixmap(pDrawable))
+ return FALSE;
+
+ miPolySegment(pDrawable, pGC, nseg, pSeg);
+
+ return TRUE;
+}
+
+void
+glamor_poly_segment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
+ xSegment *pSeg)
+{
+ _glamor_poly_segment(pDrawable, pGC, nseg, pSeg, TRUE);
+}
+
+Bool
+glamor_poly_segment_nf(DrawablePtr pDrawable, GCPtr pGC, int nseg,
+ xSegment *pSeg)
+{
+ return _glamor_poly_segment(pDrawable, pGC, nseg, pSeg, FALSE);
+}
diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h
new file mode 100644
index 000000000..7b8f762c9
--- /dev/null
+++ b/glamor/glamor_priv.h
@@ -0,0 +1,1047 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+#ifndef GLAMOR_PRIV_H
+#define GLAMOR_PRIV_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "compiler.h"
+
+#include <xorg-server.h>
+#ifndef DEBUG
+#define NDEBUG
+#endif
+#include "glamor.h"
+#include "compat-api.h"
+
+#define GL_GLEXT_PROTOTYPES
+
+#ifdef GLAMOR_GLES2
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#define GLAMOR_DEFAULT_PRECISION "precision mediump float;\n"
+#include "glamor_glext.h"
+#else
+#include <GL/gl.h>
+#include <GL/glext.h>
+#define GLAMOR_DEFAULT_PRECISION
+#endif
+
+#ifdef RENDER
+#include "glyphstr.h"
+#endif
+
+#include "glamor_debug.h"
+
+#include <list.h>
+/* The list.h rename all the function to add xorg_ prefix.
+ We add hack here to avoid the compile error when using
+ old version xserver header file.
+ These will be removed in future. */
+#ifndef xorg_list_entry
+#define xorg_list list
+#define xorg_list_for_each_entry list_for_each_entry
+#define xorg_list_for_each_entry_safe list_for_each_entry_safe
+#define xorg_list_del list_del
+#define xorg_list_add list_add
+#define xorg_list_append list_append
+#define xorg_list_init list_init
+#endif
+
+struct glamor_pixmap_private;
+
+typedef struct glamor_composite_shader {
+ GLuint prog;
+ GLint dest_to_dest_uniform_location;
+ GLint dest_to_source_uniform_location;
+ GLint dest_to_mask_uniform_location;
+ GLint source_uniform_location;
+ GLint mask_uniform_location;
+ GLint source_wh;
+ GLint mask_wh;
+ GLint source_repeat_mode;
+ GLint mask_repeat_mode;
+ union {
+ float source_solid_color[4];
+ struct {
+ struct glamor_pixmap_private *source_priv;
+ PicturePtr source;
+ };
+ };
+
+ union {
+ float mask_solid_color[4];
+ struct {
+ struct glamor_pixmap_private *mask_priv;
+ PicturePtr mask;
+ };
+ };
+} glamor_composite_shader;
+
+enum shader_source {
+ SHADER_SOURCE_SOLID,
+ SHADER_SOURCE_TEXTURE,
+ SHADER_SOURCE_TEXTURE_ALPHA,
+ SHADER_SOURCE_COUNT,
+};
+
+enum shader_mask {
+ SHADER_MASK_NONE,
+ SHADER_MASK_SOLID,
+ SHADER_MASK_TEXTURE,
+ SHADER_MASK_TEXTURE_ALPHA,
+ SHADER_MASK_COUNT,
+};
+
+enum shader_in {
+ SHADER_IN_SOURCE_ONLY,
+ SHADER_IN_NORMAL,
+ SHADER_IN_CA_SOURCE,
+ SHADER_IN_CA_ALPHA,
+ SHADER_IN_COUNT,
+};
+
+struct shader_key {
+ enum shader_source source;
+ enum shader_mask mask;
+ enum shader_in in;
+};
+
+struct blendinfo {
+ Bool dest_alpha;
+ Bool source_alpha;
+ GLenum source_blend;
+ GLenum dest_blend;
+};
+
+typedef struct {
+ INT16 x_src;
+ INT16 y_src;
+ INT16 x_mask;
+ INT16 y_mask;
+ INT16 x_dst;
+ INT16 y_dst;
+ INT16 width;
+ INT16 height;
+} glamor_composite_rect_t;
+
+
+enum glamor_vertex_type {
+ GLAMOR_VERTEX_POS,
+ GLAMOR_VERTEX_SOURCE,
+ GLAMOR_VERTEX_MASK
+};
+
+
+enum gradient_shader {
+ SHADER_GRADIENT_LINEAR,
+ SHADER_GRADIENT_RADIAL,
+ SHADER_GRADIENT_CONICAL,
+ SHADER_GRADIENT_COUNT,
+};
+
+enum gradient_shader_prog {
+ SHADER_GRADIENT_VS_PROG,
+ SHADER_GRADIENT_FS_MAIN_PROG,
+ SHADER_GRADIENT_FS_GETCOLOR_PROG,
+ SHADER_GRADIENT_PROG_COUNT,
+};
+
+struct glamor_screen_private;
+struct glamor_pixmap_private;
+
+enum glamor_gl_flavor {
+ GLAMOR_GL_DESKTOP, // OPENGL API
+ GLAMOR_GL_ES2 // OPENGL ES2.0 API
+};
+
+#define GLAMOR_CREATE_PIXMAP_CPU 0x100
+#define GLAMOR_CREATE_PIXMAP_FIXUP 0x101
+#define GLAMOR_CREATE_FBO_NO_FBO 0x103
+#define GLAMOR_CREATE_PIXMAP_MAP 0x104
+
+#define GLAMOR_CREATE_TEXTURE_EXACT_SIZE 0x104
+
+#define GLAMOR_NUM_GLYPH_CACHE_FORMATS 2
+
+#define GLAMOR_COMPOSITE_VBO_VERT_CNT (64*1024)
+
+typedef struct {
+ PicturePtr picture; /* Where the glyphs of the cache are stored */
+ GlyphPtr *glyphs;
+ uint16_t count;
+ uint16_t evict;
+} glamor_glyph_cache_t;
+
+#include "glamor_gl_dispatch.h"
+
+struct glamor_saved_procs {
+ CloseScreenProcPtr close_screen;
+ CreateGCProcPtr create_gc;
+ CreatePixmapProcPtr create_pixmap;
+ DestroyPixmapProcPtr destroy_pixmap;
+ GetSpansProcPtr get_spans;
+ GetImageProcPtr get_image;
+ CompositeProcPtr composite;
+ CompositeRectsProcPtr composite_rects;
+ TrapezoidsProcPtr trapezoids;
+ GlyphsProcPtr glyphs;
+ ChangeWindowAttributesProcPtr change_window_attributes;
+ CopyWindowProcPtr copy_window;
+ BitmapToRegionProcPtr bitmap_to_region;
+ TrianglesProcPtr triangles;
+ AddTrapsProcPtr addtraps;
+ CreatePictureProcPtr create_picture;
+ DestroyPictureProcPtr destroy_picture;
+ UnrealizeGlyphProcPtr unrealize_glyph;
+ SetWindowPixmapProcPtr set_window_pixmap;
+};
+
+#ifdef GLAMOR_GLES2
+#define CACHE_FORMAT_COUNT 3
+#else
+#define CACHE_FORMAT_COUNT 2
+#endif
+
+#define CACHE_BUCKET_WCOUNT 4
+#define CACHE_BUCKET_HCOUNT 4
+
+#define GLAMOR_TICK_AFTER(t0, t1) \
+ (((int)(t1) - (int)(t0)) < 0)
+
+#define IDLE_STATE 0
+#define RENDER_STATE 1
+#define BLIT_STATE 2
+#define RENDER_IDEL_MAX 32
+
+typedef struct glamor_screen_private {
+ struct glamor_gl_dispatch _dispatch;
+ int yInverted;
+ unsigned int tick;
+ enum glamor_gl_flavor gl_flavor;
+ int has_pack_invert;
+ int has_fbo_blit;
+ int max_fbo_size;
+
+ struct xorg_list fbo_cache[CACHE_FORMAT_COUNT][CACHE_BUCKET_WCOUNT][CACHE_BUCKET_HCOUNT];
+ unsigned long fbo_cache_watermark;
+
+ /* glamor_solid */
+ GLint solid_prog;
+ GLint solid_color_uniform_location;
+
+ /* vertext/elment_index buffer object for render */
+ GLuint vbo, ebo;
+ int vbo_offset;
+ int vbo_size;
+ char *vb;
+ int vb_stride;
+ Bool has_source_coords, has_mask_coords;
+ int render_nr_verts;
+ glamor_composite_shader composite_shader[SHADER_SOURCE_COUNT]
+ [SHADER_MASK_COUNT]
+ [SHADER_IN_COUNT];
+ glamor_glyph_cache_t glyphCaches[GLAMOR_NUM_GLYPH_CACHE_FORMATS];
+ Bool glyph_cache_initialized;
+
+ /* shaders to restore a texture to another texture.*/
+ GLint finish_access_prog[2];
+ GLint finish_access_revert[2];
+ GLint finish_access_swap_rb[2];
+
+ /* glamor_tile */
+ GLint tile_prog;
+ GLint tile_wh;
+
+ /* glamor gradient, 0 for small nstops, 1 for
+ large nstops and 2 for dynamic generate. */
+ GLint gradient_prog[SHADER_GRADIENT_COUNT][3];
+ GLint linear_gradient_shaders[SHADER_GRADIENT_PROG_COUNT][3];
+ int linear_max_nstops;
+ GLint radial_gradient_shaders[SHADER_GRADIENT_PROG_COUNT][3];
+ int radial_max_nstops;
+
+ /* glamor trapezoid shader. */
+ GLint trapezoid_prog;
+
+ /* glamor_putimage */
+ GLint put_image_xybitmap_prog;
+ GLint put_image_xybitmap_fg_uniform_location;
+ GLint put_image_xybitmap_bg_uniform_location;
+
+ PixmapPtr *back_pixmap;
+ int screen_fbo;
+ struct glamor_saved_procs saved_procs;
+ char delayed_fallback_string[GLAMOR_DELAYED_STRING_MAX + 1];
+ int delayed_fallback_pending;
+ int flags;
+ int state;
+ unsigned int render_idle_cnt;
+ ScreenPtr screen;
+ int dri3_enabled;
+
+ /* xv */
+ GLint xv_prog;
+} glamor_screen_private;
+
+typedef enum glamor_access {
+ GLAMOR_ACCESS_RO,
+ GLAMOR_ACCESS_RW,
+ GLAMOR_ACCESS_WO,
+} glamor_access_t;
+
+#define GLAMOR_FBO_NORMAL 1
+#define GLAMOR_FBO_DOWNLOADED 2
+/* glamor_pixmap_fbo:
+ * @list: to be used to link to the cache pool list.
+ * @expire: when push to cache pool list, set a expire count.
+ * will be freed when glamor_priv->tick is equal or
+ * larger than this expire count in block handler.
+ * @pbo_valid: The pbo has a valid copy of the pixmap's data.
+ * @tex: attached texture.
+ * @fb: attached fbo.
+ * @pbo: attached pbo.
+ * @width: width of this fbo.
+ * @height: height of this fbo.
+ * @format: internal format of this fbo's texture.
+ * @type: internal type of this fbo's texture.
+ * @glamor_priv: point to glamor private data.
+ */
+typedef struct glamor_pixmap_fbo {
+ struct xorg_list list;
+ unsigned int expire;
+ unsigned char pbo_valid;
+ GLuint tex;
+ GLuint fb;
+ GLuint pbo;
+ int width;
+ int height;
+ GLenum format;
+ GLenum type;
+ glamor_screen_private *glamor_priv;
+} glamor_pixmap_fbo;
+
+/*
+ * glamor_pixmap_private - glamor pixmap's private structure.
+ * @gl_fbo:
+ * 0 - The pixmap doesn't has a fbo attached to it.
+ * GLAMOR_FBO_NORMAL - The pixmap has a fbo and can be accessed normally.
+ * GLAMOR_FBO_DOWNLOADED - The pixmap has a fbo and already downloaded to
+ * CPU, so it can only be treated as a in-memory pixmap
+ * if this bit is set.
+ * @gl_tex: The pixmap is in a gl texture originally.
+ * @is_picture: The drawable is attached to a picture.
+ * @pict_format: the corresponding picture's format.
+ * @pixmap: The corresponding pixmap's pointer.
+ *
+ * For GLAMOR_TEXTURE_LARGE, nbox should larger than 1.
+ * And the box and fbo will both have nbox elements.
+ * and box[i] store the relatively coords in this pixmap
+ * of the fbo[i]. The reason why use boxes not region to
+ * represent this structure is we may need to use overlapped
+ * boxes for one pixmap for some special reason.
+ *
+ * pixmap
+ * ******************
+ * * fbo0 * fbo1 *
+ * * * *
+ * ******************
+ * * fbo2 * fbo3 *
+ * * * *
+ * ******************
+ *
+ * Let's assume the texture has size of 1024x1024
+ * box[0] = {0,0,1024,1024}
+ * box[1] = {1024,0,2048,2048}
+ * ...
+ *
+ * For GLAMOR_TEXTURE_ATLAS nbox should be 1. And box
+ * and fbo both has one elements, and the box store
+ * the relatively coords in the fbo of this pixmap:
+ *
+ * fbo
+ * ******************
+ * * pixmap *
+ * * ********* *
+ * * * * *
+ * * ********* *
+ * * *
+ * ******************
+ *
+ * Assume the pixmap is at the (100,100) relatively to
+ * the fbo's origin.
+ * box[0]={100, 100, 1124, 1124};
+ *
+ * Considering large pixmap is not a normal case, to keep
+ * it simple, I designe it as the following way.
+ * When deal with a large pixmap, it split the working
+ * rectangle into serval boxes, and each box fit into a
+ * corresponding fbo. And then the rendering function will
+ * loop from the left-top box to the right-bottom box,
+ * each time, we will set current box and current fbo
+ * to the box and fbo elements. Thus the inner routines
+ * can handle it as normal, only the coords calculation need
+ * to aware of it's large pixmap.
+ *
+ * Currently, we haven't implemented the atlas pixmap.
+ *
+ **/
+
+typedef struct glamor_pixmap_clipped_regions{
+ int block_idx;
+ RegionPtr region;
+} glamor_pixmap_clipped_regions;
+
+#define SET_PIXMAP_FBO_CURRENT(priv, idx) \
+ do { \
+ if (priv->type == GLAMOR_TEXTURE_LARGE) { \
+ (priv)->large.base.fbo = priv->large.fbo_array[idx]; \
+ (priv)->large.box = priv->large.box_array[idx]; \
+ } \
+ } while(0)
+
+typedef struct glamor_pixmap_private_base {
+ glamor_pixmap_type_t type;
+ unsigned char gl_fbo:2;
+ unsigned char is_picture:1;
+ unsigned char gl_tex:1;
+ glamor_pixmap_fbo *fbo;
+ PixmapPtr pixmap;
+ int drm_stride;
+ glamor_screen_private *glamor_priv;
+ PicturePtr picture;
+}glamor_pixmap_private_base_t;
+
+/*
+ * @base.fbo: current fbo.
+ * @box: current fbo's coords in the whole pixmap.
+ * @block_w: block width of this large pixmap.
+ * @block_h: block height of this large pixmap.
+ * @block_wcnt: block count in one block row.
+ * @block_hcnt: block count in one block column.
+ * @nbox: total block count.
+ * @box_array: contains each block's corresponding box.
+ * @fbo_array: contains each block's fbo pointer.
+ *
+ **/
+typedef struct glamor_pixmap_private_large {
+ union {
+ glamor_pixmap_type_t type;
+ glamor_pixmap_private_base_t base;
+ };
+ BoxRec box;
+ int block_w;
+ int block_h;
+ int block_wcnt;
+ int block_hcnt;
+ int nbox;
+ BoxPtr box_array;
+ glamor_pixmap_fbo **fbo_array;
+}glamor_pixmap_private_large_t;
+
+/*
+ * @box: the relative coords in the corresponding fbo.
+ */
+typedef struct glamor_pixmap_private_atlas {
+ union {
+ glamor_pixmap_type_t type;
+ glamor_pixmap_private_base_t base;
+ };
+ BoxRec box;
+}glamor_pixmap_private_atlas_t;
+
+typedef struct glamor_pixmap_private {
+ union {
+ glamor_pixmap_type_t type;
+ glamor_pixmap_private_base_t base;
+ glamor_pixmap_private_large_t large;
+ glamor_pixmap_private_atlas_t atlas;
+ };
+}glamor_pixmap_private;
+
+/*
+ * Pixmap dynamic status, used by dynamic upload feature.
+ *
+ * GLAMOR_NONE: initial status, don't need to do anything.
+ * GLAMOR_UPLOAD_PENDING: marked as need to be uploaded to gl texture.
+ * GLAMOR_UPLOAD_DONE: the pixmap has been uploaded successfully.
+ * GLAMOR_UPLOAD_FAILED: fail to upload the pixmap.
+ *
+ * */
+typedef enum glamor_pixmap_status {
+ GLAMOR_NONE,
+ GLAMOR_UPLOAD_PENDING,
+ GLAMOR_UPLOAD_DONE,
+ GLAMOR_UPLOAD_FAILED
+} glamor_pixmap_status_t;
+
+extern DevPrivateKey glamor_screen_private_key;
+extern DevPrivateKey glamor_pixmap_private_key;
+static inline glamor_screen_private *
+glamor_get_screen_private(ScreenPtr screen)
+{
+ return (glamor_screen_private *)
+ dixLookupPrivate(&screen->devPrivates,
+ glamor_screen_private_key);
+}
+
+static inline void
+glamor_set_screen_private(ScreenPtr screen, glamor_screen_private *priv)
+{
+ dixSetPrivate(&screen->devPrivates,
+ glamor_screen_private_key,
+ priv);
+}
+
+
+
+static inline glamor_pixmap_private *
+glamor_get_pixmap_private(PixmapPtr pixmap)
+{
+ glamor_pixmap_private *priv;
+ priv = dixLookupPrivate(&pixmap->devPrivates,
+ glamor_pixmap_private_key);
+ if (!priv) {
+ glamor_set_pixmap_type(pixmap, GLAMOR_MEMORY);
+ priv = dixLookupPrivate(&pixmap->devPrivates,
+ glamor_pixmap_private_key);
+ }
+ return priv;
+}
+
+void glamor_set_pixmap_private(PixmapPtr pixmap, glamor_pixmap_private *priv);
+
+/**
+ * Returns TRUE if the given planemask covers all the significant bits in the
+ * pixel values for pDrawable.
+ */
+static inline Bool
+glamor_pm_is_solid(DrawablePtr drawable, unsigned long planemask)
+{
+ return (planemask & FbFullMask(drawable->depth)) ==
+ FbFullMask(drawable->depth);
+}
+
+extern int glamor_debug_level;
+
+/* glamor.c */
+PixmapPtr glamor_get_drawable_pixmap(DrawablePtr drawable);
+
+Bool glamor_destroy_pixmap(PixmapPtr pixmap);
+
+glamor_pixmap_fbo* glamor_pixmap_detach_fbo(glamor_pixmap_private *pixmap_priv);
+void glamor_pixmap_attach_fbo(PixmapPtr pixmap, glamor_pixmap_fbo *fbo);
+glamor_pixmap_fbo * glamor_create_fbo_from_tex(glamor_screen_private *glamor_priv,
+ int w, int h, GLenum format, GLint tex, int flag);
+glamor_pixmap_fbo * glamor_create_fbo(glamor_screen_private *glamor_priv,
+ int w, int h, GLenum format, int flag);
+void glamor_destroy_fbo(glamor_pixmap_fbo *fbo);
+void glamor_pixmap_destroy_fbo(glamor_pixmap_private *priv);
+void glamor_purge_fbo(glamor_pixmap_fbo *fbo);
+
+void glamor_init_pixmap_fbo(ScreenPtr screen);
+void glamor_fini_pixmap_fbo(ScreenPtr screen);
+Bool glamor_pixmap_fbo_fixup(ScreenPtr screen, PixmapPtr pixmap);
+void glamor_fbo_expire(glamor_screen_private *glamor_priv);
+
+glamor_pixmap_fbo *
+glamor_create_fbo_array(glamor_screen_private *glamor_priv,
+ int w, int h, GLenum format, int flag,
+ int block_w, int block_h, glamor_pixmap_private *);
+
+/* glamor_copyarea.c */
+RegionPtr
+glamor_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
+ int srcx, int srcy, int width, int height, int dstx,
+ int dsty);
+void glamor_copy_n_to_n(DrawablePtr src, DrawablePtr dst, GCPtr gc,
+ BoxPtr box, int nbox, int dx, int dy, Bool reverse,
+ Bool upsidedown, Pixel bitplane, void *closure);
+
+/* glamor_copywindow.c */
+void glamor_copy_window(WindowPtr win, DDXPointRec old_origin,
+ RegionPtr src_region);
+
+/* glamor_core.c */
+Bool glamor_prepare_access(DrawablePtr drawable, glamor_access_t access);
+void glamor_finish_access(DrawablePtr drawable, glamor_access_t access);
+Bool glamor_prepare_access_window(WindowPtr window);
+void glamor_finish_access_window(WindowPtr window);
+Bool glamor_prepare_access_gc(GCPtr gc);
+void glamor_finish_access_gc(GCPtr gc);
+void glamor_init_finish_access_shaders(ScreenPtr screen);
+void glamor_fini_finish_access_shaders(ScreenPtr screen);
+const Bool glamor_get_drawable_location(const DrawablePtr drawable);
+void glamor_get_drawable_deltas(DrawablePtr drawable, PixmapPtr pixmap,
+ int *x, int *y);
+Bool glamor_stipple(PixmapPtr pixmap, PixmapPtr stipple,
+ int x, int y, int width, int height,
+ unsigned char alu, unsigned long planemask,
+ unsigned long fg_pixel, unsigned long bg_pixel,
+ int stipple_x, int stipple_y);
+GLint glamor_compile_glsl_prog(glamor_gl_dispatch * dispatch, GLenum type,
+ const char *source);
+void glamor_link_glsl_prog(glamor_gl_dispatch * dispatch, GLint prog);
+void glamor_get_color_4f_from_pixel(PixmapPtr pixmap,
+ unsigned long fg_pixel,
+ GLfloat * color);
+
+int glamor_set_destination_pixmap(PixmapPtr pixmap);
+int glamor_set_destination_pixmap_priv(glamor_pixmap_private *
+ pixmap_priv);
+void glamor_set_destination_pixmap_fbo(glamor_pixmap_fbo *, int, int, int, int);
+
+/* nc means no check. caller must ensure this pixmap has valid fbo.
+ * usually use the GLAMOR_PIXMAP_PRIV_HAS_FBO firstly.
+ * */
+void glamor_set_destination_pixmap_priv_nc(glamor_pixmap_private *
+ pixmap_priv);
+
+glamor_pixmap_fbo *
+glamor_es2_pixmap_read_prepare(PixmapPtr source, int x, int y, int w, int h, GLenum format,
+ GLenum type, int no_alpha, int revert, int swap_rb);
+
+Bool glamor_set_alu(struct glamor_gl_dispatch *dispatch,
+ unsigned char alu);
+Bool glamor_set_planemask(PixmapPtr pixmap, unsigned long planemask);
+Bool glamor_change_window_attributes(WindowPtr pWin, unsigned long mask);
+RegionPtr glamor_bitmap_to_region(PixmapPtr pixmap);
+Bool glamor_gl_has_extension(const char *extension);
+int glamor_gl_get_version(void);
+
+#define GLAMOR_GL_VERSION_ENCODE(major, minor) ( \
+ ((major) * 256) \
+ + ((minor) * 1))
+
+
+
+
+/* glamor_fill.c */
+Bool glamor_fill(DrawablePtr drawable,
+ GCPtr gc, int x, int y, int width, int height, Bool fallback);
+Bool glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
+ unsigned char alu, unsigned long planemask,
+ unsigned long fg_pixel);
+Bool
+glamor_solid_boxes(PixmapPtr pixmap,
+ BoxPtr box, int nbox,
+ unsigned long fg_pixel);
+
+/* glamor_fillspans.c */
+void glamor_fill_spans(DrawablePtr drawable,
+ GCPtr gc,
+ int n, DDXPointPtr points, int *widths, int sorted);
+
+void glamor_init_solid_shader(ScreenPtr screen);
+void glamor_fini_solid_shader(ScreenPtr screen);
+
+/* glamor_getspans.c */
+void
+
+glamor_get_spans(DrawablePtr drawable,
+ int wmax,
+ DDXPointPtr points,
+ int *widths, int nspans, char *dst_start);
+
+/* glamor_glyphs.c */
+void glamor_glyphs_fini(ScreenPtr screen);
+void glamor_glyphs(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc,
+ INT16 ySrc, int nlist, GlyphListPtr list,
+ GlyphPtr * glyphs);
+
+/* glamor_setspans.c */
+void glamor_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
+ DDXPointPtr points, int *widths, int n, int sorted);
+
+/* glamor_polyfillrect.c */
+void
+glamor_poly_fill_rect(DrawablePtr drawable,
+ GCPtr gc, int nrect, xRectangle * prect);
+
+/* glamor_polylines.c */
+void
+
+glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n,
+ DDXPointPtr points);
+
+/* glamor_putimage.c */
+void
+
+glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
+ int w, int h, int leftPad, int format, char *bits);
+void glamor_init_putimage_shaders(ScreenPtr screen);
+void glamor_fini_putimage_shaders(ScreenPtr screen);
+
+/* glamor_render.c */
+Bool
+glamor_composite_clipped_region(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ glamor_pixmap_private *soruce_pixmap_priv,
+ glamor_pixmap_private *mask_pixmap_priv,
+ glamor_pixmap_private *dest_pixmap_priv,
+ RegionPtr region,
+ int x_source,
+ int y_source,
+ int x_mask,
+ int y_mask,
+ int x_dest,
+ int y_dest);
+
+void glamor_composite(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
+
+void glamor_init_composite_shaders(ScreenPtr screen);
+void glamor_fini_composite_shaders(ScreenPtr screen);
+void glamor_composite_glyph_rects(CARD8 op,
+ PicturePtr src, PicturePtr mask,
+ PicturePtr dst, int nrect,
+ glamor_composite_rect_t * rects);
+void glamor_composite_rects (CARD8 op,
+ PicturePtr pDst,
+ xRenderColor *color,
+ int nRect,
+ xRectangle *rects);
+void glamor_init_trapezoid_shader(ScreenPtr screen);
+void glamor_fini_trapezoid_shader(ScreenPtr screen);
+PicturePtr glamor_convert_gradient_picture(ScreenPtr screen,
+ PicturePtr source,
+ int x_source,
+ int y_source, int width, int height);
+
+Bool glamor_composite_choose_shader(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ glamor_pixmap_private *source_pixmap_priv,
+ glamor_pixmap_private *mask_pixmap_priv,
+ glamor_pixmap_private *dest_pixmap_priv,
+ struct shader_key *s_key,
+ glamor_composite_shader **shader,
+ struct blendinfo *op_info,
+ PictFormatShort *psaved_source_format);
+
+void
+glamor_composite_set_shader_blend(glamor_pixmap_private *dest_priv,
+ struct shader_key *key,
+ glamor_composite_shader *shader,
+ struct blendinfo *op_info);
+
+void glamor_setup_composite_vbo(ScreenPtr screen, int n_verts);
+void glamor_emit_composite_vert(ScreenPtr screen,
+ const float *src_coords,
+ const float *mask_coords,
+ const float *dst_coords, int i);
+
+/* glamor_trapezoid.c */
+void glamor_trapezoids(CARD8 op,
+ PicturePtr src, PicturePtr dst,
+ PictFormatPtr mask_format, INT16 x_src, INT16 y_src,
+ int ntrap, xTrapezoid * traps);
+
+/* glamor_tile.c */
+Bool glamor_tile(PixmapPtr pixmap, PixmapPtr tile,
+ int x, int y, int width, int height,
+ unsigned char alu, unsigned long planemask,
+ int tile_x, int tile_y);
+void glamor_init_tile_shader(ScreenPtr screen);
+void glamor_fini_tile_shader(ScreenPtr screen);
+
+/* glamor_gradient.c */
+void glamor_init_gradient_shader(ScreenPtr screen);
+void glamor_fini_gradient_shader(ScreenPtr screen);
+PicturePtr glamor_generate_linear_gradient_picture(ScreenPtr screen,
+ PicturePtr src_picture,
+ int x_source, int y_source,
+ int width, int height,
+ PictFormatShort format);
+PicturePtr glamor_generate_radial_gradient_picture(ScreenPtr screen,
+ PicturePtr src_picture,
+ int x_source, int y_source,
+ int width, int height,
+ PictFormatShort format);
+
+/* glamor_triangles.c */
+void
+
+glamor_triangles(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc, INT16 ySrc, int ntris, xTriangle * tris);
+
+/* glamor_pixmap.c */
+
+void glamor_pixmap_init(ScreenPtr screen);
+void glamor_pixmap_fini(ScreenPtr screen);
+/**
+ * Download a pixmap's texture to cpu memory. If success,
+ * One copy of current pixmap's texture will be put into
+ * the pixmap->devPrivate.ptr. Will use pbo to map to
+ * the pointer if possible.
+ * The pixmap must be a gl texture pixmap. gl_fbo and
+ * gl_tex must be 1. Used by glamor_prepare_access.
+ *
+ */
+Bool glamor_download_pixmap_to_cpu(PixmapPtr pixmap,
+ glamor_access_t access);
+
+void *
+glamor_download_sub_pixmap_to_cpu(PixmapPtr pixmap, int x, int y, int w, int h,
+ int stride, void *bits, int pbo, glamor_access_t access);
+
+
+/**
+ * Restore a pixmap's data which is downloaded by
+ * glamor_download_pixmap_to_cpu to its original
+ * gl texture. Used by glamor_finish_access.
+ *
+ * The pixmap must be
+ * in texture originally. In other word, the gl_fbo
+ * must be 1.
+ **/
+void glamor_restore_pixmap_to_texture(PixmapPtr pixmap);
+
+/**
+ * According to the flag,
+ * if the flag is GLAMOR_CREATE_FBO_NO_FBO then just ensure
+ * the fbo has a valid texture. Otherwise, it will ensure
+ * the fbo has valid texture and attach to a valid fb.
+ * If the fbo already has a valid glfbo then do nothing.
+ */
+Bool
+glamor_pixmap_ensure_fbo(PixmapPtr pixmap, GLenum format, int flag);
+
+/**
+ * Upload a pixmap to gl texture. Used by dynamic pixmap
+ * uploading feature. The pixmap must be a software pixmap.
+ * This function will change current FBO and current shaders.
+ */
+enum glamor_pixmap_status glamor_upload_pixmap_to_texture(PixmapPtr
+ pixmap);
+
+Bool
+glamor_upload_sub_pixmap_to_texture(PixmapPtr pixmap, int x, int y, int w, int h,
+ int stride, void *bits, int pbo);
+
+PixmapPtr
+glamor_get_sub_pixmap(PixmapPtr pixmap, int x, int y,
+ int w, int h, glamor_access_t access);
+void
+glamor_put_sub_pixmap(PixmapPtr sub_pixmap, PixmapPtr pixmap, int x, int y,
+ int w, int h, glamor_access_t access);
+
+glamor_pixmap_clipped_regions *
+glamor_compute_clipped_regions(glamor_pixmap_private *priv, RegionPtr region,
+ int *clipped_nbox, int repeat_type,
+ int reverse, int upsidedown);
+
+glamor_pixmap_clipped_regions *
+glamor_compute_clipped_regions_ext(glamor_pixmap_private *pixmap_priv,
+ RegionPtr region,
+ int *n_region,
+ int inner_block_w, int inner_block_h,
+ int reverse, int upsidedown);
+
+glamor_pixmap_clipped_regions *
+glamor_compute_transform_clipped_regions(glamor_pixmap_private *priv, struct pixman_transform *transform,
+ RegionPtr region, int *n_region, int dx, int dy, int repeat_type,
+ int reverse, int upsidedown);
+
+Bool
+glamor_composite_largepixmap_region(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ glamor_pixmap_private * source_pixmap_priv,
+ glamor_pixmap_private * mask_pixmap_priv,
+ glamor_pixmap_private * dest_pixmap_priv,
+ RegionPtr region, Bool force_clip,
+ INT16 x_source,
+ INT16 y_source,
+ INT16 x_mask,
+ INT16 y_mask,
+ INT16 x_dest, INT16 y_dest,
+ CARD16 width, CARD16 height);
+
+Bool
+glamor_get_transform_block_size(struct pixman_transform *transform,
+ int block_w, int block_h,
+ int *transformed_block_w,
+ int *transformed_block_h);
+
+void
+glamor_get_transform_extent_from_box(struct pixman_box32 *temp_box,
+ struct pixman_transform *transform);
+
+/**
+ * Upload a picture to gl texture. Similar to the
+ * glamor_upload_pixmap_to_texture. Used in rendering.
+ **/
+enum glamor_pixmap_status
+ glamor_upload_picture_to_texture(PicturePtr picture);
+
+/**
+ * Upload bits to a pixmap's texture. This function will
+ * convert the bits to the specified format/type format
+ * if the conversion is unavoidable.
+ **/
+Bool glamor_upload_bits_to_pixmap_texture(PixmapPtr pixmap, GLenum format, GLenum type,
+ int no_alpha, int revert, int swap_rb, void *bits);
+
+/**
+ * Destroy all the resources allocated on the uploading
+ * phase, includs the tex and fbo.
+ **/
+void glamor_destroy_upload_pixmap(PixmapPtr pixmap);
+
+int glamor_create_picture(PicturePtr picture);
+
+void glamor_set_window_pixmap(WindowPtr pWindow, PixmapPtr pPixmap);
+
+Bool
+glamor_prepare_access_picture(PicturePtr picture, glamor_access_t access);
+
+void glamor_finish_access_picture(PicturePtr picture, glamor_access_t access);
+
+void glamor_destroy_picture(PicturePtr picture);
+
+/* fixup a fbo to the exact size as the pixmap. */
+Bool
+glamor_fixup_pixmap_priv(ScreenPtr screen, glamor_pixmap_private *pixmap_priv);
+
+void
+glamor_picture_format_fixup(PicturePtr picture,
+ glamor_pixmap_private * pixmap_priv);
+
+void
+glamor_get_image(DrawablePtr pDrawable, int x, int y, int w, int h,
+ unsigned int format, unsigned long planeMask, char *d);
+
+void
+glamor_add_traps(PicturePtr pPicture,
+ INT16 x_off,
+ INT16 y_off, int ntrap, xTrap * traps);
+
+RegionPtr
+glamor_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty,
+ unsigned long bitPlane);
+
+void
+glamor_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr * ppci, pointer pglyphBase);
+
+void
+glamor_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr * ppci, pointer pglyphBase);
+
+void
+glamor_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable, int w, int h, int x, int y);
+
+void
+glamor_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt);
+
+void
+glamor_poly_segment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
+ xSegment *pSeg);
+
+void
+glamor_poly_line(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt);
+
+void
+glamor_composite_rectangles(CARD8 op,
+ PicturePtr dst,
+ xRenderColor *color,
+ int num_rects,
+ xRectangle *rects);
+
+/* glamor_xv */
+typedef struct {
+ uint32_t transform_index;
+ uint32_t gamma; /* gamma value x 1000 */
+ int brightness;
+ int saturation;
+ int hue;
+ int contrast;
+
+ DrawablePtr pDraw;
+ PixmapPtr pPixmap;
+ uint32_t src_pitch;
+ uint8_t *src_addr;
+ int src_w, src_h, dst_w, dst_h;
+ int src_x, src_y, drw_x, drw_y;
+ int w, h;
+ RegionRec clip;
+ PixmapPtr src_pix[3]; /* y, u, v for planar */
+ int src_pix_w, src_pix_h;
+} glamor_port_private;
+
+void glamor_init_xv_shader(ScreenPtr screen);
+void glamor_fini_xv_shader(ScreenPtr screen);
+
+#include"glamor_utils.h"
+
+/* Dynamic pixmap upload to texture if needed.
+ * Sometimes, the target is a gl texture pixmap/picture,
+ * but the source or mask is in cpu memory. In that case,
+ * upload the source/mask to gl texture and then avoid
+ * fallback the whole process to cpu. Most of the time,
+ * this will increase performance obviously. */
+
+#define GLAMOR_PIXMAP_DYNAMIC_UPLOAD
+#define GLAMOR_GRADIENT_SHADER
+#define GLAMOR_TRAPEZOID_SHADER
+#define GLAMOR_TEXTURED_LARGE_PIXMAP 1
+#define WALKAROUND_LARGE_TEXTURE_MAP
+#if 0
+#define MAX_FBO_SIZE 32 /* For test purpose only. */
+#endif
+//#define GLYPHS_NO_EDEGEMAP_OVERLAP_CHECK
+#define GLYPHS_EDEGE_OVERLAP_LOOSE_CHECK
+
+#endif /* GLAMOR_PRIV_H */
diff --git a/glamor/glamor_putimage.c b/glamor/glamor_putimage.c
new file mode 100644
index 000000000..99f7ac6f5
--- /dev/null
+++ b/glamor/glamor_putimage.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ *
+ */
+
+
+/** @file glamor_putaimge.c
+ *
+ * XPutImage implementation
+ */
+#include "glamor_priv.h"
+
+void
+glamor_init_putimage_shaders(ScreenPtr screen)
+{
+#if 0
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ const char *xybitmap_vs =
+ "uniform float x_bias;\n" "uniform float x_scale;\n"
+ "uniform float y_bias;\n" "uniform float y_scale;\n"
+ "varying vec2 bitmap_coords;\n" "void main()\n" "{\n"
+ " gl_Position = vec4((gl_Vertex.x + x_bias) * x_scale,\n"
+ " (gl_Vertex.y + y_bias) * y_scale,\n"
+ " 0,\n"
+ " 1);\n"
+ " bitmap_coords = gl_MultiTexCoord0.xy;\n" "}\n";
+ const char *xybitmap_fs =
+ "uniform vec4 fg, bg;\n" "varying vec2 bitmap_coords;\n"
+ "uniform sampler2D bitmap_sampler;\n" "void main()\n" "{\n"
+ " float bitmap_value = texture2D(bitmap_sampler,\n"
+ " bitmap_coords).x;\n"
+ " gl_FragColor = mix(bg, fg, bitmap_value);\n" "}\n";
+ GLint fs_prog, vs_prog, prog;
+ GLint sampler_uniform_location;
+
+ if (!GLEW_ARB_fragment_shader)
+ return;
+
+ prog = dispatch->glCreateProgram();
+ vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, xybitmap_vs);
+ fs_prog =
+ glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, xybitmap_fs);
+ dispatch->glAttachShader(prog, vs_prog);
+ dispatch->glAttachShader(prog, fs_prog);
+ glamor_link_glsl_prog(prog);
+
+ dispatch->glUseProgram(prog);
+ sampler_uniform_location =
+ dispatch->glGetUniformLocation(prog, "bitmap_sampler");
+ dispatch->glUniform1i(sampler_uniform_location, 0);
+
+ glamor_priv->put_image_xybitmap_fg_uniform_location =
+ dispatch->glGetUniformLocation(prog, "fg");
+ glamor_priv->put_image_xybitmap_bg_uniform_location =
+ dispatch->glGetUniformLocation(prog, "bg");
+ glamor_get_transform_uniform_locations(prog,
+ &glamor_priv->put_image_xybitmap_transform);
+ glamor_priv->put_image_xybitmap_prog = prog;
+ dispatch->glUseProgram(0);
+#endif
+}
+
+
+/* Do an XYBitmap putimage. The bits are byte-aligned rows of bitmap
+ * data (where each row starts at a bit index of left_pad), and the
+ * destination gets filled with the gc's fg color where the bitmap is set
+ * and the bg color where the bitmap is unset.
+ *
+ * Implement this by passing the bitmap right through to GL, and sampling
+ * it to choose between fg and bg in the fragment shader. The driver may
+ * be exploding the bitmap up to be an 8-bit alpha texture, in which
+ * case we might be better off just doing the fg/bg choosing in the CPU
+ * and just draw the resulting texture to the destination.
+ */
+#if 0
+
+static int
+y_flip(PixmapPtr pixmap, int y)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen);
+
+ if (pixmap == screen_pixmap)
+ return (pixmap->drawable.height - 1) - y;
+ else
+ return y;
+}
+
+
+static void
+glamor_put_image_xybitmap(DrawablePtr drawable, GCPtr gc,
+ int x, int y, int w, int h, int left_pad,
+ int image_format, char *bits)
+{
+ ScreenPtr screen = drawable->pScreen;
+ PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ float fg[4], bg[4];
+ GLuint tex;
+ unsigned int stride = PixmapBytePad(1, w + left_pad);
+ RegionPtr clip;
+ BoxPtr box;
+ int nbox;
+ float dest_coords[8];
+ const float bitmap_coords[8] = {
+ 0.0, 0.0,
+ 1.0, 0.0,
+ 1.0, 1.0,
+ 0.0, 1.0,
+ };
+ GLfloat xscale, yscale;
+ glamor_pixmap_private *pixmap_priv;
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ pixmap_priv_get_scale(pixmap_priv, &xscale, &yscale);
+
+ glamor_set_normalize_vcoords(xscale, yscale,
+ x, y,
+ x + w, y + h,
+ glamor_priv->yInverted, dest_coords);
+
+ glamor_fallback("glamor_put_image_xybitmap: disabled\n");
+ goto fail;
+
+ if (glamor_priv->put_image_xybitmap_prog == 0) {
+ ErrorF("no program for xybitmap putimage\n");
+ goto fail;
+ }
+
+ glamor_set_alu(gc->alu);
+ if (!glamor_set_planemask(pixmap, gc->planemask))
+ goto fail;
+
+ dispatch->glUseProgram(glamor_priv->put_image_xybitmap_prog);
+
+ glamor_get_color_4f_from_pixel(pixmap, gc->fgPixel, fg);
+ dispatch->glUniform4fv
+ (glamor_priv->put_image_xybitmap_fg_uniform_location, 1, fg);
+ glamor_get_color_4f_from_pixel(pixmap, gc->bgPixel, bg);
+ dispatch->glUniform4fv
+ (glamor_priv->put_image_xybitmap_bg_uniform_location, 1, bg);
+
+ dispatch->glGenTextures(1, &tex);
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glEnable(GL_TEXTURE_2D);
+ dispatch->glBindTexture(GL_TEXTURE_2D, tex);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ dispatch->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ dispatch->glPixelStorei(GL_UNPACK_ROW_LENGTH, stride * 8);
+ dispatch->glPixelStorei(GL_UNPACK_SKIP_PIXELS, left_pad);
+ dispatch->glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA,
+ w, h, 0, GL_COLOR_INDEX, GL_BITMAP, bits);
+ dispatch->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ dispatch->glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+
+ /* Now that we've set up our bitmap texture and the shader, shove
+ * the destination rectangle through the cliprects and run the
+ * shader on the resulting fragments.
+ */
+ dispatch->glVertexPointer(2, GL_FLOAT, 0, dest_coords);
+ dispatch->glEnableClientState(GL_VERTEX_ARRAY);
+ dispatch->glClientActiveTexture(GL_TEXTURE0);
+ dispatch->glTexCoordPointer(2, GL_FLOAT, 0, bitmap_coords);
+ dispatch->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ dispatch->glEnable(GL_SCISSOR_TEST);
+ clip = fbGetCompositeClip(gc);
+ for (nbox = REGION_NUM_RECTS(clip),
+ box = REGION_RECTS(clip); nbox--; box++) {
+ int x1 = x;
+ int y1 = y;
+ int x2 = x + w;
+ int y2 = y + h;
+
+ if (x1 < box->x1)
+ x1 = box->x1;
+ if (y1 < box->y1)
+ y1 = box->y1;
+ if (x2 > box->x2)
+ x2 = box->x2;
+ if (y2 > box->y2)
+ y2 = box->y2;
+ if (x1 >= x2 || y1 >= y2)
+ continue;
+
+ dispatch->glScissor(box->x1,
+ y_flip(pixmap, box->y1),
+ box->x2 - box->x1, box->y2 - box->y1);
+ dispatch->glDrawArrays(GL_QUADS, 0, 4);
+ }
+
+ dispatch->glDisable(GL_SCISSOR_TEST);
+ glamor_set_alu(GXcopy);
+ glamor_set_planemask(pixmap, ~0);
+ dispatch->glDeleteTextures(1, &tex);
+ dispatch->glDisable(GL_TEXTURE_2D);
+ dispatch->glDisableClientState(GL_VERTEX_ARRAY);
+ dispatch->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ return;
+ glamor_set_alu(GXcopy);
+ glamor_set_planemask(pixmap, ~0);
+ glamor_fallback(": to %p (%c)\n",
+ drawable, glamor_get_drawable_location(drawable));
+fail:
+ if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW)) {
+ fbPutImage(drawable, gc, 1, x, y, w, h, left_pad, XYBitmap,
+ bits);
+ glamor_finish_access(drawable, GLAMOR_ACCESS_RW);
+ }
+}
+#endif
+
+void
+glamor_fini_putimage_shaders(ScreenPtr screen)
+{
+}
+
+
+static Bool
+_glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
+ int w, int h, int left_pad, int image_format, char *bits, Bool fallback)
+{
+ PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
+ glamor_pixmap_private *pixmap_priv =
+ glamor_get_pixmap_private(pixmap);
+ RegionPtr clip;
+ int x_off, y_off;
+ Bool ret = FALSE;
+ PixmapPtr temp_pixmap, sub_pixmap;
+ glamor_pixmap_private *temp_pixmap_priv;
+ BoxRec box;
+
+ glamor_get_drawable_deltas(drawable, pixmap, &x_off, &y_off);
+ clip = fbGetCompositeClip(gc);
+ if (image_format == XYBitmap) {
+ assert(depth == 1);
+ goto fail;
+ }
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) {
+ glamor_fallback("has no fbo.\n");
+ goto fail;
+ }
+
+ if (image_format != ZPixmap) {
+ glamor_fallback("non-ZPixmap\n");
+ goto fail;
+ }
+
+ if (!glamor_set_planemask(pixmap, gc->planemask)) {
+ goto fail;
+ }
+ /* create a temporary pixmap and upload the bits to that
+ * pixmap, then apply clip copy it to the destination pixmap.*/
+ box.x1 = x + drawable->x;
+ box.y1 = y + drawable->y;
+ box.x2 = x + w + drawable->x;
+ box.y2 = y + h + drawable->y;
+
+ if ((clip != NULL && RegionContainsRect(clip, &box) != rgnIN)
+ || gc->alu != GXcopy) {
+ temp_pixmap = glamor_create_pixmap(drawable->pScreen, w, h, depth, 0);
+ if (temp_pixmap == NULL)
+ goto fail;
+
+ temp_pixmap_priv = glamor_get_pixmap_private(temp_pixmap);
+
+ if (GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv)) {
+ temp_pixmap_priv->base.picture = pixmap_priv->base.picture;
+ temp_pixmap_priv->base.is_picture = pixmap_priv->base.is_picture;
+ }
+
+ glamor_upload_sub_pixmap_to_texture(temp_pixmap, 0, 0, w, h,
+ pixmap->devKind, bits, 0);
+
+ glamor_copy_area(&temp_pixmap->drawable, drawable, gc, 0, 0, w, h, x, y);
+ glamor_destroy_pixmap(temp_pixmap);
+ } else
+ glamor_upload_sub_pixmap_to_texture(pixmap, x + drawable->x + x_off, y + drawable->y + y_off,
+ w, h, PixmapBytePad(w, depth), bits, 0);
+ ret = TRUE;
+ goto done;
+
+fail:
+ glamor_set_planemask(pixmap, ~0);
+
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(&pixmap->drawable))
+ goto done;
+
+ glamor_fallback("to %p (%c)\n",
+ drawable, glamor_get_drawable_location(drawable));
+
+ sub_pixmap = glamor_get_sub_pixmap(pixmap, x + x_off + drawable->x,
+ y + y_off + drawable->y, w, h,
+ GLAMOR_ACCESS_RW);
+ if (sub_pixmap) {
+ if (clip != NULL)
+ pixman_region_translate (clip, -x - drawable->x, -y - drawable->y);
+
+ fbPutImage(&sub_pixmap->drawable, gc, depth, 0, 0, w, h,
+ left_pad, image_format, bits);
+
+ glamor_put_sub_pixmap(sub_pixmap, pixmap,
+ x + x_off + drawable->x,
+ y + y_off + drawable->y,
+ w, h, GLAMOR_ACCESS_RW);
+ if (clip != NULL)
+ pixman_region_translate (clip, x + drawable->x, y + drawable->y);
+ } else
+ fbPutImage(drawable, gc, depth, x, y, w, h,
+ left_pad, image_format, bits);
+ ret = TRUE;
+
+done:
+ return ret;
+}
+
+void
+glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
+ int w, int h, int left_pad, int image_format, char *bits)
+{
+ _glamor_put_image(drawable, gc, depth, x, y, w, h,
+ left_pad, image_format, bits, TRUE);
+}
+
+Bool
+glamor_put_image_nf(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
+ int w, int h, int left_pad, int image_format, char *bits)
+{
+ return _glamor_put_image(drawable, gc, depth, x, y, w, h,
+ left_pad, image_format, bits, FALSE);
+}
+
diff --git a/glamor/glamor_render.c b/glamor/glamor_render.c
new file mode 100644
index 000000000..76a571f8b
--- /dev/null
+++ b/glamor/glamor_render.c
@@ -0,0 +1,2135 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ * Junyan He <junyan.he@linux.intel.com>
+ *
+ */
+
+/** @file glamor_render.c
+ *
+ * Render acceleration implementation
+ */
+
+#include "glamor_priv.h"
+
+#ifdef RENDER
+#include "mipict.h"
+#include "fbpict.h"
+#if 0
+//#define DEBUGF(str, ...) do {} while(0)
+#define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__)
+//#define DEBUGRegionPrint(x) do {} while (0)
+#define DEBUGRegionPrint RegionPrint
+#endif
+
+static struct blendinfo composite_op_info[] = {
+ [PictOpClear] = {0, 0, GL_ZERO, GL_ZERO},
+ [PictOpSrc] = {0, 0, GL_ONE, GL_ZERO},
+ [PictOpDst] = {0, 0, GL_ZERO, GL_ONE},
+ [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
+ [PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
+ [PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO},
+ [PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA},
+ [PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
+ [PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
+ [PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+ [PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
+ [PictOpXor] =
+ {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+ [PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
+};
+#define RepeatFix 10
+static GLuint
+glamor_create_composite_fs(glamor_gl_dispatch * dispatch,
+ struct shader_key *key)
+{
+ const char *repeat_define =
+ "#define RepeatNone 0\n"
+ "#define RepeatNormal 1\n"
+ "#define RepeatPad 2\n"
+ "#define RepeatReflect 3\n"
+ "#define RepeatFix 10\n"
+ "uniform int source_repeat_mode;\n"
+ "uniform int mask_repeat_mode;\n";
+ const char *relocate_texture =
+ GLAMOR_DEFAULT_PRECISION
+ "vec2 rel_tex_coord(vec2 texture, vec4 wh, int repeat) \n"
+ "{\n"
+ " vec2 rel_tex; \n"
+ " rel_tex = texture * wh.xy; \n"
+ " if (repeat == RepeatNone)\n"
+ " return rel_tex; \n"
+ " else if (repeat == RepeatNormal) \n"
+ " rel_tex = floor(rel_tex) + (fract(rel_tex) / wh.xy); \n"
+ " else if(repeat == RepeatPad) { \n"
+ " if (rel_tex.x >= 1.0) rel_tex.x = 1.0 - wh.z * wh.x / 2.; \n"
+ " else if(rel_tex.x < 0.0) rel_tex.x = 0.0; \n"
+ " if (rel_tex.y >= 1.0) rel_tex.y = 1.0 - wh.w * wh.y / 2.; \n"
+ " else if(rel_tex.y < 0.0) rel_tex.y = 0.0; \n"
+ " rel_tex = rel_tex / wh.xy; \n"
+ " } \n"
+ " else if(repeat == RepeatReflect) {\n"
+ " if ((1.0 - mod(abs(floor(rel_tex.x)), 2.0)) < 0.001)\n"
+ " rel_tex.x = 2.0 - (1.0 - fract(rel_tex.x))/wh.x;\n"
+ " else \n"
+ " rel_tex.x = fract(rel_tex.x)/wh.x;\n"
+ " if ((1.0 - mod(abs(floor(rel_tex.y)), 2.0)) < 0.001)\n"
+ " rel_tex.y = 2.0 - (1.0 - fract(rel_tex.y))/wh.y;\n"
+ " else \n"
+ " rel_tex.y = fract(rel_tex.y)/wh.y;\n"
+ " } \n"
+ " return rel_tex; \n"
+ "}\n";
+ /* The texture and the pixmap size is not match eaxctly, so can't sample it directly.
+ * rel_sampler will recalculate the texture coords.*/
+ const char *rel_sampler =
+ " vec4 rel_sampler(sampler2D tex_image, vec2 tex, vec4 wh, int repeat, int set_alpha)\n"
+ "{\n"
+ " tex = rel_tex_coord(tex, wh, repeat - RepeatFix);\n"
+ " if (repeat == RepeatFix) {\n"
+ " if (!(tex.x >= 0.0 && tex.x < 1.0 \n"
+ " && tex.y >= 0.0 && tex.y < 1.0))\n"
+ " return vec4(0.0, 0.0, 0.0, set_alpha);\n"
+ " tex = (fract(tex) / wh.xy);\n"
+ " }\n"
+ " if (set_alpha != 1)\n"
+ " return texture2D(tex_image, tex);\n"
+ " else\n"
+ " return vec4(texture2D(tex_image, tex).rgb, 1.0);\n"
+ "}\n";
+
+ const char *source_solid_fetch =
+ GLAMOR_DEFAULT_PRECISION
+ "uniform vec4 source;\n"
+ "vec4 get_source()\n" "{\n" " return source;\n" "}\n";
+ const char *source_alpha_pixmap_fetch =
+ GLAMOR_DEFAULT_PRECISION
+ "varying vec2 source_texture;\n"
+ "uniform sampler2D source_sampler;\n"
+ "uniform vec4 source_wh;"
+ "vec4 get_source()\n"
+ "{\n"
+ " if (source_repeat_mode < RepeatFix)\n"
+ " return texture2D(source_sampler, source_texture);\n"
+ " else \n"
+ " return rel_sampler(source_sampler, source_texture,\n"
+ " source_wh, source_repeat_mode, 0);\n"
+ "}\n";
+ const char *source_pixmap_fetch =
+ GLAMOR_DEFAULT_PRECISION "varying vec2 source_texture;\n"
+ "uniform sampler2D source_sampler;\n"
+ "uniform vec4 source_wh;\n"
+ "vec4 get_source()\n"
+ "{\n"
+ " if (source_repeat_mode < RepeatFix) \n"
+ " return vec4(texture2D(source_sampler, source_texture).rgb, 1);\n"
+ " else \n"
+ " return rel_sampler(source_sampler, source_texture,\n"
+ " source_wh, source_repeat_mode, 1);\n"
+ "}\n";
+ const char *mask_solid_fetch =
+ GLAMOR_DEFAULT_PRECISION "uniform vec4 mask;\n"
+ "vec4 get_mask()\n" "{\n" " return mask;\n" "}\n";
+ const char *mask_alpha_pixmap_fetch =
+ GLAMOR_DEFAULT_PRECISION "varying vec2 mask_texture;\n"
+ "uniform sampler2D mask_sampler;\n"
+ "uniform vec4 mask_wh;\n"
+ "vec4 get_mask()\n"
+ "{\n"
+ " if (mask_repeat_mode < RepeatFix) \n"
+ " return texture2D(mask_sampler, mask_texture);\n"
+ " else \n"
+ " return rel_sampler(mask_sampler, mask_texture,\n"
+ " mask_wh, mask_repeat_mode, 0);\n"
+ "}\n";
+ const char *mask_pixmap_fetch =
+ GLAMOR_DEFAULT_PRECISION "varying vec2 mask_texture;\n"
+ "uniform sampler2D mask_sampler;\n"
+ "uniform vec4 mask_wh;\n"
+ "vec4 get_mask()\n"
+ "{\n"
+ " if (mask_repeat_mode < RepeatFix) \n"
+ " return vec4(texture2D(mask_sampler, mask_texture).rgb, 1);\n"
+ " else \n"
+ " return rel_sampler(mask_sampler, mask_texture,\n"
+ " mask_wh, mask_repeat_mode, 1);\n"
+ "}\n";
+ const char *in_source_only =
+ GLAMOR_DEFAULT_PRECISION "void main()\n" "{\n"
+ " gl_FragColor = get_source();\n" "}\n";
+ const char *in_normal =
+ GLAMOR_DEFAULT_PRECISION "void main()\n" "{\n"
+ " gl_FragColor = get_source() * get_mask().a;\n" "}\n";
+ const char *in_ca_source =
+ GLAMOR_DEFAULT_PRECISION "void main()\n" "{\n"
+ " gl_FragColor = get_source() * get_mask();\n" "}\n";
+ const char *in_ca_alpha =
+ GLAMOR_DEFAULT_PRECISION "void main()\n" "{\n"
+ " gl_FragColor = get_source().a * get_mask();\n" "}\n";
+ char *source;
+ const char *source_fetch;
+ const char *mask_fetch = "";
+ const char *in;
+ GLuint prog;
+
+ switch (key->source) {
+ case SHADER_SOURCE_SOLID:
+ source_fetch = source_solid_fetch;
+ break;
+ case SHADER_SOURCE_TEXTURE_ALPHA:
+ source_fetch = source_alpha_pixmap_fetch;
+ break;
+ case SHADER_SOURCE_TEXTURE:
+ source_fetch = source_pixmap_fetch;
+ break;
+ default:
+ FatalError("Bad composite shader source");
+ }
+
+ switch (key->mask) {
+ case SHADER_MASK_NONE:
+ break;
+ case SHADER_MASK_SOLID:
+ mask_fetch = mask_solid_fetch;
+ break;
+ case SHADER_MASK_TEXTURE_ALPHA:
+ mask_fetch = mask_alpha_pixmap_fetch;
+ break;
+ case SHADER_MASK_TEXTURE:
+ mask_fetch = mask_pixmap_fetch;
+ break;
+ default:
+ FatalError("Bad composite shader mask");
+ }
+
+ switch (key->in) {
+ case SHADER_IN_SOURCE_ONLY:
+ in = in_source_only;
+ break;
+ case SHADER_IN_NORMAL:
+ in = in_normal;
+ break;
+ case SHADER_IN_CA_SOURCE:
+ in = in_ca_source;
+ break;
+ case SHADER_IN_CA_ALPHA:
+ in = in_ca_alpha;
+ break;
+ default:
+ FatalError("Bad composite IN type");
+ }
+
+ XNFasprintf(&source, "%s%s%s%s%s%s", repeat_define, relocate_texture, rel_sampler,source_fetch, mask_fetch, in);
+
+
+ prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER,
+ source);
+ free(source);
+
+ return prog;
+}
+
+static GLuint
+glamor_create_composite_vs(glamor_gl_dispatch * dispatch,
+ struct shader_key *key)
+{
+ const char *main_opening =
+ "attribute vec4 v_position;\n"
+ "attribute vec4 v_texcoord0;\n"
+ "attribute vec4 v_texcoord1;\n"
+ "varying vec2 source_texture;\n"
+ "varying vec2 mask_texture;\n"
+ "void main()\n" "{\n" " gl_Position = v_position;\n";
+ const char *source_coords =
+ " source_texture = v_texcoord0.xy;\n";
+ const char *mask_coords = " mask_texture = v_texcoord1.xy;\n";
+ const char *main_closing = "}\n";
+ const char *source_coords_setup = "";
+ const char *mask_coords_setup = "";
+ char *source;
+ GLuint prog;
+
+ if (key->source != SHADER_SOURCE_SOLID)
+ source_coords_setup = source_coords;
+
+ if (key->mask != SHADER_MASK_NONE
+ && key->mask != SHADER_MASK_SOLID)
+ mask_coords_setup = mask_coords;
+
+ XNFasprintf(&source,
+ "%s%s%s%s",
+ main_opening,
+ source_coords_setup, mask_coords_setup, main_closing);
+
+ prog =
+ glamor_compile_glsl_prog(dispatch, GL_VERTEX_SHADER, source);
+ free(source);
+
+ return prog;
+}
+
+static void
+glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key,
+ glamor_composite_shader * shader)
+{
+ GLuint vs, fs, prog;
+ GLint source_sampler_uniform_location,
+ mask_sampler_uniform_location;
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ vs = glamor_create_composite_vs(dispatch, key);
+ if (vs == 0)
+ goto out;
+ fs = glamor_create_composite_fs(dispatch, key);
+ if (fs == 0)
+ goto out;
+
+ prog = dispatch->glCreateProgram();
+ dispatch->glAttachShader(prog, vs);
+ dispatch->glAttachShader(prog, fs);
+
+ dispatch->glBindAttribLocation(prog, GLAMOR_VERTEX_POS,
+ "v_position");
+ dispatch->glBindAttribLocation(prog, GLAMOR_VERTEX_SOURCE,
+ "v_texcoord0");
+ dispatch->glBindAttribLocation(prog, GLAMOR_VERTEX_MASK,
+ "v_texcoord1");
+
+ glamor_link_glsl_prog(dispatch, prog);
+
+ shader->prog = prog;
+
+ dispatch->glUseProgram(prog);
+
+ if (key->source == SHADER_SOURCE_SOLID) {
+ shader->source_uniform_location =
+ dispatch->glGetUniformLocation(prog, "source");
+ } else {
+ source_sampler_uniform_location =
+ dispatch->glGetUniformLocation(prog, "source_sampler");
+ dispatch->glUniform1i(source_sampler_uniform_location, 0);
+ shader->source_wh = dispatch->glGetUniformLocation(prog, "source_wh");
+ shader->source_repeat_mode = dispatch->glGetUniformLocation(prog, "source_repeat_mode");
+ }
+
+ if (key->mask != SHADER_MASK_NONE) {
+ if (key->mask == SHADER_MASK_SOLID) {
+ shader->mask_uniform_location =
+ dispatch->glGetUniformLocation(prog, "mask");
+ } else {
+ mask_sampler_uniform_location =
+ dispatch->glGetUniformLocation(prog,
+ "mask_sampler");
+ dispatch->glUniform1i
+ (mask_sampler_uniform_location, 1);
+ shader->mask_wh = dispatch->glGetUniformLocation(prog, "mask_wh");
+ shader->mask_repeat_mode = dispatch->glGetUniformLocation(prog, "mask_repeat_mode");
+ }
+ }
+
+out:
+ glamor_put_dispatch(glamor_priv);
+}
+
+static glamor_composite_shader *
+glamor_lookup_composite_shader(ScreenPtr screen, struct
+ shader_key
+ *key)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_composite_shader *shader;
+
+ shader =
+ &glamor_priv->composite_shader[key->source][key->
+ mask][key->in];
+ if (shader->prog == 0)
+ glamor_create_composite_shader(screen, key, shader);
+
+ return shader;
+}
+
+static void
+glamor_init_eb(unsigned short *eb, int vert_cnt)
+{
+ int i, j;
+ for(i = 0, j = 0; j < vert_cnt; i += 6, j += 4)
+ {
+ eb[i] = j;
+ eb[i + 1] = j + 1;
+ eb[i + 2] = j + 2;
+ eb[i + 3] = j;
+ eb[i + 4] = j + 2;
+ eb[i + 5] = j + 3;
+ }
+}
+
+void
+glamor_init_composite_shaders(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ unsigned short *eb;
+ float *vb = NULL;
+ int eb_size;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glGenBuffers(1, &glamor_priv->vbo);
+ dispatch->glGenBuffers(1, &glamor_priv->ebo);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glamor_priv->ebo);
+
+ eb_size = GLAMOR_COMPOSITE_VBO_VERT_CNT * sizeof(short) * 2;
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
+ dispatch->glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+ eb_size,
+ NULL, GL_STATIC_DRAW);
+ eb = dispatch->glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ }
+ else {
+ vb = malloc(GLAMOR_COMPOSITE_VBO_VERT_CNT * sizeof(float) * 2);
+ if (vb == NULL)
+ FatalError("Failed to allocate vb memory.\n");
+ eb = malloc(eb_size);
+ }
+
+ if (eb == NULL)
+ FatalError("fatal error, fail to get element buffer. GL context may be not created correctly.\n");
+ glamor_init_eb(eb, GLAMOR_COMPOSITE_VBO_VERT_CNT);
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
+ dispatch->glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ } else {
+ dispatch->glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+ eb_size,
+ eb, GL_STATIC_DRAW);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
+ dispatch->glBufferData(GL_ARRAY_BUFFER,
+ GLAMOR_COMPOSITE_VBO_VERT_CNT * sizeof(float) * 2,
+ NULL, GL_DYNAMIC_DRAW);
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ free(eb);
+ glamor_priv->vb = (char*)vb;
+ }
+
+ glamor_put_dispatch(glamor_priv);
+}
+
+void
+glamor_fini_composite_shaders(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ glamor_composite_shader *shader;
+ int i,j,k;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glDeleteBuffers(1, &glamor_priv->vbo);
+ dispatch->glDeleteBuffers(1, &glamor_priv->ebo);
+
+ for(i = 0; i < SHADER_SOURCE_COUNT; i++)
+ for(j = 0; j < SHADER_MASK_COUNT; j++)
+ for(k = 0; k < SHADER_IN_COUNT; k++)
+ {
+ shader = &glamor_priv->composite_shader[i][j][k];
+ if (shader->prog)
+ dispatch->glDeleteProgram(shader->prog);
+ }
+ if (glamor_priv->gl_flavor != GLAMOR_GL_DESKTOP
+ && glamor_priv->vb)
+ free(glamor_priv->vb);
+
+ glamor_put_dispatch(glamor_priv);
+}
+
+static Bool
+glamor_set_composite_op(ScreenPtr screen,
+ CARD8 op, struct blendinfo *op_info_result,
+ PicturePtr dest, PicturePtr mask)
+{
+ GLenum source_blend, dest_blend;
+ struct blendinfo *op_info;
+
+ if (op >= ARRAY_SIZE(composite_op_info)) {
+ glamor_fallback("unsupported render op %d \n", op);
+ return GL_FALSE;
+ }
+ op_info = &composite_op_info[op];
+
+ source_blend = op_info->source_blend;
+ dest_blend = op_info->dest_blend;
+
+ /* If there's no dst alpha channel, adjust the blend op so that we'll treat
+ * it as always 1.
+ */
+ if (PICT_FORMAT_A(dest->format) == 0 && op_info->dest_alpha) {
+ if (source_blend == GL_DST_ALPHA)
+ source_blend = GL_ONE;
+ else if (source_blend == GL_ONE_MINUS_DST_ALPHA)
+ source_blend = GL_ZERO;
+ }
+
+ /* Set up the source alpha value for blending in component alpha mode. */
+ if (mask && mask->componentAlpha
+ && PICT_FORMAT_RGB(mask->format) != 0 && op_info->source_alpha)
+ {
+ if (dest_blend == GL_SRC_ALPHA)
+ dest_blend = GL_SRC_COLOR;
+ else if (dest_blend == GL_ONE_MINUS_SRC_ALPHA)
+ dest_blend = GL_ONE_MINUS_SRC_COLOR;
+ }
+
+ op_info_result->source_blend = source_blend;
+ op_info_result->dest_blend = dest_blend;
+ op_info_result->source_alpha = op_info->source_alpha;
+ op_info_result->dest_alpha = op_info->dest_alpha;
+
+ return TRUE;
+}
+
+static void
+glamor_set_composite_texture(glamor_screen_private *glamor_priv, int unit,
+ PicturePtr picture,
+ glamor_pixmap_private * pixmap_priv,
+ GLuint wh_location, GLuint repeat_location)
+{
+ glamor_gl_dispatch *dispatch;
+ float wh[4];
+ int repeat_type;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glActiveTexture(GL_TEXTURE0 + unit);
+ dispatch->glBindTexture(GL_TEXTURE_2D, pixmap_priv->base.fbo->tex);
+ repeat_type = picture->repeatType;
+ switch (picture->repeatType) {
+ case RepeatNone:
+#ifndef GLAMOR_GLES2
+ /* XXX GLES2 doesn't support GL_CLAMP_TO_BORDER. */
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_BORDER);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_BORDER);
+#else
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE);
+#endif
+ break;
+ case RepeatNormal:
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ GL_REPEAT);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ GL_REPEAT);
+ break;
+ case RepeatPad:
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE);
+ break;
+ case RepeatReflect:
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ GL_MIRRORED_REPEAT);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ GL_MIRRORED_REPEAT);
+ break;
+ }
+
+ switch (picture->filter) {
+ default:
+ case PictFilterFast:
+ case PictFilterNearest:
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ break;
+ case PictFilterGood:
+ case PictFilterBest:
+ case PictFilterBilinear:
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR);
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER,
+ GL_LINEAR);
+ break;
+ }
+#ifndef GLAMOR_GLES2
+ dispatch->glEnable(GL_TEXTURE_2D);
+#endif
+
+ /*
+ * GLES2 doesn't support RepeatNone. We need to fix it anyway.
+ *
+ **/
+ if (repeat_type != RepeatNone)
+ repeat_type += RepeatFix;
+ else if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
+ || pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ if (picture->transform
+ || (GLAMOR_PIXMAP_FBO_NOT_EAXCT_SIZE(pixmap_priv)))
+ repeat_type += RepeatFix;
+ }
+ if (repeat_type >= RepeatFix) {
+ glamor_pixmap_fbo_fix_wh_ratio(wh, pixmap_priv);
+ if ((wh[0] != 1.0 || wh[1] != 1.0 )
+ || (glamor_priv->gl_flavor == GLAMOR_GL_ES2
+ && repeat_type == RepeatFix))
+ dispatch->glUniform4fv(wh_location, 1, wh);
+ else
+ repeat_type -= RepeatFix;
+ }
+ dispatch->glUniform1i(repeat_location, repeat_type);
+ glamor_put_dispatch(glamor_priv);
+}
+
+static void
+glamor_set_composite_solid(glamor_gl_dispatch * dispatch, float *color,
+ GLint uniform_location)
+{
+ dispatch->glUniform4fv(uniform_location, 1, color);
+}
+
+static int
+compatible_formats(CARD8 op, PicturePtr dst, PicturePtr src)
+{
+ if (op == PictOpSrc) {
+ if (src->format == dst->format)
+ return 1;
+
+ if (src->format == PICT_a8r8g8b8
+ && dst->format == PICT_x8r8g8b8)
+ return 1;
+
+ if (src->format == PICT_a8b8g8r8
+ && dst->format == PICT_x8b8g8r8)
+ return 1;
+ } else if (op == PictOpOver) {
+ if (src->alphaMap || dst->alphaMap)
+ return 0;
+
+ if (src->format != dst->format)
+ return 0;
+
+ if (src->format == PICT_x8r8g8b8
+ || src->format == PICT_x8b8g8r8)
+ return 1;
+ }
+
+ return 0;
+}
+
+static char
+glamor_get_picture_location(PicturePtr picture)
+{
+ if (picture == NULL)
+ return ' ';
+
+ if (picture->pDrawable == NULL) {
+ switch (picture->pSourcePict->type) {
+ case SourcePictTypeSolidFill:
+ return 'c';
+ case SourcePictTypeLinear:
+ return 'l';
+ case SourcePictTypeRadial:
+ return 'r';
+ default:
+ return '?';
+ }
+ }
+ return glamor_get_drawable_location(picture->pDrawable);
+}
+
+static Bool
+glamor_composite_with_copy(CARD8 op,
+ PicturePtr source,
+ PicturePtr dest,
+ INT16 x_source,
+ INT16 y_source,
+ INT16 x_dest,
+ INT16 y_dest,
+ RegionPtr region)
+{
+ int ret = FALSE;
+ if (!source->pDrawable)
+ return FALSE;
+
+ if (!compatible_formats(op, dest, source))
+ return FALSE;
+
+ if (source->repeat || source->transform) {
+ return FALSE;
+ }
+
+ x_dest += dest->pDrawable->x;
+ y_dest += dest->pDrawable->y;
+ x_source += source->pDrawable->x;
+ y_source += source->pDrawable->y;
+ if (PICT_FORMAT_A(source->format) == 0) {
+ /* Fallback if we sample outside the source so that we
+ * swizzle the correct clear color for out-of-bounds texels.
+ */
+ if (region->extents.x1 + x_source - x_dest < 0)
+ goto cleanup_region;
+ if (region->extents.x2 + x_source - x_dest > source->pDrawable->width)
+ goto cleanup_region;
+
+ if (region->extents.y1 + y_source - y_dest < 0)
+ goto cleanup_region;
+ if (region->extents.y2 + y_source - y_dest > source->pDrawable->height)
+ goto cleanup_region;
+ }
+ ret = glamor_copy_n_to_n_nf(source->pDrawable,
+ dest->pDrawable, NULL,
+ RegionRects(region), RegionNumRects(region),
+ x_source - x_dest, y_source - y_dest,
+ FALSE, FALSE, 0, NULL);
+cleanup_region:
+ return ret;
+}
+
+void
+glamor_setup_composite_vbo(ScreenPtr screen, int n_verts)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch;
+ int vert_size;
+
+ glamor_priv->render_nr_verts = 0;
+ glamor_priv->vb_stride = 2 * sizeof(float);
+ if (glamor_priv->has_source_coords)
+ glamor_priv->vb_stride += 2 * sizeof(float);
+ if (glamor_priv->has_mask_coords)
+ glamor_priv->vb_stride += 2 * sizeof(float);
+
+ vert_size = n_verts * glamor_priv->vb_stride;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
+ if (glamor_priv->vbo_size < (glamor_priv->vbo_offset + vert_size)) {
+ glamor_priv->vbo_size = GLAMOR_COMPOSITE_VBO_VERT_CNT *
+ glamor_priv->vb_stride;
+ glamor_priv->vbo_offset = 0;
+ dispatch->glBufferData(GL_ARRAY_BUFFER,
+ glamor_priv->vbo_size,
+ NULL, GL_STREAM_DRAW);
+ }
+
+ glamor_priv->vb = dispatch->glMapBufferRange(GL_ARRAY_BUFFER,
+ glamor_priv->vbo_offset,
+ vert_size,
+ GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
+ assert(glamor_priv->vb != NULL);
+ glamor_priv->vb -= glamor_priv->vbo_offset;
+ } else
+ glamor_priv->vbo_offset = 0;
+
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glamor_priv->ebo);
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
+ GL_FALSE, glamor_priv->vb_stride,
+ (void *) ((long)
+ glamor_priv->vbo_offset));
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+
+ if (glamor_priv->has_source_coords) {
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2,
+ GL_FLOAT, GL_FALSE,
+ glamor_priv->vb_stride,
+ (void *) ((long)
+ glamor_priv->vbo_offset
+ +
+ 2 *
+ sizeof(float)));
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ }
+
+ if (glamor_priv->has_mask_coords) {
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_MASK, 2,
+ GL_FLOAT, GL_FALSE,
+ glamor_priv->vb_stride,
+ (void *) ((long)
+ glamor_priv->vbo_offset
+ +
+ (glamor_priv->has_source_coords
+ ? 4 : 2) *
+ sizeof(float)));
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_MASK);
+ }
+ glamor_put_dispatch(glamor_priv);
+}
+
+void
+glamor_emit_composite_vert(ScreenPtr screen,
+ const float *src_coords,
+ const float *mask_coords,
+ const float *dst_coords, int i)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ float *vb = (float *) (glamor_priv->vb + glamor_priv->vbo_offset);
+ int j = 0;
+
+ vb[j++] = dst_coords[i * 2 + 0];
+ vb[j++] = dst_coords[i * 2 + 1];
+ if (glamor_priv->has_source_coords) {
+ vb[j++] = src_coords[i * 2 + 0];
+ vb[j++] = src_coords[i * 2 + 1];
+ }
+ if (glamor_priv->has_mask_coords) {
+ vb[j++] = mask_coords[i * 2 + 0];
+ vb[j++] = mask_coords[i * 2 + 1];
+ }
+
+ glamor_priv->render_nr_verts++;
+ glamor_priv->vbo_offset += glamor_priv->vb_stride;
+}
+
+
+
+static void
+glamor_flush_composite_rects(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
+ dispatch->glUnmapBuffer(GL_ARRAY_BUFFER);
+ else {
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
+ dispatch->glBufferData(GL_ARRAY_BUFFER,
+ glamor_priv->vbo_offset,
+ glamor_priv->vb, GL_DYNAMIC_DRAW);
+ }
+
+ if (!glamor_priv->render_nr_verts)
+ return;
+
+#ifndef GLAMOR_GLES2
+ dispatch->glDrawRangeElements(GL_TRIANGLES, 0, glamor_priv->render_nr_verts,
+ (glamor_priv->render_nr_verts * 3) / 2,
+ GL_UNSIGNED_SHORT, NULL);
+#else
+ dispatch->glDrawElements(GL_TRIANGLES, (glamor_priv->render_nr_verts * 3) / 2,
+ GL_UNSIGNED_SHORT, NULL);
+#endif
+ glamor_put_dispatch(glamor_priv);
+}
+
+int pict_format_combine_tab[][3] = {
+ {PICT_TYPE_ARGB, PICT_TYPE_A, PICT_TYPE_ARGB},
+ {PICT_TYPE_ABGR, PICT_TYPE_A, PICT_TYPE_ABGR},
+};
+
+static Bool
+combine_pict_format(PictFormatShort * des, const PictFormatShort src,
+ const PictFormatShort mask, enum shader_in in_ca)
+{
+ PictFormatShort new_vis;
+ int src_type, mask_type, src_bpp, mask_bpp;
+ int i;
+ if (src == mask) {
+ *des = src;
+ return TRUE;
+ }
+ src_bpp = PICT_FORMAT_BPP(src);
+ mask_bpp = PICT_FORMAT_BPP(mask);
+
+ assert(src_bpp == mask_bpp);
+
+ new_vis = PICT_FORMAT_VIS(src) | PICT_FORMAT_VIS(mask);
+
+ switch (in_ca) {
+ case SHADER_IN_SOURCE_ONLY:
+ return TRUE;
+ case SHADER_IN_NORMAL:
+ src_type = PICT_FORMAT_TYPE(src);
+ mask_type = PICT_TYPE_A;
+ break;
+ case SHADER_IN_CA_SOURCE:
+ src_type = PICT_FORMAT_TYPE(src);
+ mask_type = PICT_FORMAT_TYPE(mask);
+ break;
+ case SHADER_IN_CA_ALPHA:
+ src_type = PICT_TYPE_A;
+ mask_type = PICT_FORMAT_TYPE(mask);
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (src_type == mask_type) {
+ *des = PICT_VISFORMAT(src_bpp, src_type, new_vis);
+ return TRUE;
+ }
+
+ for (i = 0;
+ i <
+ sizeof(pict_format_combine_tab) /
+ sizeof(pict_format_combine_tab[0]); i++) {
+ if ((src_type == pict_format_combine_tab[i][0]
+ && mask_type == pict_format_combine_tab[i][1])
+ || (src_type == pict_format_combine_tab[i][1]
+ && mask_type == pict_format_combine_tab[i][0])) {
+ *des = PICT_VISFORMAT(src_bpp,
+ pict_format_combine_tab[i]
+ [2], new_vis);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+glamor_set_normalize_tcoords_generic(glamor_pixmap_private *priv,
+ int repeat_type,
+ float *matrix,
+ float xscale, float yscale,
+ int x1, int y1, int x2, int y2,
+ int yInverted, float *texcoords,
+ int stride)
+{
+ if (!matrix && repeat_type == RepeatNone)
+ glamor_set_normalize_tcoords_ext(priv, xscale, yscale,
+ x1, y1,
+ x2, y2,
+ yInverted,
+ texcoords, stride);
+ else if (matrix && repeat_type == RepeatNone)
+ glamor_set_transformed_normalize_tcoords_ext(priv, matrix, xscale,
+ yscale, x1, y1,
+ x2, y2,
+ yInverted,
+ texcoords, stride);
+ else if (!matrix && repeat_type != RepeatNone)
+ glamor_set_repeat_normalize_tcoords_ext(priv, repeat_type,
+ xscale, yscale,
+ x1, y1,
+ x2, y2,
+ yInverted,
+ texcoords, stride);
+ else if (matrix && repeat_type != RepeatNone)
+ glamor_set_repeat_transformed_normalize_tcoords_ext(priv, repeat_type,
+ matrix, xscale, yscale,
+ x1, y1,
+ x2, y2,
+ yInverted,
+ texcoords, stride);
+}
+
+Bool glamor_composite_choose_shader(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ glamor_pixmap_private *source_pixmap_priv,
+ glamor_pixmap_private *mask_pixmap_priv,
+ glamor_pixmap_private *dest_pixmap_priv,
+ struct shader_key *s_key,
+ glamor_composite_shader **shader,
+ struct blendinfo *op_info,
+ PictFormatShort *psaved_source_format)
+{
+ ScreenPtr screen = dest->pDrawable->pScreen;
+ PixmapPtr dest_pixmap = dest_pixmap_priv->base.pixmap;
+ PixmapPtr source_pixmap = NULL;
+ PixmapPtr mask_pixmap = NULL;
+ enum glamor_pixmap_status source_status = GLAMOR_NONE;
+ enum glamor_pixmap_status mask_status = GLAMOR_NONE;
+ PictFormatShort saved_source_format = 0;
+ struct shader_key key;
+ GLfloat source_solid_color[4];
+ GLfloat mask_solid_color[4];
+ Bool ret = FALSE;
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) {
+ glamor_fallback("dest has no fbo.\n");
+ goto fail;
+ }
+
+ memset(&key, 0, sizeof(key));
+ if (!source) {
+ key.source = SHADER_SOURCE_SOLID;
+ source_solid_color[0] = 0.0;
+ source_solid_color[1] = 0.0;
+ source_solid_color[2] = 0.0;
+ source_solid_color[3] = 0.0;
+ } else if (!source->pDrawable) {
+ if (source->pSourcePict->type == SourcePictTypeSolidFill) {
+ key.source = SHADER_SOURCE_SOLID;
+ glamor_get_rgba_from_pixel(source->
+ pSourcePict->solidFill.
+ color,
+ &source_solid_color[0],
+ &source_solid_color[1],
+ &source_solid_color[2],
+ &source_solid_color[3],
+ PICT_a8r8g8b8);
+ } else
+ goto fail;
+ } else {
+ key.source = SHADER_SOURCE_TEXTURE_ALPHA;
+ }
+
+ if (mask) {
+ if (!mask->pDrawable) {
+ if (mask->pSourcePict->type ==
+ SourcePictTypeSolidFill) {
+ key.mask = SHADER_MASK_SOLID;
+ glamor_get_rgba_from_pixel
+ (mask->pSourcePict->solidFill.color,
+ &mask_solid_color[0],
+ &mask_solid_color[1],
+ &mask_solid_color[2],
+ &mask_solid_color[3], PICT_a8r8g8b8);
+ } else
+ goto fail;
+ } else {
+ key.mask = SHADER_MASK_TEXTURE_ALPHA;
+ }
+
+ if (!mask->componentAlpha) {
+ key.in = SHADER_IN_NORMAL;
+ } else {
+ if (op == PictOpClear)
+ key.mask = SHADER_MASK_NONE;
+ else if (op == PictOpSrc || op == PictOpAdd
+ || op == PictOpIn || op == PictOpOut
+ || op == PictOpOverReverse)
+ key.in = SHADER_IN_CA_SOURCE;
+ else if (op == PictOpOutReverse || op == PictOpInReverse) {
+ key.in = SHADER_IN_CA_ALPHA;
+ } else {
+ glamor_fallback("Unsupported component alpha op: %d\n", op);
+ goto fail;
+ }
+ }
+ } else {
+ key.mask = SHADER_MASK_NONE;
+ key.in = SHADER_IN_SOURCE_ONLY;
+ }
+
+ if (source && source->alphaMap) {
+ glamor_fallback("source alphaMap\n");
+ goto fail;
+ }
+ if (mask && mask->alphaMap) {
+ glamor_fallback("mask alphaMap\n");
+ goto fail;
+ }
+
+ if (key.source == SHADER_SOURCE_TEXTURE ||
+ key.source == SHADER_SOURCE_TEXTURE_ALPHA) {
+ source_pixmap = source_pixmap_priv->base.pixmap;
+ if (source_pixmap == dest_pixmap) {
+ /* XXX source and the dest share the same texture.
+ * Does it need special handle? */
+ glamor_fallback("source == dest\n");
+ }
+ if (source_pixmap_priv->base.gl_fbo == 0) {
+ /* XXX in Xephyr, we may have gl_fbo equal to 1 but gl_tex
+ * equal to zero when the pixmap is screen pixmap. Then we may
+ * refer the tex zero directly latter in the composition.
+ * It seems that it works fine, but it may have potential problem*/
+#ifdef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
+ source_status = GLAMOR_UPLOAD_PENDING;
+#else
+ glamor_fallback("no texture in source\n");
+ goto fail;
+#endif
+ }
+ }
+
+ if (key.mask == SHADER_MASK_TEXTURE ||
+ key.mask == SHADER_MASK_TEXTURE_ALPHA) {
+ mask_pixmap = mask_pixmap_priv->base.pixmap;
+ if (mask_pixmap == dest_pixmap) {
+ glamor_fallback("mask == dest\n");
+ goto fail;
+ }
+ if (mask_pixmap_priv->base.gl_fbo == 0) {
+#ifdef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
+ mask_status = GLAMOR_UPLOAD_PENDING;
+#else
+ glamor_fallback("no texture in mask\n");
+ goto fail;
+#endif
+ }
+ }
+
+#ifdef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
+ if (source_status == GLAMOR_UPLOAD_PENDING
+ && mask_status == GLAMOR_UPLOAD_PENDING
+ && source_pixmap == mask_pixmap) {
+
+ if (source->format != mask->format) {
+ saved_source_format = source->format;
+
+ if (!combine_pict_format(&source->format, source->format,
+ mask->format, key.in)) {
+ glamor_fallback("combine source %x mask %x failed.\n",
+ source->format, mask->format);
+ goto fail;
+ }
+
+ if (source->format != saved_source_format) {
+ glamor_picture_format_fixup(source,
+ source_pixmap_priv);
+ }
+ /* XXX
+ * By default, glamor_upload_picture_to_texture will wire alpha to 1
+ * if one picture doesn't have alpha. So we don't do that again in
+ * rendering function. But here is a special case, as source and
+ * mask share the same texture but may have different formats. For
+ * example, source doesn't have alpha, but mask has alpha. Then the
+ * texture will have the alpha value for the mask. And will not wire
+ * to 1 for the source. In this case, we have to use different shader
+ * to wire the source's alpha to 1.
+ *
+ * But this may cause a potential problem if the source's repeat mode
+ * is REPEAT_NONE, and if the source is smaller than the dest, then
+ * for the region not covered by the source may be painted incorrectly.
+ * because we wire the alpha to 1.
+ *
+ **/
+ if (!PICT_FORMAT_A(saved_source_format)
+ && PICT_FORMAT_A(mask->format))
+ key.source = SHADER_SOURCE_TEXTURE;
+
+ if (!PICT_FORMAT_A(mask->format)
+ && PICT_FORMAT_A(saved_source_format))
+ key.mask = SHADER_MASK_TEXTURE;
+
+ mask_status = GLAMOR_NONE;
+ }
+
+ source_status = glamor_upload_picture_to_texture(source);
+ if (source_status != GLAMOR_UPLOAD_DONE) {
+ glamor_fallback("Failed to upload source texture.\n");
+ goto fail;
+ }
+ } else {
+ if (source_status == GLAMOR_UPLOAD_PENDING) {
+ source_status = glamor_upload_picture_to_texture(source);
+ if (source_status != GLAMOR_UPLOAD_DONE) {
+ glamor_fallback("Failed to upload source texture.\n");
+ goto fail;
+ }
+ }
+
+ if (mask_status == GLAMOR_UPLOAD_PENDING) {
+ mask_status = glamor_upload_picture_to_texture(mask);
+ if (mask_status != GLAMOR_UPLOAD_DONE) {
+ glamor_fallback("Failed to upload mask texture.\n");
+ goto fail;
+ }
+ }
+ }
+#endif
+
+ /*Before enter the rendering stage, we need to fixup
+ * transformed source and mask, if the transform is not int translate. */
+ if (key.source != SHADER_SOURCE_SOLID
+ && source->transform
+ && !pixman_transform_is_int_translate(source->transform)
+ && source_pixmap_priv->type != GLAMOR_TEXTURE_LARGE) {
+ if (!glamor_fixup_pixmap_priv(screen, source_pixmap_priv))
+ goto fail;
+ }
+ if (key.mask != SHADER_MASK_NONE && key.mask != SHADER_MASK_SOLID
+ && mask->transform
+ && !pixman_transform_is_int_translate(mask->transform)
+ && mask_pixmap_priv->type != GLAMOR_TEXTURE_LARGE) {
+ if (!glamor_fixup_pixmap_priv(screen, mask_pixmap_priv))
+ goto fail;
+ }
+
+
+ if (!glamor_set_composite_op(screen, op, op_info, dest, mask))
+ goto fail;
+
+ *shader = glamor_lookup_composite_shader(screen, &key);
+ if ((*shader)->prog == 0) {
+ glamor_fallback("no shader program for this"
+ "render acccel mode\n");
+ goto fail;
+ }
+
+ if (key.source == SHADER_SOURCE_SOLID)
+ memcpy(&(*shader)->source_solid_color[0],
+ source_solid_color, 4*sizeof(float));
+ else {
+ (*shader)->source_priv = source_pixmap_priv;
+ (*shader)->source = source;
+ }
+
+ if (key.mask == SHADER_MASK_SOLID)
+ memcpy(&(*shader)->mask_solid_color[0],
+ mask_solid_color, 4*sizeof(float));
+ else {
+ (*shader)->mask_priv = mask_pixmap_priv;
+ (*shader)->mask = mask;
+ }
+
+ ret = TRUE;
+ memcpy(s_key, &key, sizeof(key));
+ *psaved_source_format = saved_source_format;
+ goto done;
+
+fail:
+ if (saved_source_format)
+ source->format = saved_source_format;
+done:
+ return ret;
+}
+
+void
+glamor_composite_set_shader_blend(glamor_pixmap_private *dest_priv,
+ struct shader_key *key,
+ glamor_composite_shader *shader,
+ struct blendinfo *op_info)
+{
+ glamor_gl_dispatch *dispatch;
+ glamor_screen_private *glamor_priv;
+
+ glamor_priv = dest_priv->base.glamor_priv;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glUseProgram(shader->prog);
+
+ if (key->source == SHADER_SOURCE_SOLID) {
+ glamor_set_composite_solid(dispatch,
+ shader->source_solid_color,
+ shader->source_uniform_location);
+ } else {
+ glamor_set_composite_texture(glamor_priv, 0,
+ shader->source,
+ shader->source_priv, shader->source_wh,
+ shader->source_repeat_mode);
+ }
+
+ if (key->mask != SHADER_MASK_NONE) {
+ if (key->mask == SHADER_MASK_SOLID) {
+ glamor_set_composite_solid(dispatch,
+ shader->mask_solid_color,
+ shader->mask_uniform_location);
+ } else {
+ glamor_set_composite_texture(glamor_priv, 1,
+ shader->mask,
+ shader->mask_priv, shader->mask_wh,
+ shader->mask_repeat_mode);
+ }
+ }
+
+ if (op_info->source_blend == GL_ONE
+ && op_info->dest_blend == GL_ZERO) {
+ dispatch->glDisable(GL_BLEND);
+ } else {
+ dispatch->glEnable(GL_BLEND);
+ dispatch->glBlendFunc(op_info->source_blend,
+ op_info->dest_blend);
+ }
+
+ glamor_put_dispatch(glamor_priv);
+}
+
+static Bool
+glamor_composite_with_shader(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ glamor_pixmap_private *source_pixmap_priv,
+ glamor_pixmap_private *mask_pixmap_priv,
+ glamor_pixmap_private *dest_pixmap_priv,
+ int nrect, glamor_composite_rect_t * rects,
+ Bool two_pass_ca)
+{
+ ScreenPtr screen = dest->pDrawable->pScreen;
+ glamor_screen_private *glamor_priv = dest_pixmap_priv->base.glamor_priv;
+ PixmapPtr dest_pixmap = dest_pixmap_priv->base.pixmap;
+ PixmapPtr source_pixmap = NULL;
+ PixmapPtr mask_pixmap = NULL;
+ glamor_gl_dispatch *dispatch = NULL;
+ GLfloat dst_xscale, dst_yscale;
+ GLfloat mask_xscale = 1, mask_yscale = 1,
+ src_xscale = 1, src_yscale = 1;
+ struct shader_key key, key_ca;
+ float *vertices;
+ int dest_x_off, dest_y_off;
+ int source_x_off, source_y_off;
+ int mask_x_off, mask_y_off;
+ PictFormatShort saved_source_format = 0;
+ float src_matrix[9], mask_matrix[9];
+ float *psrc_matrix = NULL, *pmask_matrix = NULL;
+ int vert_stride = 4;
+ int nrect_max;
+ Bool ret = FALSE;
+ glamor_composite_shader *shader = NULL, *shader_ca = NULL;
+ struct blendinfo op_info, op_info_ca;
+
+ if(!glamor_composite_choose_shader(op, source, mask, dest,
+ source_pixmap_priv, mask_pixmap_priv,
+ dest_pixmap_priv,
+ &key, &shader, &op_info,
+ &saved_source_format)) {
+ glamor_fallback("glamor_composite_choose_shader failed\n");
+ return ret;
+ }
+ if (two_pass_ca) {
+ if(!glamor_composite_choose_shader(PictOpAdd, source, mask, dest,
+ source_pixmap_priv, mask_pixmap_priv,
+ dest_pixmap_priv,
+ &key_ca, &shader_ca, &op_info_ca,
+ &saved_source_format)) {
+ glamor_fallback("glamor_composite_choose_shader failed\n");
+ return ret;
+ }
+ }
+
+ glamor_set_destination_pixmap_priv_nc(dest_pixmap_priv);
+ glamor_composite_set_shader_blend(dest_pixmap_priv, &key, shader, &op_info);
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+ glamor_priv->has_source_coords = key.source != SHADER_SOURCE_SOLID;
+ glamor_priv->has_mask_coords = (key.mask != SHADER_MASK_NONE &&
+ key.mask != SHADER_MASK_SOLID);
+
+ dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable);
+ dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
+ glamor_get_drawable_deltas(dest->pDrawable, dest_pixmap,
+ &dest_x_off, &dest_y_off);
+ pixmap_priv_get_dest_scale(dest_pixmap_priv, &dst_xscale, &dst_yscale);
+
+ if (glamor_priv->has_source_coords) {
+ source_pixmap = source_pixmap_priv->base.pixmap;
+ glamor_get_drawable_deltas(source->pDrawable,
+ source_pixmap, &source_x_off,
+ &source_y_off);
+ pixmap_priv_get_scale(source_pixmap_priv, &src_xscale,
+ &src_yscale);
+ if (source->transform) {
+ psrc_matrix = src_matrix;
+ glamor_picture_get_matrixf(source, psrc_matrix);
+ }
+ vert_stride += 4;
+ }
+
+ if (glamor_priv->has_mask_coords) {
+ mask_pixmap = mask_pixmap_priv->base.pixmap;
+ glamor_get_drawable_deltas(mask->pDrawable, mask_pixmap,
+ &mask_x_off, &mask_y_off);
+ pixmap_priv_get_scale(mask_pixmap_priv, &mask_xscale,
+ &mask_yscale);
+ if (mask->transform) {
+ pmask_matrix = mask_matrix;
+ glamor_picture_get_matrixf(mask, pmask_matrix);
+ }
+ vert_stride += 4;
+ }
+
+ nrect_max = (vert_stride * nrect) > GLAMOR_COMPOSITE_VBO_VERT_CNT ?
+ (GLAMOR_COMPOSITE_VBO_VERT_CNT / vert_stride) : nrect;
+
+ while(nrect) {
+ int mrect, rect_processed;
+ int vb_stride;
+
+ mrect = nrect > nrect_max ? nrect_max : nrect ;
+ glamor_setup_composite_vbo(screen, mrect * vert_stride);
+ rect_processed = mrect;
+ vb_stride = glamor_priv->vb_stride/sizeof(float);
+ while (mrect--) {
+ INT16 x_source;
+ INT16 y_source;
+ INT16 x_mask;
+ INT16 y_mask;
+ INT16 x_dest;
+ INT16 y_dest;
+ CARD16 width;
+ CARD16 height;
+
+ x_dest = rects->x_dst + dest_x_off;
+ y_dest = rects->y_dst + dest_y_off;
+ x_source = rects->x_src + source_x_off;
+ y_source = rects->y_src + source_y_off;
+ x_mask = rects->x_mask + mask_x_off;
+ y_mask = rects->y_mask + mask_y_off;
+ width = rects->width;
+ height = rects->height;
+
+ DEBUGF("dest(%d,%d) source(%d %d) mask (%d %d), width %d height %d \n",
+ x_dest, y_dest, x_source, y_source,x_mask,y_mask,width,height);
+ vertices = (float*)(glamor_priv->vb + glamor_priv->vbo_offset);
+ assert(glamor_priv->vbo_offset < glamor_priv->vbo_size - glamor_priv->vb_stride);
+ glamor_set_normalize_vcoords_ext(dest_pixmap_priv, dst_xscale,
+ dst_yscale,
+ x_dest, y_dest,
+ x_dest + width, y_dest + height,
+ glamor_priv->yInverted,
+ vertices, vb_stride);
+ vertices += 2;
+ if (key.source != SHADER_SOURCE_SOLID) {
+ glamor_set_normalize_tcoords_generic(
+ source_pixmap_priv, source->repeatType, psrc_matrix,
+ src_xscale, src_yscale, x_source, y_source,
+ x_source + width, y_source + height,
+ glamor_priv->yInverted, vertices, vb_stride);
+ vertices += 2;
+ }
+
+ if (key.mask != SHADER_MASK_NONE
+ && key.mask != SHADER_MASK_SOLID) {
+ glamor_set_normalize_tcoords_generic(
+ mask_pixmap_priv, mask->repeatType, pmask_matrix,
+ mask_xscale, mask_yscale, x_mask, y_mask,
+ x_mask + width, y_mask + height,
+ glamor_priv->yInverted, vertices, vb_stride);
+ }
+ glamor_priv->render_nr_verts += 4;
+ glamor_priv->vbo_offset += glamor_priv->vb_stride * 4;
+ rects++;
+ }
+ glamor_flush_composite_rects(screen);
+ nrect -= rect_processed;
+ if (two_pass_ca) {
+ glamor_composite_set_shader_blend(dest_pixmap_priv,
+ &key_ca, shader_ca,
+ &op_info_ca);
+ glamor_flush_composite_rects(screen);
+ if (nrect)
+ glamor_composite_set_shader_blend(dest_pixmap_priv,
+ &key, shader,
+ &op_info);
+ }
+ }
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_MASK);
+ dispatch->glDisable(GL_BLEND);
+#ifndef GLAMOR_GLES2
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glDisable(GL_TEXTURE_2D);
+ dispatch->glActiveTexture(GL_TEXTURE1);
+ dispatch->glDisable(GL_TEXTURE_2D);
+#endif
+ DEBUGF("finish rendering.\n");
+ dispatch->glUseProgram(0);
+ glamor_priv->state = RENDER_STATE;
+ glamor_priv->render_idle_cnt = 0;
+ if (saved_source_format)
+ source->format = saved_source_format;
+ glamor_put_dispatch(glamor_priv);
+
+ ret = TRUE;
+ return ret;
+}
+
+PicturePtr
+glamor_convert_gradient_picture(ScreenPtr screen,
+ PicturePtr source,
+ int x_source,
+ int y_source, int width, int height)
+{
+ PixmapPtr pixmap;
+ PicturePtr dst = NULL;
+ int error;
+ PictFormatShort format;
+ if (!source->pDrawable)
+ format = PICT_a8r8g8b8;
+ else
+ format = source->format;
+#ifdef GLAMOR_GRADIENT_SHADER
+ if (!source->pDrawable) {
+ if (source->pSourcePict->type == SourcePictTypeLinear) {
+ dst = glamor_generate_linear_gradient_picture(screen,
+ source, x_source, y_source, width, height, format);
+ } else if (source->pSourcePict->type == SourcePictTypeRadial) {
+ dst = glamor_generate_radial_gradient_picture(screen,
+ source, x_source, y_source, width, height, format);
+ }
+
+ if (dst) {
+#if 0 /* Debug to compare it to pixman, Enable it if needed. */
+ glamor_compare_pictures(screen, source,
+ dst, x_source, y_source, width, height,
+ 0, 3);
+#endif
+ return dst;
+ }
+ }
+#endif
+ pixmap = glamor_create_pixmap(screen,
+ width,
+ height,
+ PIXMAN_FORMAT_DEPTH(format),
+ GLAMOR_CREATE_PIXMAP_CPU);
+
+ if (!pixmap)
+ return NULL;
+
+ dst = CreatePicture(0,
+ &pixmap->drawable,
+ PictureMatchFormat(screen,
+ PIXMAN_FORMAT_DEPTH(format),
+ format),
+ 0, 0, serverClient, &error);
+ glamor_destroy_pixmap(pixmap);
+ if (!dst)
+ return NULL;
+
+ ValidatePicture(dst);
+
+ fbComposite(PictOpSrc, source, NULL, dst, x_source, y_source,
+ 0, 0, 0, 0, width, height);
+ return dst;
+}
+
+Bool
+glamor_composite_clipped_region(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ glamor_pixmap_private *source_pixmap_priv,
+ glamor_pixmap_private *mask_pixmap_priv,
+ glamor_pixmap_private *dest_pixmap_priv,
+ RegionPtr region,
+ int x_source,
+ int y_source,
+ int x_mask,
+ int y_mask,
+ int x_dest,
+ int y_dest)
+{
+ ScreenPtr screen = dest->pDrawable->pScreen;
+ PixmapPtr source_pixmap = NULL, mask_pixmap = NULL;
+ PicturePtr temp_src = source, temp_mask = mask;
+ glamor_pixmap_private *temp_src_priv = source_pixmap_priv;
+ glamor_pixmap_private *temp_mask_priv = mask_pixmap_priv;
+ int x_temp_src, y_temp_src, x_temp_mask, y_temp_mask;
+ BoxPtr extent;
+ glamor_composite_rect_t rect[10];
+ glamor_composite_rect_t *prect = rect;
+ int prect_size = ARRAY_SIZE(rect);
+ int ok = FALSE;
+ int i;
+ int width;
+ int height;
+ BoxPtr box;
+ int nbox;
+ Bool two_pass_ca = FALSE;
+
+ extent = RegionExtents(region);
+ box = RegionRects(region);
+ nbox = RegionNumRects(region);
+ width = extent->x2 - extent->x1;
+ height = extent->y2 - extent->y1;
+
+ x_temp_src = x_source;
+ y_temp_src = y_source;
+ x_temp_mask = x_mask;
+ y_temp_mask = y_mask;
+
+ DEBUGF("clipped (%d %d) (%d %d) (%d %d) width %d height %d \n",
+ x_source, y_source, x_mask, y_mask, x_dest, y_dest, width, height);
+
+ if (source_pixmap_priv)
+ source_pixmap = source_pixmap_priv->base.pixmap;
+
+ if (mask_pixmap_priv)
+ mask_pixmap = mask_pixmap_priv->base.pixmap;
+
+ /* XXX is it possible source mask have non-zero drawable.x/y? */
+ if (source
+ && ((!source->pDrawable
+ && (source->pSourcePict->type != SourcePictTypeSolidFill))
+ || (source->pDrawable
+ && !GLAMOR_PIXMAP_PRIV_HAS_FBO(source_pixmap_priv)
+ && (source_pixmap->drawable.width != width
+ || source_pixmap->drawable.height != height)))) {
+ temp_src =
+ glamor_convert_gradient_picture(screen, source,
+ extent->x1 + x_source - x_dest,
+ extent->y1 + y_source - y_dest,
+ width, height);
+ if (!temp_src) {
+ temp_src = source;
+ goto out;
+ }
+ temp_src_priv = glamor_get_pixmap_private((PixmapPtr)(temp_src->pDrawable));
+ x_temp_src = - extent->x1 + x_dest;
+ y_temp_src = - extent->y1 + y_dest;
+ }
+
+ if (mask
+ &&
+ ((!mask->pDrawable
+ && (mask->pSourcePict->type != SourcePictTypeSolidFill))
+ || (mask->pDrawable
+ && !GLAMOR_PIXMAP_PRIV_HAS_FBO(mask_pixmap_priv)
+ && (mask_pixmap->drawable.width != width
+ || mask_pixmap->drawable.height != height)))) {
+ /* XXX if mask->pDrawable is the same as source->pDrawable, we have an opportunity
+ * to do reduce one convertion. */
+ temp_mask =
+ glamor_convert_gradient_picture(screen, mask,
+ extent->x1 + x_mask - x_dest,
+ extent->y1 + y_mask - y_dest,
+ width, height);
+ if (!temp_mask) {
+ temp_mask = mask;
+ goto out;
+ }
+ temp_mask_priv = glamor_get_pixmap_private((PixmapPtr)(temp_mask->pDrawable));
+ x_temp_mask = - extent->x1 + x_dest;
+ y_temp_mask = - extent->y1 + y_dest;
+ }
+ /* Do two-pass PictOpOver componentAlpha, until we enable
+ * dual source color blending.
+ */
+
+ if (mask && mask->componentAlpha) {
+ if (op == PictOpOver) {
+ two_pass_ca = TRUE;
+ op = PictOpOutReverse;
+ }
+ }
+
+ if (!mask && temp_src) {
+ if (glamor_composite_with_copy(op, temp_src, dest,
+ x_temp_src, y_temp_src,
+ x_dest, y_dest, region)) {
+ ok = TRUE;
+ goto out;
+ }
+ }
+
+ /*XXXXX, self copy?*/
+
+ x_dest += dest->pDrawable->x;
+ y_dest += dest->pDrawable->y;
+ if (temp_src && temp_src->pDrawable) {
+ x_temp_src += temp_src->pDrawable->x;
+ y_temp_src += temp_src->pDrawable->y;
+ }
+ if (temp_mask && temp_mask->pDrawable) {
+ x_temp_mask += temp_mask->pDrawable->x;
+ y_temp_mask += temp_mask->pDrawable->y;
+ }
+
+ if (nbox > ARRAY_SIZE(rect)) {
+ prect = calloc(nbox, sizeof(*prect));
+ if (prect)
+ prect_size = nbox;
+ else {
+ prect = rect;
+ prect_size = ARRAY_SIZE(rect);
+ }
+ }
+ while(nbox) {
+ int box_cnt;
+ box_cnt = nbox > prect_size ? prect_size : nbox;
+ for (i = 0; i < box_cnt; i++) {
+ prect[i].x_src = box[i].x1 + x_temp_src - x_dest;
+ prect[i].y_src = box[i].y1 + y_temp_src - y_dest;
+ prect[i].x_mask = box[i].x1 + x_temp_mask - x_dest;
+ prect[i].y_mask = box[i].y1 + y_temp_mask - y_dest;
+ prect[i].x_dst = box[i].x1;
+ prect[i].y_dst = box[i].y1;
+ prect[i].width = box[i].x2 - box[i].x1;
+ prect[i].height = box[i].y2 - box[i].y1;
+ DEBUGF("dest %d %d \n", prect[i].x_dst, prect[i].y_dst);
+ }
+ ok = glamor_composite_with_shader(op, temp_src, temp_mask, dest,
+ temp_src_priv, temp_mask_priv,
+ dest_pixmap_priv,
+ box_cnt, prect, two_pass_ca);
+ if (!ok)
+ break;
+ nbox -= box_cnt;
+ box += box_cnt;
+ }
+
+ if (prect != rect)
+ free(prect);
+out:
+ if (temp_src != source)
+ FreePicture(temp_src, 0);
+ if (temp_mask != mask)
+ FreePicture(temp_mask, 0);
+
+ return ok;
+}
+
+static Bool
+_glamor_composite(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ INT16 x_source,
+ INT16 y_source,
+ INT16 x_mask,
+ INT16 y_mask,
+ INT16 x_dest, INT16 y_dest,
+ CARD16 width, CARD16 height, Bool fallback)
+{
+ ScreenPtr screen = dest->pDrawable->pScreen;
+ glamor_pixmap_private *dest_pixmap_priv;
+ glamor_pixmap_private *source_pixmap_priv =
+ NULL, *mask_pixmap_priv = NULL;
+ PixmapPtr dest_pixmap =
+ glamor_get_drawable_pixmap(dest->pDrawable);
+ PixmapPtr source_pixmap = NULL, mask_pixmap = NULL;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ Bool ret = TRUE;
+ RegionRec region;
+ BoxPtr extent;
+ int nbox, ok = FALSE;
+ PixmapPtr sub_dest_pixmap = NULL;
+ PixmapPtr sub_source_pixmap = NULL;
+ PixmapPtr sub_mask_pixmap = NULL;
+ int dest_x_off, dest_y_off, saved_dest_x, saved_dest_y;
+ int source_x_off, source_y_off, saved_source_x, saved_source_y;
+ int mask_x_off, mask_y_off, saved_mask_x, saved_mask_y;
+ DrawablePtr saved_dest_drawable;
+ DrawablePtr saved_source_drawable;
+ DrawablePtr saved_mask_drawable;
+ int force_clip = 0;
+ dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
+
+ if (source->pDrawable) {
+ source_pixmap = glamor_get_drawable_pixmap(source->pDrawable);
+ source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
+ if (source_pixmap_priv && source_pixmap_priv->type == GLAMOR_DRM_ONLY)
+ goto fail;
+ }
+
+ if (mask && mask->pDrawable) {
+ mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable);
+ mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap);
+ if (mask_pixmap_priv && mask_pixmap_priv->type == GLAMOR_DRM_ONLY)
+ goto fail;
+ }
+
+ DEBUGF("source pixmap %p (%d %d) mask(%d %d) dest(%d %d) width %d height %d \n",
+ source_pixmap, x_source, y_source, x_mask, y_mask, x_dest, y_dest, width, height);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) {
+ goto fail;
+ }
+
+ if (op >= ARRAY_SIZE(composite_op_info))
+ goto fail;
+
+ if (mask && mask->componentAlpha) {
+ if (op == PictOpAtop
+ || op == PictOpAtopReverse
+ || op == PictOpXor
+ || op >= PictOpSaturate) {
+ glamor_fallback
+ ("glamor_composite(): component alpha op %x\n", op);
+ goto fail;
+ }
+ }
+
+ if ((source && source->filter >= PictFilterConvolution)
+ || (mask && mask->filter >= PictFilterConvolution)) {
+ glamor_fallback("glamor_composite(): unsupported filter\n");
+ goto fail;
+ }
+
+ if (!miComputeCompositeRegion(&region,
+ source, mask, dest,
+ x_source + (source_pixmap ? source->pDrawable->x : 0),
+ y_source + (source_pixmap ? source->pDrawable->y : 0),
+ x_mask + (mask_pixmap ? mask->pDrawable->x : 0),
+ y_mask + (mask_pixmap ? mask->pDrawable->y : 0),
+ x_dest + dest->pDrawable->x,
+ y_dest + dest->pDrawable->y,
+ width,
+ height)) {
+ ret = TRUE;
+ goto done;
+ }
+
+ nbox = REGION_NUM_RECTS(&region);
+ DEBUGF("first clipped when compositing.\n");
+ DEBUGRegionPrint(&region);
+ extent = RegionExtents(&region);
+ if (nbox == 0) {
+ ret = TRUE;
+ goto done;
+ }
+ /* If destination is not a large pixmap, but the region is larger
+ * than texture size limitation, and source or mask is memory pixmap,
+ * then there may be need to load a large memory pixmap to a
+ * texture, and this is not permitted. Then we force to clip the
+ * destination and make sure latter will not upload a large memory
+ * pixmap. */
+ if (!glamor_check_fbo_size(glamor_priv,
+ extent->x2 - extent->x1, extent->y2 - extent->y1)
+ && (dest_pixmap_priv->type != GLAMOR_TEXTURE_LARGE)
+ && ((source_pixmap_priv
+ && (source_pixmap_priv->type == GLAMOR_MEMORY || source->repeatType == RepeatPad))
+ || (mask_pixmap_priv
+ && (mask_pixmap_priv->type == GLAMOR_MEMORY || mask->repeatType == RepeatPad))
+ || (!source_pixmap_priv
+ && (source->pSourcePict->type != SourcePictTypeSolidFill))
+ || (!mask_pixmap_priv && mask
+ && mask->pSourcePict->type != SourcePictTypeSolidFill)))
+ force_clip = 1;
+
+ if (force_clip || dest_pixmap_priv->type == GLAMOR_TEXTURE_LARGE
+ || (source_pixmap_priv
+ && source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE)
+ || (mask_pixmap_priv
+ && mask_pixmap_priv->type == GLAMOR_TEXTURE_LARGE))
+ ok = glamor_composite_largepixmap_region(op,
+ source, mask, dest,
+ source_pixmap_priv,
+ mask_pixmap_priv,
+ dest_pixmap_priv,
+ &region, force_clip,
+ x_source, y_source,
+ x_mask, y_mask,
+ x_dest, y_dest,
+ width, height);
+ else
+ ok = glamor_composite_clipped_region(op, source,
+ mask, dest,
+ source_pixmap_priv,
+ mask_pixmap_priv,
+ dest_pixmap_priv,
+ &region,
+ x_source, y_source,
+ x_mask, y_mask,
+ x_dest, y_dest);
+
+ REGION_UNINIT(dest->pDrawable->pScreen, &region);
+
+ if (ok)
+ goto done;
+fail:
+
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(&dest_pixmap->drawable)
+ && (!source_pixmap
+ || glamor_ddx_fallback_check_pixmap(&source_pixmap->drawable))
+ && (!mask_pixmap
+ || glamor_ddx_fallback_check_pixmap(&mask_pixmap->drawable))) {
+ ret = FALSE;
+ goto done;
+ }
+
+ glamor_fallback
+ ("from picts %p:%p %dx%d / %p:%p %d x %d (%c,%c) to pict %p:%p %dx%d (%c)\n",
+ source, source->pDrawable,
+ source->pDrawable ? source->pDrawable->width : 0,
+ source->pDrawable ? source->pDrawable->height : 0, mask,
+ (!mask) ? NULL : mask->pDrawable, (!mask
+ || !mask->pDrawable) ? 0 :
+ mask->pDrawable->width, (!mask
+ || !mask->
+ pDrawable) ? 0 : mask->pDrawable->
+ height, glamor_get_picture_location(source),
+ glamor_get_picture_location(mask), dest, dest->pDrawable,
+ dest->pDrawable->width, dest->pDrawable->height,
+ glamor_get_picture_location(dest));
+
+#define GET_SUB_PICTURE(p, access) do { \
+ glamor_get_drawable_deltas(p->pDrawable, p ##_pixmap, \
+ & p ##_x_off, & p ##_y_off); \
+ sub_ ##p ##_pixmap = glamor_get_sub_pixmap(p ##_pixmap, \
+ x_ ##p + p ##_x_off + p->pDrawable->x, \
+ y_ ##p + p ##_y_off + p->pDrawable->y, \
+ width, height, access); \
+ if (sub_ ##p ##_pixmap != NULL) { \
+ saved_ ##p ##_drawable = p->pDrawable; \
+ saved_ ##p ##_x = x_ ##p; \
+ saved_ ##p ##_y = y_ ##p; \
+ if (p->pCompositeClip) \
+ pixman_region_translate (p->pCompositeClip, \
+ -p->pDrawable->x - x_ ##p, \
+ -p->pDrawable->y - y_ ##p); \
+ p->pDrawable = &sub_ ##p ##_pixmap->drawable; \
+ x_ ##p = 0; \
+ y_ ##p = 0; \
+ } } while(0)
+ GET_SUB_PICTURE(dest, GLAMOR_ACCESS_RW);
+ if (source->pDrawable && !source->transform)
+ GET_SUB_PICTURE(source, GLAMOR_ACCESS_RO);
+ if (mask && mask->pDrawable && !mask->transform)
+ GET_SUB_PICTURE(mask, GLAMOR_ACCESS_RO);
+
+ if (glamor_prepare_access_picture(dest, GLAMOR_ACCESS_RW)) {
+ if (source_pixmap == dest_pixmap || glamor_prepare_access_picture
+ (source, GLAMOR_ACCESS_RO)) {
+ if (!mask
+ || glamor_prepare_access_picture(mask,
+ GLAMOR_ACCESS_RO))
+ {
+ fbComposite(op,
+ source, mask, dest,
+ x_source, y_source,
+ x_mask, y_mask, x_dest,
+ y_dest, width, height);
+ if (mask)
+ glamor_finish_access_picture(mask, GLAMOR_ACCESS_RO);
+ }
+ if (source_pixmap != dest_pixmap)
+ glamor_finish_access_picture(source, GLAMOR_ACCESS_RO);
+ }
+ glamor_finish_access_picture(dest, GLAMOR_ACCESS_RW);
+ }
+
+#define PUT_SUB_PICTURE(p, access) do { \
+ if (sub_ ##p ##_pixmap != NULL) { \
+ x_ ##p = saved_ ##p ##_x; \
+ y_ ##p = saved_ ##p ##_y; \
+ p->pDrawable = saved_ ##p ##_drawable; \
+ if (p->pCompositeClip) \
+ pixman_region_translate (p->pCompositeClip, \
+ p->pDrawable->x + x_ ##p, \
+ p->pDrawable->y + y_ ##p); \
+ glamor_put_sub_pixmap(sub_ ##p ##_pixmap, p ##_pixmap, \
+ x_ ##p + p ##_x_off + p->pDrawable->x, \
+ y_ ##p + p ##_y_off + p->pDrawable->y, \
+ width, height, access); \
+ }} while(0)
+ if (mask && mask->pDrawable)
+ PUT_SUB_PICTURE(mask, GLAMOR_ACCESS_RO);
+ if (source->pDrawable)
+ PUT_SUB_PICTURE(source, GLAMOR_ACCESS_RO);
+ PUT_SUB_PICTURE(dest, GLAMOR_ACCESS_RW);
+ done:
+ return ret;
+}
+
+void
+glamor_composite(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ INT16 x_source,
+ INT16 y_source,
+ INT16 x_mask,
+ INT16 y_mask,
+ INT16 x_dest, INT16 y_dest,
+ CARD16 width, CARD16 height)
+{
+ _glamor_composite(op, source, mask, dest, x_source, y_source,
+ x_mask, y_mask, x_dest, y_dest, width, height,
+ TRUE);
+}
+
+Bool
+glamor_composite_nf(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ INT16 x_source,
+ INT16 y_source,
+ INT16 x_mask,
+ INT16 y_mask,
+ INT16 x_dest, INT16 y_dest,
+ CARD16 width, CARD16 height)
+{
+ return _glamor_composite(op, source, mask, dest, x_source, y_source,
+ x_mask, y_mask, x_dest, y_dest, width, height,
+ FALSE);
+}
+
+static void
+glamor_get_src_rect_extent(int nrect,
+ glamor_composite_rect_t *rects,
+ BoxPtr extent)
+{
+ extent->x1 = MAXSHORT;
+ extent->y1 = MAXSHORT;
+ extent->x2 = MINSHORT;
+ extent->y2 = MINSHORT;
+
+ while(nrect--) {
+ if (extent->x1 > rects->x_src)
+ extent->x1 = rects->x_src;
+ if (extent->y1 > rects->y_src)
+ extent->y1 = rects->y_src;
+ if (extent->x2 < rects->x_src + rects->width)
+ extent->x2 = rects->x_src + rects->width;
+ if (extent->y2 < rects->y_src + rects->height)
+ extent->y2 = rects->y_src + rects->height;
+ rects++;
+ }
+}
+
+static void
+glamor_composite_src_rect_translate(int nrect,
+ glamor_composite_rect_t *rects,
+ int x, int y)
+{
+ while(nrect--) {
+ rects->x_src += x;
+ rects->y_src += y;
+ rects++;
+ }
+}
+
+void
+glamor_composite_glyph_rects(CARD8 op,
+ PicturePtr src, PicturePtr mask, PicturePtr dst,
+ int nrect, glamor_composite_rect_t * rects)
+{
+ int n;
+ PicturePtr temp_src = NULL;
+ glamor_composite_rect_t *r;
+
+ ValidatePicture(src);
+ ValidatePicture(dst);
+ if (!(glamor_is_large_picture(src)
+ || (mask && glamor_is_large_picture(mask))
+ || glamor_is_large_picture(dst))) {
+ glamor_pixmap_private *src_pixmap_priv = NULL;
+ glamor_pixmap_private *mask_pixmap_priv = NULL;
+ glamor_pixmap_private *dst_pixmap_priv;
+ glamor_pixmap_private *temp_src_priv = NULL;
+ BoxRec src_extent;
+
+ dst_pixmap_priv = glamor_get_pixmap_private
+ (glamor_get_drawable_pixmap(dst->pDrawable));
+
+ if (mask && mask->pDrawable)
+ mask_pixmap_priv = glamor_get_pixmap_private
+ (glamor_get_drawable_pixmap(mask->pDrawable));
+ if (src->pDrawable)
+ src_pixmap_priv = glamor_get_pixmap_private
+ (glamor_get_drawable_pixmap(src->pDrawable));
+
+ if (!src->pDrawable
+ && (src->pSourcePict->type != SourcePictTypeSolidFill)) {
+ glamor_get_src_rect_extent(nrect, rects, &src_extent);
+ temp_src = glamor_convert_gradient_picture(dst->pDrawable->pScreen,
+ src,
+ src_extent.x1, src_extent.y1,
+ src_extent.x2 - src_extent.x1,
+ src_extent.y2 - src_extent.y1);
+ if (!temp_src)
+ goto fallback;
+
+ temp_src_priv = glamor_get_pixmap_private
+ ((PixmapPtr)(temp_src->pDrawable));
+ glamor_composite_src_rect_translate(nrect, rects,
+ -src_extent.x1, -src_extent.y1);
+ } else {
+ temp_src = src;
+ temp_src_priv = src_pixmap_priv;
+ }
+
+ if (mask && mask->componentAlpha) {
+ if (op == PictOpOver) {
+ if (glamor_composite_with_shader(PictOpOutReverse,
+ temp_src, mask, dst, temp_src_priv,
+ mask_pixmap_priv, dst_pixmap_priv, nrect, rects,
+ TRUE))
+ goto done;
+ }
+ } else {
+ if (glamor_composite_with_shader(op, temp_src, mask, dst, temp_src_priv,
+ mask_pixmap_priv, dst_pixmap_priv, nrect, rects, FALSE))
+ goto done;
+ }
+ }
+fallback:
+ n = nrect;
+ r = rects;
+
+ while (n--) {
+ CompositePicture(op,
+ temp_src ? temp_src : src,
+ mask,
+ dst,
+ r->x_src, r->y_src,
+ r->x_mask, r->y_mask,
+ r->x_dst, r->y_dst, r->width, r->height);
+ r++;
+ }
+
+done:
+ if (temp_src && temp_src != src)
+ FreePicture(temp_src, 0);
+}
+
+static Bool
+_glamor_composite_rects (CARD8 op,
+ PicturePtr pDst,
+ xRenderColor *color,
+ int nRect,
+ xRectangle *rects,
+ Bool fallback)
+{
+ miCompositeRects(op, pDst, color, nRect, rects);
+ return TRUE;
+}
+
+void
+glamor_composite_rects (CARD8 op,
+ PicturePtr pDst,
+ xRenderColor *color,
+ int nRect,
+ xRectangle *rects)
+{
+ _glamor_composite_rects(op, pDst, color, nRect, rects, TRUE);
+}
+
+Bool
+glamor_composite_rects_nf (CARD8 op,
+ PicturePtr pDst,
+ xRenderColor *color,
+ int nRect,
+ xRectangle *rects)
+{
+ return _glamor_composite_rects(op, pDst, color, nRect, rects, FALSE);
+}
+
+#endif /* RENDER */
diff --git a/glamor/glamor_setspans.c b/glamor/glamor_setspans.c
new file mode 100644
index 000000000..3d447b606
--- /dev/null
+++ b/glamor/glamor_setspans.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ *
+ */
+
+#include "glamor_priv.h"
+
+static Bool
+_glamor_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
+ DDXPointPtr points, int *widths, int numPoints, int sorted,
+ Bool fallback)
+{
+ PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(drawable);
+ glamor_pixmap_private *dest_pixmap_priv;
+ int i;
+ uint8_t *drawpixels_src = (uint8_t *) src;
+ RegionPtr clip = fbGetCompositeClip(gc);
+ BoxRec *pbox;
+ int x_off, y_off;
+ Bool ret = FALSE;
+
+ dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) {
+ glamor_fallback("pixmap has no fbo.\n");
+ goto fail;
+ }
+
+ /* XXX Shall we set alu here? */
+ if (!glamor_set_planemask(dest_pixmap, gc->planemask))
+ goto fail;
+
+ glamor_get_drawable_deltas(drawable, dest_pixmap, &x_off, &y_off);
+ for (i = 0; i < numPoints; i++) {
+
+ int n = REGION_NUM_RECTS(clip);
+ pbox = REGION_RECTS(clip);
+ while (n--) {
+ int x1 = points[i].x;
+ int x2 = x1 + widths[i];
+ int y1 = points[i].y;
+
+ if (pbox->y1 > points[i].y || pbox->y2 < points[i].y)
+ break;
+ x1 = x1 > pbox->x1 ? x1 : pbox->x1;
+ x2 = x2 < pbox->x2 ? x2 : pbox->x2;
+ if (x1 >= x2)
+ continue;
+ glamor_upload_sub_pixmap_to_texture(dest_pixmap, x1 + x_off, y1 + y_off, x2 - x1, 1,
+ PixmapBytePad(widths[i], drawable->depth),
+ drawpixels_src, 0);
+ }
+ drawpixels_src += PixmapBytePad(widths[i], drawable->depth);
+ }
+ ret = TRUE;
+ goto done;
+
+fail:
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(drawable))
+ goto done;
+
+ glamor_fallback("to %p (%c)\n",
+ drawable, glamor_get_drawable_location(drawable));
+ if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW)) {
+ fbSetSpans(drawable, gc, src, points, widths, numPoints, sorted);
+ glamor_finish_access(drawable, GLAMOR_ACCESS_RW);
+ }
+ ret = TRUE;
+
+done:
+ return ret;
+}
+
+void
+glamor_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
+ DDXPointPtr points, int *widths, int n, int sorted)
+{
+ _glamor_set_spans(drawable, gc, src, points,
+ widths, n, sorted, TRUE);
+}
+
+Bool
+glamor_set_spans_nf(DrawablePtr drawable, GCPtr gc, char *src,
+ DDXPointPtr points, int *widths, int n, int sorted)
+{
+ return _glamor_set_spans(drawable, gc, src, points,
+ widths, n, sorted, FALSE);
+}
diff --git a/glamor/glamor_tile.c b/glamor/glamor_tile.c
new file mode 100644
index 000000000..60486cfc0
--- /dev/null
+++ b/glamor/glamor_tile.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * 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:
+ * Eric Anholt <eric@anholt.net>
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ *
+ */
+
+#include "glamor_priv.h"
+
+/** @file glamor_tile.c
+ *
+ * Implements the basic fill-with-a-tile support used by multiple GC ops.
+ */
+
+void
+glamor_init_tile_shader(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ const char *tile_vs =
+ "attribute vec4 v_position;\n"
+ "attribute vec4 v_texcoord0;\n"
+ "varying vec2 tile_texture;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = v_position;\n"
+ " tile_texture = v_texcoord0.xy;\n" "}\n";
+ const char *tile_fs =
+ GLAMOR_DEFAULT_PRECISION
+ "varying vec2 tile_texture;\n"
+ "uniform sampler2D sampler;\n"
+ "uniform vec2 wh;"
+ "void main()\n"
+ "{\n"
+ " vec2 rel_tex;"
+ " rel_tex = tile_texture * wh; \n"
+ " rel_tex = floor(rel_tex) + (fract(rel_tex) / wh); \n"
+ " gl_FragColor = texture2D(sampler, rel_tex);\n"
+ "}\n";
+ GLint fs_prog, vs_prog;
+ GLint sampler_uniform_location;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+ glamor_priv->tile_prog = dispatch->glCreateProgram();
+ vs_prog = glamor_compile_glsl_prog(dispatch, GL_VERTEX_SHADER, tile_vs);
+ fs_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER,
+ tile_fs);
+ dispatch->glAttachShader(glamor_priv->tile_prog, vs_prog);
+ dispatch->glAttachShader(glamor_priv->tile_prog, fs_prog);
+
+ dispatch->glBindAttribLocation(glamor_priv->tile_prog,
+ GLAMOR_VERTEX_POS, "v_position");
+ dispatch->glBindAttribLocation(glamor_priv->tile_prog,
+ GLAMOR_VERTEX_SOURCE,
+ "v_texcoord0");
+ glamor_link_glsl_prog(dispatch, glamor_priv->tile_prog);
+
+ sampler_uniform_location =
+ dispatch->glGetUniformLocation(glamor_priv->tile_prog,
+ "sampler");
+ dispatch->glUseProgram(glamor_priv->tile_prog);
+ dispatch->glUniform1i(sampler_uniform_location, 0);
+
+ glamor_priv->tile_wh =
+ dispatch->glGetUniformLocation(glamor_priv->tile_prog,
+ "wh");
+ dispatch->glUseProgram(0);
+ glamor_put_dispatch(glamor_priv);
+}
+
+void
+glamor_fini_tile_shader(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glDeleteProgram(glamor_priv->tile_prog);
+ glamor_put_dispatch(glamor_priv);
+}
+
+static void
+_glamor_tile(PixmapPtr pixmap, PixmapPtr tile,
+ int x, int y, int width, int height,
+ int tile_x, int tile_y)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch;
+ int x1 = x;
+ int x2 = x + width;
+ int y1 = y;
+ int y2 = y + height;
+ int tile_x1 = tile_x;
+ int tile_x2 = tile_x + width;
+ int tile_y1 = tile_y;
+ int tile_y2 = tile_y + height;
+ float vertices[8];
+ float source_texcoords[8];
+ GLfloat dst_xscale, dst_yscale, src_xscale, src_yscale;
+ glamor_pixmap_private *src_pixmap_priv;
+ glamor_pixmap_private *dst_pixmap_priv;
+ float wh[4];
+ src_pixmap_priv = glamor_get_pixmap_private(tile);
+ dst_pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ glamor_set_destination_pixmap_priv_nc(dst_pixmap_priv);
+ pixmap_priv_get_dest_scale(dst_pixmap_priv, &dst_xscale, &dst_yscale);
+ pixmap_priv_get_scale(src_pixmap_priv, &src_xscale,
+ &src_yscale);
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glUseProgram(glamor_priv->tile_prog);
+
+ glamor_pixmap_fbo_fix_wh_ratio(wh, src_pixmap_priv);
+ dispatch->glUniform2fv(glamor_priv->tile_wh, 1, wh);
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glBindTexture(GL_TEXTURE_2D,
+ src_pixmap_priv->base.fbo->tex);
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ GL_REPEAT);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ GL_REPEAT);
+#ifndef GLAMOR_GLES2
+ dispatch->glEnable(GL_TEXTURE_2D);
+#endif
+ glamor_set_repeat_normalize_tcoords
+ (src_pixmap_priv, RepeatNormal,
+ src_xscale, src_yscale,
+ tile_x1, tile_y1,
+ tile_x2, tile_y2,
+ glamor_priv->yInverted,
+ source_texcoords);
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2,
+ GL_FLOAT, GL_FALSE,
+ 2 * sizeof(float),
+ source_texcoords);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+
+ glamor_set_normalize_vcoords(dst_pixmap_priv, dst_xscale, dst_yscale,
+ x1, y1,
+ x2, y2,
+ glamor_priv->yInverted, vertices);
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
+ GL_FALSE, 2 * sizeof(float),
+ vertices);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+#ifndef GLAMOR_GLES2
+ dispatch->glDisable(GL_TEXTURE_2D);
+#endif
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glUseProgram(0);
+ glamor_put_dispatch(glamor_priv);
+
+ glamor_priv->state = RENDER_STATE;
+ glamor_priv->render_idle_cnt = 0;
+}
+
+Bool
+glamor_tile(PixmapPtr pixmap, PixmapPtr tile,
+ int x, int y, int width, int height,
+ unsigned char alu, unsigned long planemask,
+ int tile_x, int tile_y)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_pixmap_private *dst_pixmap_priv;
+ glamor_pixmap_private *src_pixmap_priv;
+ glamor_gl_dispatch *dispatch;
+
+ dst_pixmap_priv = glamor_get_pixmap_private(pixmap);
+ src_pixmap_priv = glamor_get_pixmap_private(tile);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv))
+ return FALSE;
+
+ if (glamor_priv->tile_prog == 0) {
+ glamor_fallback("Tiling unsupported\n");
+ goto fail;
+ }
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)) {
+ /* XXX dynamic uploading candidate. */
+ glamor_fallback("Non-texture tile pixmap\n");
+ goto fail;
+ }
+
+ if (!glamor_set_planemask(pixmap, planemask)) {
+ glamor_fallback("unsupported planemask %lx\n", planemask);
+ goto fail;
+ }
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ if (!glamor_set_alu(dispatch, alu)) {
+ glamor_fallback("unsupported alu %x\n", alu);
+ glamor_put_dispatch(glamor_priv);
+ goto fail;
+ }
+
+ if (dst_pixmap_priv->type == GLAMOR_TEXTURE_LARGE
+ || src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ glamor_pixmap_clipped_regions *clipped_dst_regions;
+ int n_dst_region, i, j, k;
+ BoxRec box;
+ RegionRec region;
+
+ box.x1 = x;
+ box.y1 = y;
+ box.x2 = x + width;
+ box.y2 = y + height;
+ RegionInitBoxes(&region, &box, 1);
+ clipped_dst_regions = glamor_compute_clipped_regions(dst_pixmap_priv,
+ &region, &n_dst_region, 0, 0, 0);
+ for(i = 0; i < n_dst_region; i++)
+ {
+ int n_src_region;
+ glamor_pixmap_clipped_regions *clipped_src_regions;
+ BoxPtr current_boxes;
+ int n_current_boxes;
+
+ SET_PIXMAP_FBO_CURRENT(dst_pixmap_priv, clipped_dst_regions[i].block_idx);
+
+ if (src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ RegionTranslate(clipped_dst_regions[i].region,
+ tile_x - x, tile_y - y);
+ DEBUGF("tiled a large src pixmap. %dx%d \n", tile->drawable.width, tile->drawable.height);
+ clipped_src_regions = glamor_compute_clipped_regions(src_pixmap_priv,
+ clipped_dst_regions[i].region,
+ &n_src_region, 1, 0, 0);
+ DEBUGF("got %d src regions %d \n", n_src_region);
+ for (j = 0; j < n_src_region; j++)
+ {
+
+ SET_PIXMAP_FBO_CURRENT(src_pixmap_priv, clipped_src_regions[j].block_idx);
+
+ RegionTranslate(clipped_src_regions[j].region,
+ x - tile_x,
+ y - tile_y);
+ current_boxes = RegionRects(clipped_src_regions[j].region);
+ n_current_boxes = RegionNumRects(clipped_src_regions[j].region);
+ for(k = 0; k < n_current_boxes; k++)
+ {
+ DEBUGF("Tile on %d %d %d %d dst block id %d tile block id %d tilex %d tiley %d\n",
+ current_boxes[k].x1, current_boxes[k].y1,
+ current_boxes[k].x2 - current_boxes[k].x1,
+ current_boxes[k].y2 - current_boxes[k].y1,
+ clipped_dst_regions[i].block_idx,
+ clipped_src_regions[j].block_idx,
+ (tile_x + (current_boxes[k].x1 - x)),
+ tile_y + (current_boxes[k].y1 - y));
+
+ _glamor_tile(pixmap, tile,
+ current_boxes[k].x1, current_boxes[k].y1,
+ current_boxes[k].x2 - current_boxes[k].x1,
+ current_boxes[k].y2 - current_boxes[k].y1,
+ (tile_x + (current_boxes[k].x1 - x)),
+ (tile_y + (current_boxes[k].y1 - y)));
+ }
+
+ RegionDestroy(clipped_src_regions[j].region);
+ }
+ free(clipped_src_regions);
+ } else {
+ current_boxes = RegionRects(clipped_dst_regions[i].region);
+ n_current_boxes = RegionNumRects(clipped_dst_regions[i].region);
+ for(k = 0; k < n_current_boxes; k++)
+ {
+ _glamor_tile(pixmap, tile,
+ current_boxes[k].x1, current_boxes[k].y1,
+ current_boxes[k].x2 - current_boxes[k].x1,
+ current_boxes[k].y2 - current_boxes[k].y1,
+ (tile_x + (current_boxes[k].x1 - x)),
+ (tile_y + (current_boxes[k].y1 - y)));
+ }
+ }
+ RegionDestroy(clipped_dst_regions[i].region);
+ }
+ free(clipped_dst_regions);
+ RegionUninit(&region);
+ }
+ else
+ _glamor_tile(pixmap, tile, x, y, width, height, tile_x, tile_y);
+
+ glamor_set_alu(dispatch, GXcopy);
+ glamor_put_dispatch(glamor_priv);
+ return TRUE;
+fail:
+ return FALSE;
+
+}
diff --git a/glamor/glamor_trapezoid.c b/glamor/glamor_trapezoid.c
new file mode 100644
index 000000000..76b3729cf
--- /dev/null
+++ b/glamor/glamor_trapezoid.c
@@ -0,0 +1,1819 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * 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:
+ * Junyan He <junyan.he@linux.intel.com>
+ *
+ */
+
+/** @file glamor_trapezoid.c
+ *
+ * Trapezoid acceleration implementation
+ */
+
+#include "glamor_priv.h"
+
+#ifdef RENDER
+#include "mipict.h"
+#include "fbpict.h"
+
+static xFixed
+_glamor_linefixedX (xLineFixed *l, xFixed y, Bool ceil)
+{
+ xFixed dx = l->p2.x - l->p1.x;
+ xFixed_32_32 ex = (xFixed_32_32) (y - l->p1.y) * dx;
+ xFixed dy = l->p2.y - l->p1.y;
+ if (ceil)
+ ex += (dy - 1);
+ return l->p1.x + (xFixed) (ex / dy);
+}
+
+static xFixed
+_glamor_linefixedY (xLineFixed *l, xFixed x, Bool ceil)
+{
+ xFixed dy = l->p2.y - l->p1.y;
+ xFixed_32_32 ey = (xFixed_32_32) (x - l->p1.x) * dy;
+ xFixed dx = l->p2.x - l->p1.x;
+ if (ceil)
+ ey += (dx - 1);
+ return l->p1.y + (xFixed) (ey / dx);
+}
+
+#ifdef GLAMOR_TRAPEZOID_SHADER
+
+#define GLAMOR_VERTEX_TOP_BOTTOM (GLAMOR_VERTEX_SOURCE + 1)
+#define GLAMOR_VERTEX_LEFT_PARAM (GLAMOR_VERTEX_SOURCE + 2)
+#define GLAMOR_VERTEX_RIGHT_PARAM (GLAMOR_VERTEX_SOURCE + 3)
+
+#define DEBUG_CLIP_VTX 0
+
+#define POINT_INSIDE_CLIP_RECT(point, rect) \
+ (point[0] >= IntToxFixed(rect->x1) \
+ && point[0] <= IntToxFixed(rect->x2) \
+ && point[1] >= IntToxFixed(rect->y1) \
+ && point[1] <= IntToxFixed(rect->y2))
+
+static xFixed
+_glamor_lines_crossfixedY (xLineFixed *l, xLineFixed *r)
+{
+ xFixed dx1 = l->p2.x - l->p1.x;
+ xFixed dx2 = r->p2.x - r->p1.x;
+ xFixed dy1 = l->p2.y - l->p1.y;
+ xFixed dy2 = r->p2.y - r->p1.y;
+ xFixed_32_32 tmp = (xFixed_32_32) dy2 * dy1;
+ xFixed_32_32 dividend1 = (tmp >> 32) * (l->p1.x - r->p1.x);
+ xFixed_32_32 dividend2;
+ xFixed_32_32 dividend3;
+ xFixed_32_32 divisor;
+
+ tmp = (xFixed_32_32) dx1 * dy2;
+ dividend2 = (tmp >> 32) * l->p1.y;
+ tmp = (xFixed_32_32) dy1 * dx2;
+ dividend3 = (tmp >> 32) * r->p1.y;
+ divisor = ((xFixed_32_32) dx1 * (xFixed_32_32) dy2
+ - (xFixed_32_32) dy1 * (xFixed_32_32) dx2) >> 32;
+
+ if (divisor)
+ return (xFixed)((dividend2 - dividend1 - dividend3) / divisor);
+
+ return 0xFFFFFFFF;
+}
+
+static Bool
+point_inside_trapezoid(int point[2], xTrapezoid * trap, xFixed cut_y)
+{
+ int ret = TRUE;
+ int tmp;
+ if (point[1] > trap->bottom) {
+ ret = FALSE;
+ if (DEBUG_CLIP_VTX) {
+ ErrorF("Out of Trap bottom, point[1] = %d(0x%x)), "
+ "bottom = %d(0x%x)\n",
+ (unsigned int)xFixedToInt(point[1]), point[1],
+ (unsigned int)xFixedToInt(trap->bottom),
+ (unsigned int)trap->bottom);
+ }
+
+ return ret;
+ }
+
+ if (point[1] < trap->top) {
+ ret = FALSE;
+ if (DEBUG_CLIP_VTX) {
+ ErrorF("Out of Trap top, point[1] = %d(0x%x)), "
+ "top = %d(0x%x)\n",
+ (unsigned int)xFixedToInt(point[1]), point[1],
+ (unsigned int)xFixedToInt(trap->top),
+ (unsigned int)trap->top);
+ }
+
+ return ret;
+ }
+
+ tmp = _glamor_linefixedX (&trap->left, point[1], FALSE);
+ if (point[0] < tmp) {
+ ret = FALSE;
+
+ if (abs(cut_y - trap->top) < pixman_fixed_1_minus_e &&
+ abs(point[1] - trap->top) < pixman_fixed_1_minus_e &&
+ tmp - point[0] < pixman_fixed_1_minus_e) {
+ ret = TRUE;
+ } else if (abs(cut_y - trap->bottom) < pixman_fixed_1_minus_e &&
+ point[1] - trap->bottom < pixman_fixed_1_minus_e &&
+ tmp - point[0] < pixman_fixed_1_minus_e) {
+ ret = TRUE;
+ }
+
+ if (DEBUG_CLIP_VTX && !ret) {
+ ErrorF("Out of Trap left, point[0] = %d(0x%x)), "
+ "left = %d(0x%x)\n",
+ (unsigned int)xFixedToInt(point[0]), point[0],
+ (unsigned int)xFixedToInt(tmp), (unsigned int)tmp);
+ }
+
+ if (!ret)
+ return ret;
+ }
+
+ tmp = _glamor_linefixedX (&trap->right, point[1], TRUE);
+ if (point[0] > tmp) {
+ ret = FALSE;
+
+ if (abs(cut_y - trap->top) < pixman_fixed_1_minus_e &&
+ abs(point[1] - trap->top) < pixman_fixed_1_minus_e &&
+ point[0] - tmp < pixman_fixed_1_minus_e) {
+ ret = TRUE;
+ } else if (abs(cut_y - trap->bottom) < pixman_fixed_1_minus_e &&
+ abs(point[1] - trap->bottom) < pixman_fixed_1_minus_e &&
+ point[0] - tmp < pixman_fixed_1_minus_e) {
+ ret = TRUE;
+ }
+
+ if (DEBUG_CLIP_VTX && !ret) {
+ ErrorF("Out of Trap right, point[0] = %d(0x%x)), "
+ "right = %d(0x%x)\n",
+ (unsigned int)xFixedToInt(point[0]), point[0],
+ (unsigned int)xFixedToInt(tmp), (unsigned int)tmp);
+ }
+
+ if (!ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static void
+glamor_emit_composite_triangle(ScreenPtr screen,
+ const float *src_coords,
+ const float *mask_coords,
+ const float *dst_coords)
+{
+ glamor_emit_composite_vert(screen, src_coords, mask_coords,
+ dst_coords, 0);
+ glamor_emit_composite_vert(screen, src_coords, mask_coords,
+ dst_coords, 1);
+ glamor_emit_composite_vert(screen, src_coords, mask_coords,
+ dst_coords, 2);
+}
+
+static void
+glamor_flush_composite_triangles(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
+ dispatch->glUnmapBuffer(GL_ARRAY_BUFFER);
+ else {
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
+ dispatch->glBufferData(GL_ARRAY_BUFFER,
+ glamor_priv->vbo_offset,
+ glamor_priv->vb, GL_DYNAMIC_DRAW);
+ }
+
+ if (!glamor_priv->render_nr_verts)
+ return;
+
+ dispatch->glDrawArrays(GL_TRIANGLES, 0, glamor_priv->render_nr_verts);
+ glamor_put_dispatch(glamor_priv);
+}
+
+static Bool
+_glamor_clip_trapezoid_vertex(xTrapezoid * trap, BoxPtr pbox,
+ int vertex[6], int *num)
+{
+ xFixed edge_cross_y = 0xFFFFFFFF;
+ int tl[2];
+ int bl[2];
+ int tr[2];
+ int br[2];
+ int left_cut_top[2];
+ int left_cut_left[2];
+ int left_cut_right[2];
+ int left_cut_bottom[2];
+ int right_cut_top[2];
+ int right_cut_left[2];
+ int right_cut_right[2];
+ int right_cut_bottom[2];
+ int tmp[2];
+ int tmp_vtx[20*2];
+ float tmp_vtx_slope[20];
+ BoxRec trap_bound;
+ int i = 0;
+ int vertex_num = 0;
+
+ if (DEBUG_CLIP_VTX) {
+ ErrorF("The parameter of xTrapezoid is:\ntop: %d 0x%x\tbottom: %d 0x%x\n"
+ "left: p1 (%d 0x%x, %d 0x%x)\tp2 (%d 0x%x, %d 0x%x)\n"
+ "right: p1 (%d 0x%x, %d 0x%x)\tp2 (%d 0x%x, %d 0x%x)\n",
+ xFixedToInt(trap->top), (unsigned int)trap->top,
+ xFixedToInt(trap->bottom), (unsigned int)trap->bottom,
+ xFixedToInt(trap->left.p1.x), (unsigned int)trap->left.p1.x,
+ xFixedToInt(trap->left.p1.y), (unsigned int)trap->left.p1.y,
+ xFixedToInt(trap->left.p2.x), (unsigned int)trap->left.p2.x,
+ xFixedToInt(trap->left.p2.y), (unsigned int)trap->left.p2.y,
+ xFixedToInt(trap->right.p1.x), (unsigned int)trap->right.p1.x,
+ xFixedToInt(trap->right.p1.y), (unsigned int)trap->right.p1.y,
+ xFixedToInt(trap->right.p2.x), (unsigned int)trap->right.p2.x,
+ xFixedToInt(trap->right.p2.y), (unsigned int)trap->right.p2.y);
+ }
+
+ miTrapezoidBounds(1, trap, &trap_bound);
+ if (DEBUG_CLIP_VTX)
+ ErrorF("The bounds for this traps is: bounds.x1 = %d, bounds.x2 = %d, "
+ "bounds.y1 = %d, bounds.y2 = %d\n", trap_bound.x1, trap_bound.x2,
+ trap_bound.y1, trap_bound.y2);
+
+ if (trap_bound.x1 > pbox->x2 || trap_bound.x2 < pbox->x1)
+ return FALSE;
+ if (trap_bound.y1 > pbox->y2 || trap_bound.y2 < pbox->y1)
+ return FALSE;
+
+#define IS_TRAP_EDGE_VERTICAL(edge) \
+ (edge->p1.x == edge->p2.x)
+
+#define CACULATE_CUT_VERTEX(vtx, cal_x, ceil, vh_edge, edge) \
+ do { \
+ if(cal_x) { \
+ vtx[1] = (vh_edge); \
+ vtx[0] = (_glamor_linefixedX( \
+ edge, vh_edge, ceil)); \
+ if(DEBUG_CLIP_VTX) \
+ ErrorF("The intersection point of line y=%d and " \
+ "line of p1:(%d,%d) -- p2 (%d,%d) " \
+ "is (%d, %d)\n", \
+ xFixedToInt(vh_edge), \
+ xFixedToInt(edge->p1.x), \
+ xFixedToInt(edge->p1.y), \
+ xFixedToInt(edge->p2.x), \
+ xFixedToInt(edge->p2.y), \
+ xFixedToInt(vtx[0]), \
+ xFixedToInt(vtx[1])); \
+ } else { \
+ vtx[0] = (vh_edge); \
+ vtx[1] = (_glamor_linefixedY( \
+ edge, vh_edge, ceil)); \
+ if(DEBUG_CLIP_VTX) \
+ ErrorF("The intersection point of line x=%d and " \
+ "line of p1:(%d,%d) -- p2 (%d,%d) " \
+ "is (%d, %d)\n", \
+ xFixedToInt(vh_edge), \
+ xFixedToInt(edge->p1.x), \
+ xFixedToInt(edge->p1.y), \
+ xFixedToInt(edge->p2.x), \
+ xFixedToInt(edge->p2.y), \
+ xFixedToInt(vtx[0]), \
+ xFixedToInt(vtx[1])); \
+ } \
+ } while(0)
+
+#define ADD_VERTEX_IF_INSIDE(vtx) \
+ if(POINT_INSIDE_CLIP_RECT(vtx, pbox) \
+ && point_inside_trapezoid(vtx, trap, edge_cross_y)){ \
+ tmp_vtx[vertex_num] = xFixedToInt(vtx[0]); \
+ tmp_vtx[vertex_num + 1] = xFixedToInt(vtx[1]); \
+ vertex_num += 2; \
+ if(DEBUG_CLIP_VTX) \
+ ErrorF("@ Point: (%d, %d) is inside " \
+ "the Rect and Trapezoid\n", \
+ xFixedToInt(vtx[0]), \
+ xFixedToInt(vtx[1])); \
+ } else if(DEBUG_CLIP_VTX){ \
+ ErrorF("X Point: (%d, %d) is outside " \
+ "the Rect and Trapezoid\t", \
+ xFixedToInt(vtx[0]), \
+ xFixedToInt(vtx[1])); \
+ if(POINT_INSIDE_CLIP_RECT(vtx, pbox)) \
+ ErrorF("The Point is outside " \
+ "the Trapezoid\n"); \
+ else \
+ ErrorF("The Point is outside " \
+ "the Rect\n"); \
+ }
+
+ /*Trap's right edge cut right edge. */
+ if((!IS_TRAP_EDGE_VERTICAL((&trap->left))) ||
+ (!IS_TRAP_EDGE_VERTICAL((&trap->right)))) {
+ edge_cross_y = _glamor_lines_crossfixedY((&trap->left), (&trap->right));
+ if (DEBUG_CLIP_VTX) {
+ ErrorF("Trap's left edge cut right edge at %d(0x%x), "
+ "trap_top = %x, trap_bottom = %x\n",
+ xFixedToInt(edge_cross_y), edge_cross_y,
+ (unsigned int)trap->top, (unsigned int)trap->bottom);
+ }
+ }
+
+ /*Trap's TopLeft, BottomLeft, TopRight and BottomRight. */
+ CACULATE_CUT_VERTEX(tl, 1, FALSE, trap->top, (&trap->left));
+ CACULATE_CUT_VERTEX(bl, 1, FALSE, trap->bottom, (&trap->left));
+ CACULATE_CUT_VERTEX(tr, 1, TRUE, trap->top, (&trap->right));
+ CACULATE_CUT_VERTEX(br, 1, TRUE, trap->bottom, (&trap->right));
+
+ if (DEBUG_CLIP_VTX)
+ ErrorF("Trap's TopLeft, BottomLeft, TopRight and BottomRight\n");
+ if (DEBUG_CLIP_VTX)
+ ErrorF("Caculate the vertex of trapezoid:\n"
+ " (%3d, %3d)-------------------------(%3d, %3d)\n"
+ " / \\ \n"
+ " / \\ \n"
+ " / \\ \n"
+ " (%3d, %3d)---------------------------------(%3d, %3d)\n"
+ "Clip with rect:\n"
+ " (%3d, %3d)------------------------(%3d, %3d) \n"
+ " | | \n"
+ " | | \n"
+ " | | \n"
+ " (%3d, %3d)------------------------(%3d, %3d) \n",
+ xFixedToInt(tl[0]), xFixedToInt(tl[1]), xFixedToInt(tr[0]),
+ xFixedToInt(tr[1]), xFixedToInt(bl[0]), xFixedToInt(bl[1]),
+ xFixedToInt(br[0]), xFixedToInt(br[1]),
+ pbox->x1, pbox->y1, pbox->x2, pbox->y1, pbox->x1, pbox->y2,
+ pbox->x2, pbox->y2);
+
+ ADD_VERTEX_IF_INSIDE(tl);
+ ADD_VERTEX_IF_INSIDE(bl);
+ ADD_VERTEX_IF_INSIDE(tr);
+ ADD_VERTEX_IF_INSIDE(br);
+
+ /*Trap's left edge cut Rect. */
+ if (DEBUG_CLIP_VTX)
+ ErrorF("Trap's left edge cut Rect\n");
+ CACULATE_CUT_VERTEX(left_cut_top, 1, FALSE, IntToxFixed(pbox->y1), (&trap->left));
+ ADD_VERTEX_IF_INSIDE(left_cut_top);
+ if (!IS_TRAP_EDGE_VERTICAL((&trap->left))) {
+ CACULATE_CUT_VERTEX(left_cut_left, 0, FALSE, IntToxFixed(pbox->x1), (&trap->left));
+ ADD_VERTEX_IF_INSIDE(left_cut_left);
+ }
+ CACULATE_CUT_VERTEX(left_cut_bottom, 1, FALSE, IntToxFixed(pbox->y2), (&trap->left));
+ ADD_VERTEX_IF_INSIDE(left_cut_bottom);
+ if (!IS_TRAP_EDGE_VERTICAL((&trap->left))) {
+ CACULATE_CUT_VERTEX(left_cut_right, 0, FALSE, IntToxFixed(pbox->x2), (&trap->left));
+ ADD_VERTEX_IF_INSIDE(left_cut_right);
+ }
+
+ /*Trap's right edge cut Rect. */
+ if (DEBUG_CLIP_VTX)
+ ErrorF("Trap's right edge cut Rect\n");
+ CACULATE_CUT_VERTEX(right_cut_top, 1, TRUE, IntToxFixed(pbox->y1), (&trap->right));
+ ADD_VERTEX_IF_INSIDE(right_cut_top);
+ if (!IS_TRAP_EDGE_VERTICAL((&trap->right))) {
+ CACULATE_CUT_VERTEX(right_cut_left, 0, TRUE, IntToxFixed(pbox->x1), (&trap->right));
+ ADD_VERTEX_IF_INSIDE(right_cut_left);
+ }
+ CACULATE_CUT_VERTEX(right_cut_bottom, 1, TRUE, IntToxFixed(pbox->y2), (&trap->right));
+ ADD_VERTEX_IF_INSIDE(right_cut_bottom);
+ if (!IS_TRAP_EDGE_VERTICAL((&trap->right))) {
+ CACULATE_CUT_VERTEX(right_cut_right, 0, TRUE, IntToxFixed(pbox->x2), (&trap->right));
+ ADD_VERTEX_IF_INSIDE(right_cut_right);
+ }
+
+ /* Trap's top cut Left and Right of rect. */
+ if (DEBUG_CLIP_VTX)
+ ErrorF("Trap's top cut Left and Right of rect\n");
+ tmp[0] = IntToxFixed(pbox->x1);
+ tmp[1] = trap->top;
+ ADD_VERTEX_IF_INSIDE(tmp);
+ tmp[0] = IntToxFixed(pbox->x2);
+ tmp[1] = trap->top;
+ ADD_VERTEX_IF_INSIDE(tmp);
+
+ /* Trap's bottom cut Left and Right of rect. */
+ if (DEBUG_CLIP_VTX)
+ ErrorF("Trap's bottom cut Left and Right of rect\n");
+ tmp[0] = IntToxFixed(pbox->x1);
+ tmp[1] = trap->bottom;
+ ADD_VERTEX_IF_INSIDE(tmp);
+ tmp[0] = IntToxFixed(pbox->x2);
+ tmp[1] = trap->bottom;
+ ADD_VERTEX_IF_INSIDE(tmp);
+
+ /* The orginal 4 vertex of rect. */
+ if (DEBUG_CLIP_VTX)
+ ErrorF("The orginal 4 vertex of rect\n");
+ tmp[0] = IntToxFixed(pbox->x1);
+ tmp[1] = IntToxFixed(pbox->y1);
+ ADD_VERTEX_IF_INSIDE(tmp);
+ tmp[0] = IntToxFixed(pbox->x1);
+ tmp[1] = IntToxFixed(pbox->y2);
+ ADD_VERTEX_IF_INSIDE(tmp);
+ tmp[0] = IntToxFixed(pbox->x2);
+ tmp[1] = IntToxFixed(pbox->y2);
+ ADD_VERTEX_IF_INSIDE(tmp);
+ tmp[0] = IntToxFixed(pbox->x2);
+ tmp[1] = IntToxFixed(pbox->y1);
+ ADD_VERTEX_IF_INSIDE(tmp);
+
+ if (DEBUG_CLIP_VTX) {
+ ErrorF("\nThe candidate vertex number is %d\n", vertex_num / 2);
+ for (i = 0; i < vertex_num / 2; i++) {
+ ErrorF("(%d, %d) ", tmp_vtx[2*i], tmp_vtx[2*i + 1]);
+ }
+ ErrorF("\n");
+ }
+
+ /* Sort the vertex by X and then Y. */
+ for (i = 0; i < vertex_num / 2; i++) {
+ int j;
+ for (j = 0; j < vertex_num / 2 - i - 1; j++) {
+ if (tmp_vtx[2*j] > tmp_vtx[2*(j+1)]
+ || (tmp_vtx[2*j] == tmp_vtx[2*(j+1)]
+ && tmp_vtx[2*j + 1] > tmp_vtx[2*(j+1) + 1])) {
+ tmp[0] = tmp_vtx[2*j];
+ tmp[1] = tmp_vtx[2*j + 1];
+ tmp_vtx[2*j] = tmp_vtx[2*(j+1)];
+ tmp_vtx[2*j + 1] = tmp_vtx[2*(j+1) + 1];
+ tmp_vtx[2*(j+1)] = tmp[0];
+ tmp_vtx[2*(j+1) + 1] = tmp[1];
+ }
+ }
+
+ }
+
+ if (DEBUG_CLIP_VTX) {
+ ErrorF("\nAfter sort vertex number is:\n");
+ for (i = 0; i < vertex_num / 2; i++) {
+ ErrorF("(%d, %d) ", tmp_vtx[2*i], tmp_vtx[2*i + 1]);
+ }
+ ErrorF("\n");
+ }
+
+ memset(vertex, -1, 2*6);
+ *num = 0;
+
+ for (i = 0; i < vertex_num / 2; i++) {
+ if (*num > 0 && vertex[2*(*num - 1)] == tmp_vtx[2*i]
+ && vertex[2*(*num - 1) + 1] == tmp_vtx[2*i + 1]) {
+ /*same vertex.*/
+ if (DEBUG_CLIP_VTX)
+ ErrorF("X Point:(%d, %d) discard\n",
+ tmp_vtx[2*i], tmp_vtx[2*i + 1]);
+ continue;
+ }
+
+ (*num)++;
+ if (*num > 6) {
+ if (DEBUG_CLIP_VTX)
+ FatalError("Trapezoid clip with Rect can never have vtx"
+ "number bigger than 6\n");
+ else {
+ ErrorF("Trapezoid clip with Rect can never have vtx"
+ "number bigger than 6\n");
+ *num = 6;
+ break;
+ }
+ }
+
+ vertex[2*(*num - 1)] = tmp_vtx[2*i];
+ vertex[2*(*num - 1) + 1] = tmp_vtx[2*i + 1];
+ if (DEBUG_CLIP_VTX)
+ ErrorF("@ Point:(%d, %d) select, num now is %d\n",
+ tmp_vtx[2*i], tmp_vtx[2*i + 1], *num);
+ }
+
+ /* Now we need to arrange the vtx in the polygon's counter-clockwise
+ order. We first select the left and top point as the start point and
+ sort every vtx by the slope from vtx to the start vtx. */
+ for (i = 1; i < *num; i++) {
+ tmp_vtx_slope[i] = (vertex[2*i] != vertex[0] ?
+ (float)(vertex[2*i + 1] - vertex[1]) / (float)(vertex[2*i] - vertex[0])
+ : (float)INT_MAX);
+ }
+
+ if (DEBUG_CLIP_VTX) {
+ ErrorF("\nvtx number: %d, VTX and slope:\n", *num);
+ for (i = 0; i < *num; i++) {
+ ErrorF("(%d, %d):%f ",
+ vertex[2*i], vertex[2*i + 1],
+ tmp_vtx_slope[i]);
+ }
+ ErrorF("\n");
+ }
+
+ /* Sort the vertex by slope. */
+ for (i = 0; i < *num - 1; i++) {
+ int j;
+ float tmp_slope;
+ for (j = 1; j < *num - i - 1; j++) {
+ if (tmp_vtx_slope[j] < tmp_vtx_slope[j + 1]) {
+ tmp_slope = tmp_vtx_slope[j];
+ tmp_vtx_slope[j] = tmp_vtx_slope[j + 1];
+ tmp_vtx_slope[j + 1] = tmp_slope;
+ tmp[0] = vertex[2*j];
+ tmp[1] = vertex[2*j + 1];
+ vertex[2*j] = vertex[2*(j+1)];
+ vertex[2*j + 1] = vertex[2*(j+1) + 1];
+ vertex[2*(j+1)] = tmp[0];
+ vertex[2*(j+1) + 1] = tmp[1];
+ }
+ }
+ }
+
+ if (DEBUG_CLIP_VTX) {
+ ErrorF("\nBefore return, vtx number: %d, VTX and slope:\n", *num);
+ for (i = 0; i < *num; i++) {
+ ErrorF("(%d, %d):%f ",
+ vertex[2*i], vertex[2*i + 1],
+ tmp_vtx_slope[i]);
+ }
+ ErrorF("\n");
+ }
+
+ return TRUE;
+}
+
+static void
+glamor_setup_composite_vbo_for_trapezoid(ScreenPtr screen, int n_verts)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch;
+ int stride;
+ int vert_size;
+
+ glamor_priv->render_nr_verts = 0;
+
+ /* For GLAMOR_VERTEX_POS */
+ glamor_priv->vb_stride = 2 * sizeof(float);
+
+ /* For GLAMOR_GLAMOR_VERTEX_SOURCE */
+ glamor_priv->vb_stride += 2 * sizeof(float);
+
+ /* For GLAMOR_VERTEX_TOP_BOTTOM */
+ glamor_priv->vb_stride += 2 * sizeof(float);
+
+ /* For GLAMOR_VERTEX_LEFT_PARAM */
+ glamor_priv->vb_stride += 4 * sizeof(float);
+
+ /* For GLAMOR_VERTEX_RIGHT_PARAM */
+ glamor_priv->vb_stride += 4 * sizeof(float);
+
+ vert_size = n_verts * glamor_priv->vb_stride;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_TOP_BOTTOM);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_LEFT_PARAM);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_RIGHT_PARAM);
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
+ if (glamor_priv->vbo_size < (glamor_priv->vbo_offset + vert_size)) {
+ glamor_priv->vbo_size = GLAMOR_COMPOSITE_VBO_VERT_CNT *
+ glamor_priv->vb_stride;
+ glamor_priv->vbo_offset = 0;
+ dispatch->glBufferData(GL_ARRAY_BUFFER,
+ glamor_priv->vbo_size,
+ NULL, GL_STREAM_DRAW);
+ }
+
+ glamor_priv->vb = dispatch->glMapBufferRange(GL_ARRAY_BUFFER,
+ glamor_priv->vbo_offset,
+ vert_size,
+ GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
+
+ assert(glamor_priv->vb != NULL);
+ glamor_priv->vb -= glamor_priv->vbo_offset;
+ } else {
+ glamor_priv->vbo_offset = 0;
+ }
+
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glamor_priv->ebo);
+
+ /* Set the vertex pointer. */
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
+ GL_FALSE, glamor_priv->vb_stride,
+ (void *) ((long)glamor_priv->vbo_offset));
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+ stride = 2;
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT,
+ GL_FALSE, glamor_priv->vb_stride,
+ (void *) ((long)glamor_priv->vbo_offset + stride * sizeof(float)));
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ stride += 2;
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_TOP_BOTTOM, 2, GL_FLOAT,
+ GL_FALSE, glamor_priv->vb_stride,
+ (void *) ((long)glamor_priv->vbo_offset + stride * sizeof(float)));
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_TOP_BOTTOM);
+ stride += 2;
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_LEFT_PARAM, 4, GL_FLOAT,
+ GL_FALSE, glamor_priv->vb_stride,
+ (void *) ((long)glamor_priv->vbo_offset + stride * sizeof(float)));
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_LEFT_PARAM);
+ stride += 4;
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_RIGHT_PARAM, 4, GL_FLOAT,
+ GL_FALSE, glamor_priv->vb_stride,
+ (void *) ((long)glamor_priv->vbo_offset + stride * sizeof(float)));
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_RIGHT_PARAM);
+
+ glamor_put_dispatch(glamor_priv);
+}
+
+static Bool
+_glamor_trapezoids_with_shader(CARD8 op,
+ PicturePtr src, PicturePtr dst,
+ PictFormatPtr mask_format, INT16 x_src, INT16 y_src,
+ int ntrap, xTrapezoid * traps)
+{
+ ScreenPtr screen = dst->pDrawable->pScreen;
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ struct shader_key key;
+ glamor_composite_shader *shader = NULL;
+ struct blendinfo op_info;
+ PictFormatShort saved_source_format = 0;
+ PixmapPtr source_pixmap = NULL;
+ PixmapPtr dest_pixmap = NULL;
+ glamor_pixmap_private *source_pixmap_priv = NULL;
+ glamor_pixmap_private *dest_pixmap_priv = NULL;
+ glamor_pixmap_private *temp_src_priv = NULL;
+ int x_temp_src, y_temp_src;
+ int src_width, src_height;
+ int source_x_off, source_y_off;
+ GLfloat src_xscale = 1, src_yscale = 1;
+ int x_dst, y_dst;
+ int dest_x_off, dest_y_off;
+ GLfloat dst_xscale, dst_yscale;
+ BoxRec bounds;
+ PicturePtr temp_src = src;
+ glamor_gl_dispatch *dispatch = NULL;
+ int vert_stride = 3;
+ int ntriangle_per_loop;
+ int nclip_rect;
+ int mclip_rect;
+ int clip_processed;
+ int clipped_vtx[6*2];
+ RegionRec region;
+ BoxPtr box = NULL;
+ BoxPtr pbox = NULL;
+ int traps_count = 0;
+ int traps_not_completed = 0;
+ xTrapezoid * ptrap = NULL;
+ int nbox;
+ float src_matrix[9];
+ Bool ret = FALSE;
+
+ /* If a mask format wasn't provided, we get to choose, but behavior should
+ * be as if there was no temporary mask the traps were accumulated into.
+ */
+ if (!mask_format) {
+ if (dst->polyEdge == PolyEdgeSharp)
+ mask_format = PictureMatchFormat(screen, 1, PICT_a1);
+ else
+ mask_format = PictureMatchFormat(screen, 8, PICT_a8);
+ for (; ntrap; ntrap--, traps++)
+ glamor_trapezoids(op, src, dst, mask_format, x_src,
+ y_src, 1, traps);
+ return TRUE;
+ }
+
+ miTrapezoidBounds(ntrap, traps, &bounds);
+ DEBUGF("The bounds for all traps is: bounds.x1 = %d, bounds.x2 = %d, "
+ "bounds.y1 = %d, bounds.y2 = %d\n", bounds.x1, bounds.x2,
+ bounds.y1, bounds.y2);
+
+ /* No area need to render. */
+ if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+ return TRUE;
+
+ dest_pixmap = glamor_get_drawable_pixmap(dst->pDrawable);
+ dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)
+ || dest_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ /* Currently. Always fallback to cpu if destination is in CPU memory.*/
+ ret = FALSE;
+ DEBUGF("dst pixmap has no FBO.\n");
+ goto TRAPEZOID_OUT;
+ }
+
+ if (src->pDrawable) {
+ source_pixmap = glamor_get_drawable_pixmap(src->pDrawable);
+ source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
+ temp_src_priv = source_pixmap_priv;
+ if (source_pixmap_priv
+ && (source_pixmap_priv->type == GLAMOR_DRM_ONLY
+ || source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE)) {
+ ret = FALSE;
+ goto TRAPEZOID_OUT;
+ }
+ }
+
+ x_dst = bounds.x1;
+ y_dst = bounds.y1;
+
+ src_width = bounds.x2 - bounds.x1;
+ src_height = bounds.y2 - bounds.y1;
+
+ x_temp_src = x_src + bounds.x1 - (traps[0].left.p1.x >> 16);
+ y_temp_src = y_src + bounds.y1 - (traps[0].left.p1.y >> 16);
+
+ if ((!src->pDrawable &&
+ (src->pSourcePict->type != SourcePictTypeSolidFill)) //1. The Gradient case.
+ /* 2. Has no fbo but can upload.*/
+ || (src->pDrawable && !GLAMOR_PIXMAP_PRIV_HAS_FBO(source_pixmap_priv)
+ && ((src_width * src_height * 4 <
+ source_pixmap->drawable.width * source_pixmap->drawable.height)
+ || !glamor_check_fbo_size(glamor_priv, source_pixmap->drawable.width,
+ source_pixmap->drawable.height)))) {
+
+ if (!glamor_check_fbo_size(glamor_priv, src_width, src_height)) {
+ ret = FALSE;
+ goto TRAPEZOID_OUT;
+ }
+ temp_src = glamor_convert_gradient_picture(screen, src,
+ x_src, y_src,
+ src_width, src_height);
+ if (!temp_src) {
+ temp_src = src;
+ ret = FALSE;
+ DEBUGF("Convert gradient picture failed\n");
+ goto TRAPEZOID_OUT;
+ }
+ temp_src_priv = glamor_get_pixmap_private((PixmapPtr)temp_src->pDrawable);
+ x_temp_src = y_temp_src = 0;
+ }
+
+ x_dst += dst->pDrawable->x;
+ y_dst += dst->pDrawable->y;
+ if (temp_src->pDrawable) {
+ x_temp_src += temp_src->pDrawable->x;
+ y_temp_src += temp_src->pDrawable->y;
+ }
+
+ if (!miComputeCompositeRegion(&region,
+ temp_src, NULL, dst,
+ x_temp_src, y_temp_src,
+ 0, 0,
+ x_dst, y_dst,
+ src_width, src_height)) {
+ DEBUGF("All the regions are clipped out, do nothing\n");
+ goto TRAPEZOID_OUT;
+ }
+
+ box = REGION_RECTS(&region);
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = box;
+
+ ret = glamor_composite_choose_shader(op, temp_src, NULL, dst,
+ temp_src_priv, NULL, dest_pixmap_priv,
+ &key, &shader, &op_info, &saved_source_format);
+ if (ret == FALSE) {
+ DEBUGF("can not set the shader program for composite\n");
+ goto TRAPEZOID_RESET_GL;
+ }
+ glamor_set_destination_pixmap_priv_nc(dest_pixmap_priv);
+ glamor_composite_set_shader_blend(dest_pixmap_priv, &key, shader, &op_info);
+ glamor_priv->has_source_coords = key.source != SHADER_SOURCE_SOLID;
+ glamor_priv->has_mask_coords = (key.mask != SHADER_MASK_NONE &&
+ key.mask != SHADER_MASK_SOLID);
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+ glamor_get_drawable_deltas(dst->pDrawable, dest_pixmap,
+ &dest_x_off, &dest_y_off);
+
+ pixmap_priv_get_dest_scale(dest_pixmap_priv, &dst_xscale, &dst_yscale);
+
+ if (glamor_priv->has_source_coords) {
+ source_pixmap = glamor_get_drawable_pixmap(temp_src->pDrawable);
+ source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
+ glamor_get_drawable_deltas(temp_src->pDrawable,
+ source_pixmap,
+ &source_x_off, &source_y_off);
+ pixmap_priv_get_scale(source_pixmap_priv,
+ &src_xscale, &src_yscale);
+ glamor_picture_get_matrixf(temp_src, src_matrix);
+ vert_stride += 3;
+ }
+
+ if (glamor_priv->has_mask_coords) {
+ DEBUGF("Should never have mask coords here!\n");
+ ret = FALSE;
+ goto TRAPEZOID_RESET_GL;
+ }
+
+ /* A trapezoid clip with a rectangle will at most generate a hexagon,
+ which can be devided into 4 triangles to render. */
+ ntriangle_per_loop = (vert_stride * nbox * ntrap * 4) > GLAMOR_COMPOSITE_VBO_VERT_CNT ?
+ (GLAMOR_COMPOSITE_VBO_VERT_CNT / vert_stride) : nbox * ntrap * 4;
+ ntriangle_per_loop = (ntriangle_per_loop / 4) * 4;
+
+ nclip_rect = nbox;
+ while (nclip_rect) {
+ mclip_rect = (nclip_rect * ntrap * 4) > ntriangle_per_loop ?
+ (ntriangle_per_loop / (4 * ntrap)) : nclip_rect;
+
+ if (!mclip_rect) {/* Maybe too many traps. */
+ mclip_rect = 1;
+ ptrap = traps;
+ traps_count = ntriangle_per_loop / 4;
+ traps_not_completed = ntrap - traps_count;
+ } else {
+ traps_count = ntrap;
+ ptrap = traps;
+ traps_not_completed = 0;
+ }
+
+NTRAPS_LOOP_AGAIN:
+
+ glamor_setup_composite_vbo(screen, mclip_rect * traps_count * 4 * vert_stride);
+ clip_processed = mclip_rect;
+
+
+ while (mclip_rect--) {
+ while (traps_count--) {
+ int vtx_num;
+ int i;
+ float vertices[3*2], source_texcoords[3*2];
+
+ DEBUGF("In loop of render trapezoid, nclip_rect = %d, mclip_rect = %d, "
+ "clip_processed = %d, traps_count = %d, traps_not_completed = %d\n",
+ nclip_rect, mclip_rect, clip_processed, traps_count, traps_not_completed);
+
+ if (_glamor_clip_trapezoid_vertex(ptrap, pbox, clipped_vtx, &vtx_num)) {
+ for (i = 0; i < vtx_num - 2; i++) {
+ int clipped_vtx_tmp[3*2];
+
+ clipped_vtx_tmp[0] = clipped_vtx[0];
+ clipped_vtx_tmp[1] = clipped_vtx[1];
+ clipped_vtx_tmp[2] = clipped_vtx[(i+1)*2];
+ clipped_vtx_tmp[3] = clipped_vtx[(i+1)*2 + 1];
+ clipped_vtx_tmp[4] = clipped_vtx[(i+2)*2];
+ clipped_vtx_tmp[5] = clipped_vtx[(i+2)*2 + 1];
+ glamor_set_normalize_tri_vcoords(
+ dst_xscale, dst_yscale, clipped_vtx_tmp,
+ glamor_priv->yInverted, vertices);
+ DEBUGF("vertices of triangle: (%f X %f), (%f X %f), "
+ "(%f X %f)\n", vertices[0], vertices[1],
+ vertices[2], vertices[3], vertices[4], vertices[5]);
+
+
+ if (key.source != SHADER_SOURCE_SOLID) {
+ if (src->transform) {
+ glamor_set_transformed_normalize_tri_tcoords(
+ source_pixmap_priv,
+ src_matrix, src_xscale, src_yscale,
+ clipped_vtx_tmp,
+ glamor_priv->yInverted,
+ source_texcoords);
+ } else {
+ glamor_set_normalize_tri_tcoords(
+ src_xscale, src_yscale,
+ clipped_vtx_tmp,
+ glamor_priv->yInverted,
+ source_texcoords);
+ }
+
+ DEBUGF("source_texcoords of triangle: (%f X %f), "
+ "(%f X %f), (%f X %f)\n",
+ source_texcoords[0], source_texcoords[1],
+ source_texcoords[2], source_texcoords[3],
+ source_texcoords[4], source_texcoords[5]);
+ }
+
+ glamor_emit_composite_triangle(screen, source_texcoords,
+ NULL, vertices);
+ }
+ }
+
+ ptrap++;
+ }
+
+ if (traps_not_completed) { /* one loop of ntraps not completed */
+ mclip_rect = 1;
+ traps_count = traps_not_completed > (ntriangle_per_loop / 4) ?
+ (ntriangle_per_loop / 4) : traps_not_completed;
+ traps_not_completed -= traps_count;
+ glamor_flush_composite_triangles(screen);
+ goto NTRAPS_LOOP_AGAIN;
+ } else {
+ ptrap = traps;
+ traps_count = ntrap;
+ }
+
+ pbox++;
+ }
+
+ glamor_flush_composite_triangles(screen);
+
+ nclip_rect -= clip_processed;
+ }
+
+ ret = TRUE;
+
+TRAPEZOID_RESET_GL:
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_MASK);
+ dispatch->glDisable(GL_BLEND);
+#ifndef GLAMOR_GLES2
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glDisable(GL_TEXTURE_2D);
+ dispatch->glActiveTexture(GL_TEXTURE1);
+ dispatch->glDisable(GL_TEXTURE_2D);
+#endif
+ dispatch->glUseProgram(0);
+
+TRAPEZOID_OUT:
+ if (box) {
+ REGION_UNINIT(dst->pDrawable->pScreen, &region);
+ }
+
+ if (temp_src != src) {
+ FreePicture(temp_src, 0);
+ } else {
+ if (saved_source_format) {
+ src->format = saved_source_format;
+ }
+ }
+
+ if (dispatch) {
+ glamor_put_dispatch(glamor_priv);
+ }
+
+ return ret;
+}
+
+void
+glamor_init_trapezoid_shader(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ GLint fs_prog, vs_prog;
+
+ const char *trapezoid_vs =
+ GLAMOR_DEFAULT_PRECISION
+ "attribute vec4 v_position;\n"
+ "attribute vec2 v_texcoord;\n"
+ /* v_top_bottom, v_left_param and v_right_param contain the
+ constant value for all the vertex of one rect. Using uniform
+ is more suitable but we need to reset the uniform variables
+ for every rect rendering and can not use the vbo, which causes
+ performance loss. So we set these attributes to same value
+ for every vertex of one rect and so it is also a constant in FS */
+ "attribute vec2 v_top_bottom;\n"
+ "attribute vec4 v_left_param;\n"
+ "attribute vec4 v_right_param;\n"
+ "\n"
+ "varying vec2 source_texture;\n"
+ "varying float trap_top;\n"
+ "varying float trap_bottom;\n"
+ "varying float trap_left_x;\n"
+ "varying float trap_left_y;\n"
+ "varying float trap_left_slope;\n"
+ "varying float trap_left_vertical_f;\n"
+ "varying float trap_right_x;\n"
+ "varying float trap_right_y;\n"
+ "varying float trap_right_slope;\n"
+ "varying float trap_right_vertical_f;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = v_position;\n"
+ " source_texture = v_texcoord.xy;\n"
+ " trap_top = v_top_bottom.x;\n"
+ " trap_bottom = v_top_bottom.y;\n"
+ " \n"
+ " trap_left_x = v_left_param.x;\n"
+ " trap_left_y = v_left_param.y;\n"
+ " trap_left_slope = v_left_param.z;\n"
+ " trap_left_vertical_f = v_left_param.w;\n"
+ " \n"
+ " trap_right_x = v_right_param.x;\n"
+ " trap_right_y = v_right_param.y;\n"
+ " trap_right_slope = v_right_param.z;\n"
+ " trap_right_vertical_f = v_right_param.w;\n"
+ "}\n";
+
+ /*
+ * Because some GL fill function do not support the MultSample
+ * anti-alias, we need to do the MSAA here. This manner like
+ * pixman, will caculate the value of area in trapezoid dividing
+ * the totol area for each pixel, as follow:
+ |
+ ----+------------------------------------------------------>
+ |
+ | -------------
+ | / \
+ | / \
+ | / \
+ | / +----------------+
+ | / |.....\ |
+ | / |......\ |
+ | / |.......\ |
+ | / |........\ |
+ | /-------------------+---------\ |
+ | | |
+ | | |
+ | +----------------+
+ |
+ \|/
+
+ */
+ const char *trapezoid_fs =
+ GLAMOR_DEFAULT_PRECISION
+ "varying vec2 source_texture; \n"
+ "varying float trap_top; \n"
+ "varying float trap_bottom; \n"
+ "varying float trap_left_x; \n"
+ "varying float trap_left_y; \n"
+ "varying float trap_left_slope; \n"
+ "varying float trap_left_vertical_f; \n"
+ "varying float trap_right_x; \n"
+ "varying float trap_right_y; \n"
+ "varying float trap_right_slope; \n"
+ "varying float trap_right_vertical_f; \n"
+ "float x_per_pix = 1.0;"
+ "float y_per_pix = 1.0;"
+ "\n"
+ "float get_alpha_val() \n"
+ "{ \n"
+ " float x_up_cut_left; \n"
+ " float x_bottom_cut_left; \n"
+ " float x_up_cut_right; \n"
+ " float x_bottom_cut_right; \n"
+ " bool trap_left_vertical;\n"
+ " bool trap_right_vertical;\n"
+ " if (abs(trap_left_vertical_f - 1.0) <= 0.0001)\n"
+ " trap_left_vertical = true;\n"
+ " else\n"
+ " trap_left_vertical = false;\n"
+ " if (abs(trap_right_vertical_f - 1.0) <= 0.0001)\n"
+ " trap_right_vertical = true;\n"
+ " else\n"
+ " trap_right_vertical = false;\n"
+ " \n"
+ " if(trap_left_vertical == true) { \n"
+ " x_up_cut_left = trap_left_x; \n"
+ " x_bottom_cut_left = trap_left_x; \n"
+ " } else { \n"
+ " x_up_cut_left = trap_left_x \n"
+ " + (source_texture.y - y_per_pix/2.0 - trap_left_y) \n"
+ " / trap_left_slope; \n"
+ " x_bottom_cut_left = trap_left_x \n"
+ " + (source_texture.y + y_per_pix/2.0 - trap_left_y) \n"
+ " / trap_left_slope; \n"
+ " } \n"
+ " \n"
+ " if(trap_right_vertical == true) { \n"
+ " x_up_cut_right = trap_right_x; \n"
+ " x_bottom_cut_right = trap_right_x; \n"
+ " } else { \n"
+ " x_up_cut_right = trap_right_x \n"
+ " + (source_texture.y - y_per_pix/2.0 - trap_right_y) \n"
+ " / trap_right_slope; \n"
+ " x_bottom_cut_right = trap_right_x \n"
+ " + (source_texture.y + y_per_pix/2.0 - trap_right_y) \n"
+ " / trap_right_slope; \n"
+ " } \n"
+ " \n"
+ " if((x_up_cut_left <= source_texture.x - x_per_pix/2.0) && \n"
+ " (x_bottom_cut_left <= source_texture.x - x_per_pix/2.0) && \n"
+ " (x_up_cut_right >= source_texture.x + x_per_pix/2.0) && \n"
+ " (x_bottom_cut_right >= source_texture.x + x_per_pix/2.0) && \n"
+ " (trap_top <= source_texture.y - y_per_pix/2.0) && \n"
+ " (trap_bottom >= source_texture.y + y_per_pix/2.0)) { \n"
+ // The complete inside case.
+ " return 1.0; \n"
+ " } else if((trap_top > source_texture.y + y_per_pix/2.0) || \n"
+ " (trap_bottom < source_texture.y - y_per_pix/2.0)) { \n"
+ // The complete outside. Above the top or Below the bottom.
+ " return 0.0; \n"
+ " } else { \n"
+ " if((x_up_cut_right < source_texture.x - x_per_pix/2.0 && \n"
+ " x_bottom_cut_right < source_texture.x - x_per_pix/2.0) \n"
+ " || (x_up_cut_left > source_texture.x + x_per_pix/2.0 && \n"
+ " x_bottom_cut_left > source_texture.x + x_per_pix/2.0)) { \n"
+ // The complete outside. At Left or Right of the trapezoide.
+ " return 0.0; \n"
+ " } \n"
+ " } \n"
+ // Get here, the pix is partly inside the trapezoid.
+ " { \n"
+ " float percent = 0.0; \n"
+ " float up = (source_texture.y - y_per_pix/2.0) >= trap_top ? \n"
+ " (source_texture.y - y_per_pix/2.0) : trap_top; \n"
+ " float bottom = (source_texture.y + y_per_pix/2.0) <= trap_bottom ? \n"
+ " (source_texture.y + y_per_pix/2.0) : trap_bottom; \n"
+ " float left = source_texture.x - x_per_pix/2.0; \n"
+ " float right = source_texture.x + x_per_pix/2.0; \n"
+ " \n"
+ " percent = (bottom - up) / y_per_pix; \n"
+ " \n"
+ " if(trap_left_vertical == true) { \n"
+ " if(trap_left_x > source_texture.x - x_per_pix/2.0 && \n"
+ " trap_left_x < source_texture.x + x_per_pix/2.0) \n"
+ " left = trap_left_x; \n"
+ " } \n"
+ " if(trap_right_vertical == true) { \n"
+ " if(trap_right_x > source_texture.x - x_per_pix/2.0 && \n"
+ " trap_right_x < source_texture.x + x_per_pix/2.0) \n"
+ " right = trap_right_x; \n"
+ " } \n"
+ " if((up >= bottom) || (left >= right)) \n"
+ " return 0.0; \n"
+ " \n"
+ " percent = percent * ((right - left)/x_per_pix); \n"
+ " if(trap_left_vertical == true && trap_right_vertical == true) \n"
+ " return percent; \n"
+ " \n"
+ " if(trap_left_vertical != true) { \n"
+ " float area; \n"
+ // the slope should never be 0.0 here
+ " float up_x = trap_left_x + (up - trap_left_y)/trap_left_slope; \n"
+ " float bottom_x = trap_left_x + (bottom - trap_left_y)/trap_left_slope; \n"
+ " if(trap_left_slope < 0.0 && up_x > left) { \n"
+ /* case 1
+ |
+ ----+------------------------------------->
+ | /
+ | /
+ | +---/--------+
+ | | /.........|
+ | | /..........|
+ | |/...........|
+ | /............|
+ | /|............|
+ | +------------+
+ |
+ \|/
+ */
+ " float left_y = trap_left_y + trap_left_slope*(left - trap_left_x); \n"
+ " if((up_x > left) && (left_y > up)) { \n"
+ " area = 0.5 * (up_x - left) * (left_y - up); \n"
+ " if(up_x > right) { \n"
+ " float right_y = trap_left_y \n"
+ " + trap_left_slope*(right - trap_left_x); \n"
+ " area = area - 0.5 * (up_x - right) * (right_y - up); \n"
+ " } \n"
+ " if(left_y > bottom) { \n"
+ " area = area - 0.5 * (bottom_x - left) * (left_y - bottom); \n"
+ " } \n"
+ " } else { \n"
+ " area = 0.0; \n"
+ " } \n"
+ " percent = percent * (1.0 - (area/((right-left)*(bottom-up)))); \n"
+ " } else if(trap_left_slope > 0.0 && bottom_x > left) { \n"
+ /* case 2
+ |
+ ----+------------------------------------->
+ | \
+ | \
+ | +\-----------+
+ | | \..........|
+ | | \.........|
+ | | \........|
+ | | \.......|
+ | | \......|
+ | +------\-----+
+ | \
+ | \
+ \|/
+ */
+ " float right_y = trap_left_y + trap_left_slope*(right - trap_left_x); \n"
+ " if((up_x < right) && (right_y > up)) { \n"
+ " area = 0.5 * (right - up_x) * (right_y - up); \n"
+ " if(up_x < left) { \n"
+ " float left_y = trap_left_y \n"
+ " + trap_left_slope*(left - trap_left_x); \n"
+ " area = area - 0.5 * (left - up_x) * (left_y - up); \n"
+ " } \n"
+ " if(right_y > bottom) { \n"
+ " area = area - 0.5 * (right - bottom_x) * (right_y - bottom); \n"
+ " } \n"
+ " } else { \n"
+ " area = 0.0; \n"
+ " } \n"
+ " percent = percent * (area/((right-left)*(bottom-up))); \n"
+ " } \n"
+ " } \n"
+ " \n"
+ " if(trap_right_vertical != true) { \n"
+ " float area; \n"
+ // the slope should never be 0.0 here
+ " float up_x = trap_right_x + (up - trap_right_y)/trap_right_slope; \n"
+ " float bottom_x = trap_right_x + (bottom - trap_right_y)/trap_right_slope; \n"
+ " if(trap_right_slope < 0.0 && bottom_x < right) { \n"
+ /* case 3
+ |
+ ----+------------------------------------->
+ | /
+ | +--------/---+
+ | |......./ |
+ | |....../ |
+ | |...../ |
+ | |..../ |
+ | |.../ |
+ | +--/---------+
+ | /
+ |
+ \|/
+ */
+ " float left_y = trap_right_y + trap_right_slope*(left - trap_right_x); \n"
+ " if((up_x > left) && (left_y > up)) { \n"
+ " area = 0.5 * (up_x - left) * (left_y - up); \n"
+ " if(up_x > right) { \n"
+ " float right_y = trap_right_y \n"
+ " + trap_right_slope*(right - trap_right_x); \n"
+ " area = area - 0.5 * (up_x - right) * (right_y - up); \n"
+ " } \n"
+ " if(left_y > bottom) { \n"
+ " area = area - 0.5 * (bottom_x - left) * (left_y - bottom); \n"
+ " } \n"
+ " } else { \n"
+ " area = 0.0; \n"
+ " } \n"
+ " percent = percent * (area/((right-left)*(bottom-up))); \n"
+ " } else if(trap_right_slope > 0.0 && up_x < right) { \n"
+ /* case 4
+ |
+ ----+------------------------------------->
+ | \
+ | +--------\---+
+ | |.........\ |
+ | |..........\ |
+ | |...........\|
+ | |............\
+ | |............|\
+ | +------------+ \
+ | \
+ |
+ \|/
+ */
+ " float right_y = trap_right_y + trap_right_slope*(right - trap_right_x); \n"
+ " if((up_x < right) && (right_y > up)) { \n"
+ " area = 0.5 * (right - up_x) * (right_y - up); \n"
+ " if(up_x < left) { \n"
+ " float left_y = trap_right_y \n"
+ " + trap_right_slope*(left - trap_right_x); \n"
+ " area = area - 0.5 * (left - up_x) * (left_y - up); \n"
+ " } \n"
+ " if(right_y > bottom) { \n"
+ " area = area - 0.5 * (right - bottom_x) * (right_y - bottom); \n"
+ " } \n"
+ " } else { \n"
+ " area = 0.0; \n"
+ " } \n"
+ " percent = percent * (1.0 - (area/((right-left)*(bottom-up)))); \n"
+ " } \n"
+ " } \n"
+ " \n"
+ " return percent; \n"
+ " } \n"
+ "} \n"
+ "\n"
+ "void main() \n"
+ "{ \n"
+ " float alpha_val = get_alpha_val(); \n"
+ " gl_FragColor = vec4(0.0, 0.0, 0.0, alpha_val); \n"
+ "}\n";
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+ glamor_priv->trapezoid_prog = dispatch->glCreateProgram();
+
+ vs_prog = glamor_compile_glsl_prog(dispatch,
+ GL_VERTEX_SHADER, trapezoid_vs);
+ fs_prog = glamor_compile_glsl_prog(dispatch,
+ GL_FRAGMENT_SHADER, trapezoid_fs);
+
+ dispatch->glAttachShader(glamor_priv->trapezoid_prog, vs_prog);
+ dispatch->glAttachShader(glamor_priv->trapezoid_prog, fs_prog);
+
+ dispatch->glBindAttribLocation(glamor_priv->trapezoid_prog,
+ GLAMOR_VERTEX_POS, "v_positionsition");
+ dispatch->glBindAttribLocation(glamor_priv->trapezoid_prog,
+ GLAMOR_VERTEX_SOURCE, "v_texcoord");
+ dispatch->glBindAttribLocation(glamor_priv->trapezoid_prog,
+ GLAMOR_VERTEX_TOP_BOTTOM, "v_top_bottom");
+ dispatch->glBindAttribLocation(glamor_priv->trapezoid_prog,
+ GLAMOR_VERTEX_LEFT_PARAM, "v_left_param");
+ dispatch->glBindAttribLocation(glamor_priv->trapezoid_prog,
+ GLAMOR_VERTEX_RIGHT_PARAM, "v_right_param");
+
+ glamor_link_glsl_prog(dispatch, glamor_priv->trapezoid_prog);
+
+ dispatch->glUseProgram(0);
+
+ glamor_put_dispatch(glamor_priv);
+}
+
+void
+glamor_fini_trapezoid_shader(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glDeleteProgram(glamor_priv->trapezoid_prog);
+ glamor_put_dispatch(glamor_priv);
+}
+
+static Bool
+_glamor_generate_trapezoid_with_shader(ScreenPtr screen, PicturePtr picture,
+ xTrapezoid * traps, int ntrap, BoxRec *bounds)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ glamor_pixmap_private *pixmap_priv;
+ PixmapPtr pixmap = NULL;
+ GLint trapezoid_prog;
+ GLfloat xscale, yscale;
+ float left_slope, right_slope;
+ xTrapezoid *ptrap;
+ BoxRec one_trap_bound;
+ int nrect_max;
+ int i, j;
+ float *vertices;
+ float params[4];
+
+ glamor_priv = glamor_get_screen_private(screen);
+ trapezoid_prog = glamor_priv->trapezoid_prog;
+
+ pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)
+ || pixmap_priv->type == GLAMOR_TEXTURE_LARGE) { /* should always have here. */
+ DEBUGF("GLAMOR_PIXMAP_PRIV_HAS_FBO check failed, fallback\n");
+ return FALSE;
+ }
+
+ /* First, clear all to zero */
+ if (!glamor_solid(pixmap, 0, 0, pixmap_priv->base.pixmap->drawable.width,
+ pixmap_priv->base.pixmap->drawable.height,
+ GXclear, 0xFFFFFFFF, 0)) {
+ DEBUGF("glamor_solid failed, fallback\n");
+ return FALSE;
+ }
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+ glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+
+ pixmap_priv_get_dest_scale(pixmap_priv, (&xscale), (&yscale));
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ /* Now draw the Trapezoid mask. */
+ dispatch->glUseProgram(trapezoid_prog);
+
+ dispatch->glEnable(GL_BLEND);
+ dispatch->glBlendFunc(GL_ONE, GL_ONE);
+
+ nrect_max = GLAMOR_COMPOSITE_VBO_VERT_CNT / (4 * GLAMOR_VERTEX_RIGHT_PARAM);
+
+ for (i = 0; i < ntrap;) {
+ int mrect;
+ int stride;
+
+ mrect = (ntrap - i) > nrect_max ? nrect_max : (ntrap - i);
+ glamor_setup_composite_vbo_for_trapezoid(screen, 4 * mrect);
+ stride = glamor_priv->vb_stride / sizeof(float);
+
+ for (j = 0; j < mrect; j++) {
+ ptrap = traps + i + j;
+
+ DEBUGF("--- The parameter of xTrapezoid is:\ntop: %d 0x%x\tbottom: %d 0x%x\n"
+ "left: p1 (%d 0x%x, %d 0x%x)\tp2 (%d 0x%x, %d 0x%x)\n"
+ "right: p1 (%d 0x%x, %d 0x%x)\tp2 (%d 0x%x, %d 0x%x)\n",
+ xFixedToInt(ptrap->top), ptrap->top,
+ xFixedToInt(ptrap->bottom), ptrap->bottom,
+ xFixedToInt(ptrap->left.p1.x), ptrap->left.p1.x,
+ xFixedToInt(ptrap->left.p1.y), ptrap->left.p1.y,
+ xFixedToInt(ptrap->left.p2.x), ptrap->left.p2.x,
+ xFixedToInt(ptrap->left.p2.y), ptrap->left.p2.y,
+ xFixedToInt(ptrap->right.p1.x), ptrap->right.p1.x,
+ xFixedToInt(ptrap->right.p1.y), ptrap->right.p1.y,
+ xFixedToInt(ptrap->right.p2.x), ptrap->right.p2.x,
+ xFixedToInt(ptrap->right.p2.y), ptrap->right.p2.y);
+
+ miTrapezoidBounds(1, ptrap, &one_trap_bound);
+
+ vertices = (float*)(glamor_priv->vb + glamor_priv->vbo_offset) + 2;
+ glamor_set_tcoords_ext((pixmap_priv->base.pixmap->drawable.width),
+ (pixmap_priv->base.pixmap->drawable.height),
+ (one_trap_bound.x1),
+ (one_trap_bound.y1),
+ (one_trap_bound.x2),
+ (one_trap_bound.y2),
+ glamor_priv->yInverted, vertices, stride);
+ DEBUGF("tex_vertices --> leftup : %f X %f, rightup: %f X %f,"
+ "rightbottom: %f X %f, leftbottom : %f X %f\n",
+ vertices[0], vertices[1],
+ vertices[1*stride], vertices[1*stride + 1],
+ vertices[2*stride], vertices[2*stride + 1],
+ vertices[3*stride], vertices[3*stride + 1]);
+
+ /* Need to rebase. */
+ one_trap_bound.x1 -= bounds->x1;
+ one_trap_bound.x2 -= bounds->x1;
+ one_trap_bound.y1 -= bounds->y1;
+ one_trap_bound.y2 -= bounds->y1;
+
+ vertices -= 2;
+
+ glamor_set_normalize_vcoords_ext(pixmap_priv, xscale, yscale,
+ one_trap_bound.x1, one_trap_bound.y1,
+ one_trap_bound.x2, one_trap_bound.y2,
+ glamor_priv->yInverted, vertices, stride);
+ DEBUGF("vertices --> leftup : %f X %f, rightup: %f X %f,"
+ "rightbottom: %f X %f, leftbottom : %f X %f\n",
+ vertices[0], vertices[1],
+ vertices[1*stride], vertices[1*stride + 1],
+ vertices[2*stride], vertices[2*stride + 1],
+ vertices[3*stride], vertices[3*stride + 1]);
+ vertices += 4;
+
+ /* Set the top and bottom. */
+ params[0] = ((float)ptrap->top) / 65536;
+ params[1] = ((float)ptrap->bottom) / 65536;
+ glamor_set_const_ext(params, 2, vertices, 4, stride);
+ vertices += 2;
+
+ /* Set the left params. */
+ params[0] = ((float)ptrap->left.p1.x) / 65536;
+ params[1] = ((float)ptrap->left.p1.y) / 65536;
+
+ if (ptrap->left.p1.x == ptrap->left.p2.x) {
+ left_slope = 0.0;
+ params[3] = 1.0;
+ } else {
+ left_slope = ((float)(ptrap->left.p1.y - ptrap->left.p2.y))
+ / ((float)(ptrap->left.p1.x - ptrap->left.p2.x));
+ params[3] = 0.0;
+ }
+ params[2] = left_slope;
+ glamor_set_const_ext(params, 4, vertices, 4, stride);
+ vertices += 4;
+
+ /* Set the left params. */
+ params[0] = ((float)ptrap->right.p1.x) / 65536;
+ params[1] = ((float)ptrap->right.p1.y) / 65536;
+
+ if (ptrap->right.p1.x == ptrap->right.p2.x) {
+ right_slope = 0.0;
+ params[3] = 1.0;
+ } else {
+ right_slope = ((float)(ptrap->right.p1.y - ptrap->right.p2.y))
+ / ((float)(ptrap->right.p1.x - ptrap->right.p2.x));
+ params[3] = 0.0;
+ }
+ params[2] = right_slope;
+ glamor_set_const_ext(params, 4, vertices, 4, stride);
+
+ DEBUGF("trap_top = %f, trap_bottom = %f, "
+ "trap_left_x = %f, trap_left_y = %f, left_slope = %f, "
+ "trap_right_x = %f, trap_right_y = %f, right_slope = %f\n",
+ ((float)ptrap->top) / 65536, ((float)ptrap->bottom) / 65536,
+ ((float)ptrap->left.p1.x) / 65536, ((float)ptrap->left.p1.y) / 65536,
+ left_slope,
+ ((float)ptrap->right.p1.x) / 65536, ((float)ptrap->right.p1.y) / 65536,
+ right_slope);
+
+ glamor_priv->render_nr_verts += 4;
+ glamor_priv->vbo_offset += glamor_priv->vb_stride * 4;
+ }
+
+ i += mrect;
+
+ /* Now rendering. */
+ if (!glamor_priv->render_nr_verts)
+ continue;
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
+ dispatch->glUnmapBuffer(GL_ARRAY_BUFFER);
+ else {
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
+ dispatch->glBufferData(GL_ARRAY_BUFFER,
+ glamor_priv->vbo_offset,
+ glamor_priv->vb, GL_DYNAMIC_DRAW);
+ }
+
+#ifndef GLAMOR_GLES2
+ dispatch->glDrawRangeElements(GL_TRIANGLES, 0, glamor_priv->render_nr_verts,
+ (glamor_priv->render_nr_verts * 3) / 2,
+ GL_UNSIGNED_SHORT, NULL);
+#else
+ dispatch->glDrawElements(GL_TRIANGLES, (glamor_priv->render_nr_verts * 3) / 2,
+ GL_UNSIGNED_SHORT, NULL);
+#endif
+ }
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ dispatch->glBlendFunc(GL_ONE, GL_ZERO);
+ dispatch->glDisable(GL_BLEND);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_TOP_BOTTOM);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_LEFT_PARAM);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_RIGHT_PARAM);
+ dispatch->glUseProgram(0);
+ glamor_put_dispatch(glamor_priv);
+ return TRUE;
+}
+
+#endif /*GLAMOR_TRAPEZOID_SHADER */
+
+/**
+ * Creates an appropriate picture for temp mask use.
+ */
+static PicturePtr
+glamor_create_mask_picture(ScreenPtr screen,
+ PicturePtr dst,
+ PictFormatPtr pict_format,
+ CARD16 width, CARD16 height, int gpu)
+{
+ PixmapPtr pixmap;
+ PicturePtr picture;
+ int error;
+
+ if (!pict_format) {
+ if (dst->polyEdge == PolyEdgeSharp)
+ pict_format =
+ PictureMatchFormat(screen, 1, PICT_a1);
+ else
+ pict_format =
+ PictureMatchFormat(screen, 8, PICT_a8);
+ if (!pict_format)
+ return 0;
+ }
+
+ if (gpu) {
+ pixmap = glamor_create_pixmap(screen, width, height,
+ pict_format->depth, 0);
+ } else {
+ pixmap = glamor_create_pixmap(screen, 0, 0,
+ pict_format->depth,
+ GLAMOR_CREATE_PIXMAP_CPU);
+ }
+
+ if (!pixmap)
+ return 0;
+ picture = CreatePicture(0, &pixmap->drawable, pict_format,
+ 0, 0, serverClient, &error);
+ glamor_destroy_pixmap(pixmap);
+ return picture;
+}
+
+static int
+_glamor_trapezoid_bounds (int ntrap, xTrapezoid *traps, BoxPtr box)
+{
+ int has_large_trapezoid = 0;
+ box->y1 = MAXSHORT;
+ box->y2 = MINSHORT;
+ box->x1 = MAXSHORT;
+ box->x2 = MINSHORT;
+
+ for (; ntrap; ntrap--, traps++) {
+ INT16 x1, y1, x2, y2;
+
+ if (!xTrapezoidValid(traps))
+ continue;
+ y1 = xFixedToInt (traps->top);
+ if (y1 < box->y1)
+ box->y1 = y1;
+
+ y2 = xFixedToInt (xFixedCeil (traps->bottom));
+ if (y2 > box->y2)
+ box->y2 = y2;
+
+ x1 = xFixedToInt (min (_glamor_linefixedX (&traps->left, traps->top, FALSE),
+ _glamor_linefixedX (&traps->left, traps->bottom, FALSE)));
+ if (x1 < box->x1)
+ box->x1 = x1;
+
+ x2 = xFixedToInt (xFixedCeil (max (_glamor_linefixedX (&traps->right, traps->top, TRUE),
+ _glamor_linefixedX (&traps->right, traps->bottom, TRUE))));
+ if (x2 > box->x2)
+ box->x2 = x2;
+
+ if (!has_large_trapezoid && (x2 - x1) > 256 && (y2 - y1) > 32)
+ has_large_trapezoid = 1;
+ }
+
+ return has_large_trapezoid;
+}
+
+/**
+ * glamor_trapezoids will first try to create a trapezoid mask using shader,
+ * if failed, miTrapezoids will generate trapezoid mask accumulating in
+ * system memory.
+ */
+static Bool
+_glamor_trapezoids(CARD8 op,
+ PicturePtr src, PicturePtr dst,
+ PictFormatPtr mask_format, INT16 x_src, INT16 y_src,
+ int ntrap, xTrapezoid * traps, Bool fallback)
+{
+ ScreenPtr screen = dst->pDrawable->pScreen;
+ BoxRec bounds;
+ PicturePtr picture;
+ INT16 x_dst, y_dst;
+ INT16 x_rel, y_rel;
+ int width, height, stride;
+ PixmapPtr pixmap;
+ pixman_image_t *image = NULL;
+ int ret = 0;
+ int has_large_trapezoid;
+
+ /* If a mask format wasn't provided, we get to choose, but behavior should
+ * be as if there was no temporary mask the traps were accumulated into.
+ */
+ if (!mask_format) {
+ if (dst->polyEdge == PolyEdgeSharp)
+ mask_format =
+ PictureMatchFormat(screen, 1, PICT_a1);
+ else
+ mask_format =
+ PictureMatchFormat(screen, 8, PICT_a8);
+ for (; ntrap; ntrap--, traps++)
+ glamor_trapezoids(op, src, dst, mask_format, x_src,
+ y_src, 1, traps);
+ return TRUE;
+ }
+
+ has_large_trapezoid = _glamor_trapezoid_bounds(ntrap, traps, &bounds);
+ DEBUGF("The bounds for all traps is: bounds.x1 = %d, bounds.x2 = %d, "
+ "bounds.y1 = %d, bounds.y2 = %d, ---- ntrap = %d\n", bounds.x1,
+ bounds.x2, bounds.y1, bounds.y2, ntrap);
+
+ if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+ return TRUE;
+
+ x_dst = traps[0].left.p1.x >> 16;
+ y_dst = traps[0].left.p1.y >> 16;
+
+ width = bounds.x2 - bounds.x1;
+ height = bounds.y2 - bounds.y1;
+ stride = PixmapBytePad(width, mask_format->depth);
+
+#ifdef GLAMOR_TRAPEZOID_SHADER
+ /* We seperate the render to two paths.
+ Some GL implemetation do not implement the Anti-Alias for triangles
+ and polygen's filling. So when the edge is not vertical or horizontal,
+ sawtooth will be obvious. The trapezoid is widely used to render wide
+ lines and circles. In these case, the line or circle will be divided
+ into a large number of small trapezoids to approximate it, so the sawtooth
+ at the edge will cause the result not be acceptable.
+ When the depth of the mask is 1, there is no Anti-Alias needed, so we
+ use the clip logic to generate the result directly(fast path).
+ When the depth is not 1, AA is needed and we use a shader to generate
+ a temp mask pixmap.
+ */
+ if (mask_format->depth == 1) {
+ ret = _glamor_trapezoids_with_shader(op, src, dst, mask_format,
+ x_src, y_src, ntrap, traps);
+ if(ret)
+ return TRUE;
+ } else {
+ if (has_large_trapezoid || ntrap > 256) {
+ /* The shader speed is relative slower than pixman when generating big chunk
+ trapezoid mask. We fallback to pixman to improve the performance. */
+ ;
+ } else if (dst->polyMode == PolyModeImprecise) {
+ /* The precise mode is that we sample the trapezoid on the centre points of
+ an (2*n+1)x(2*n-1) subpixel grid. It is computationally expensive in shader
+ and we use inside area ratio to replace it if the polymode == Imprecise. */
+ picture = glamor_create_mask_picture(screen, dst, mask_format,
+ width, height, 1);
+ if (!picture)
+ return TRUE;
+
+ ret = _glamor_generate_trapezoid_with_shader(screen, picture, traps, ntrap, &bounds);
+
+ if (!ret)
+ FreePicture(picture, 0);
+ }
+ }
+#endif
+
+ if (!ret) {
+ DEBUGF("Fallback to sw rasterize of trapezoid\n");
+
+ picture = glamor_create_mask_picture(screen, dst, mask_format,
+ width, height, 0);
+ if (!picture)
+ return TRUE;
+
+ image = pixman_image_create_bits(picture->format,
+ width, height, NULL, stride);
+ if (!image) {
+ FreePicture(picture, 0);
+ return TRUE;
+ }
+
+ for (; ntrap; ntrap--, traps++)
+ pixman_rasterize_trapezoid(image,
+ (pixman_trapezoid_t *) traps,
+ -bounds.x1, -bounds.y1);
+
+ pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
+
+ screen->ModifyPixmapHeader(pixmap, width, height,
+ mask_format->depth,
+ BitsPerPixel(mask_format->depth),
+ PixmapBytePad(width,
+ mask_format->depth),
+ pixman_image_get_data(image));
+ }
+
+ x_rel = bounds.x1 + x_src - x_dst;
+ y_rel = bounds.y1 + y_src - y_dst;
+ DEBUGF("x_src = %d, y_src = %d, x_dst = %d, y_dst = %d, "
+ "x_rel = %d, y_rel = %d\n", x_src, y_src, x_dst,
+ y_dst, x_rel, y_rel);
+
+ CompositePicture(op, src, picture, dst,
+ x_rel, y_rel,
+ 0, 0,
+ bounds.x1, bounds.y1,
+ bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
+
+ if (image)
+ pixman_image_unref(image);
+
+ FreePicture(picture, 0);
+ return TRUE;
+}
+
+void
+glamor_trapezoids(CARD8 op,
+ PicturePtr src, PicturePtr dst,
+ PictFormatPtr mask_format, INT16 x_src, INT16 y_src,
+ int ntrap, xTrapezoid * traps)
+{
+ DEBUGF("x_src = %d, y_src = %d, ntrap = %d\n", x_src, y_src, ntrap);
+
+ _glamor_trapezoids(op, src, dst, mask_format, x_src,
+ y_src, ntrap, traps, TRUE);
+}
+
+Bool
+glamor_trapezoids_nf(CARD8 op,
+ PicturePtr src, PicturePtr dst,
+ PictFormatPtr mask_format, INT16 x_src, INT16 y_src,
+ int ntrap, xTrapezoid * traps)
+{
+ DEBUGF("x_src = %d, y_src = %d, ntrap = %d\n", x_src, y_src, ntrap);
+
+ return _glamor_trapezoids(op, src, dst, mask_format, x_src,
+ y_src, ntrap, traps, FALSE);
+}
+
+#endif /* RENDER */
+
diff --git a/glamor/glamor_triangles.c b/glamor/glamor_triangles.c
new file mode 100644
index 000000000..e0f4a9708
--- /dev/null
+++ b/glamor/glamor_triangles.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1998 Keith Packard
+ *
+ * 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:
+ * Zhigang Gong <zhigang.gong@gmail.com>
+ *
+ */
+
+#include "glamor_priv.h"
+
+static Bool
+_glamor_triangles(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc, INT16 ySrc, int ntris, xTriangle * tris, Bool fallback)
+{
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(pDst->pDrawable)
+ && (!pSrc->pDrawable
+ || glamor_ddx_fallback_check_pixmap(pSrc->pDrawable)))
+ return FALSE;
+
+ if (glamor_prepare_access_picture(pDst, GLAMOR_ACCESS_RW)) {
+ if (glamor_prepare_access_picture(pSrc,
+ GLAMOR_ACCESS_RO)) {
+
+ fbTriangles(op, pSrc, pDst, maskFormat, xSrc,
+ ySrc, ntris, tris);
+
+ glamor_finish_access_picture(pSrc, GLAMOR_ACCESS_RO);
+ }
+
+ glamor_finish_access_picture(pDst, GLAMOR_ACCESS_RW);
+ }
+ return TRUE;
+}
+
+void
+glamor_triangles(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc, INT16 ySrc, int ntris, xTriangle * tris)
+{
+ _glamor_triangles(op, pSrc, pDst, maskFormat,
+ xSrc, ySrc, ntris, tris, TRUE);
+}
+
+Bool
+glamor_triangles_nf(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc, INT16 ySrc, int ntris, xTriangle * tris)
+{
+ return _glamor_triangles(op, pSrc, pDst, maskFormat,
+ xSrc, ySrc, ntris, tris, FALSE);
+}
+
diff --git a/glamor/glamor_utils.h b/glamor/glamor_utils.h
new file mode 100644
index 000000000..d30783826
--- /dev/null
+++ b/glamor/glamor_utils.h
@@ -0,0 +1,1835 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * 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 PR