summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2013-12-18 11:21:07 -0800
committerEric Anholt <eric@anholt.net>2013-12-18 11:21:07 -0800
commit2dbbe2565052cc024ce0e98918ed34c1239b780a (patch)
treeafbfe15131679fb9537d1795a93d1c81b0351369
parent4d62646142718024b0981eb4f1fd0131e829161f (diff)
parent7982eca622bbc4b6a4845801a77da8a16138004a (diff)
Merge branch 'glamor-gongzg-merge'
-rw-r--r--glamor/Makefile.am47
-rw-r--r--glamor/glamor.c401
-rw-r--r--glamor/glamor.h63
-rw-r--r--glamor/glamor_copyarea.c401
-rw-r--r--glamor/glamor_copywindow.c60
-rw-r--r--glamor/glamor_core.c495
-rw-r--r--glamor/glamor_debug.h82
-rw-r--r--glamor/glamor_egl.c384
-rw-r--r--glamor/glamor_fill.c205
-rw-r--r--glamor/glamor_fillspans.c89
-rw-r--r--glamor/glamor_getspans.c110
-rw-r--r--glamor/glamor_gl_dispatch.c73
-rw-r--r--glamor/glamor_gl_dispatch.h101
-rw-r--r--glamor/glamor_glext.h32
-rw-r--r--glamor/glamor_glyphs.c860
-rw-r--r--glamor/glamor_picture.c93
-rw-r--r--glamor/glamor_pixmap.c752
-rw-r--r--glamor/glamor_polyfillrect.c110
-rw-r--r--glamor/glamor_polylines.c179
-rw-r--r--glamor/glamor_priv.h569
-rw-r--r--glamor/glamor_putimage.c417
-rw-r--r--glamor/glamor_render.c1446
-rw-r--r--glamor/glamor_setspans.c110
-rw-r--r--glamor/glamor_tile.c194
-rw-r--r--glamor/glamor_triangles.c61
-rw-r--r--glamor/glamor_utils.h542
-rw-r--r--glamor/glamor_window.c74
27 files changed, 7950 insertions, 0 deletions
diff --git a/glamor/Makefile.am b/glamor/Makefile.am
new file mode 100644
index 000000000..8712e765a
--- /dev/null
+++ b/glamor/Makefile.am
@@ -0,0 +1,47 @@
+noinst_LTLIBRARIES = libglamor.la
+
+# Override these since glamor doesn't need them and the needed files aren't
+# built (in hw/xfree86/os-support/solaris) until after glamor is built
+SOLARIS_ASM_CFLAGS=""
+
+if XORG
+sdk_HEADERS = glamor.h
+endif
+
+if GLAMOR_GLES2
+libglamor_la_LIBADD = $(GLESV2_LIBS)
+else
+libglamor_la_LIBADD = $(GL_LIBS)
+endif
+
+if XORG
+sdk_HEADERS = glamor.h
+endif
+
+INCLUDES = \
+ $(XORG_INCS)
+
+
+AM_CFLAGS = $(XORG_CFLAGS) $(DIX_CFLAGS) $(LIBDRM_CFLAGS)
+
+libglamor_la_SOURCES = \
+ glamor.c \
+ glamor_copyarea.c \
+ glamor_copywindow.c \
+ glamor_core.c \
+ glamor_fill.c \
+ glamor_fillspans.c \
+ glamor_getspans.c \
+ glamor_glyphs.c \
+ glamor_polyfillrect.c \
+ glamor_polylines.c \
+ glamor_putimage.c \
+ glamor_setspans.c \
+ glamor_render.c \
+ glamor_tile.c \
+ glamor_triangles.c\
+ glamor_pixmap.c\
+ glamor_picture.c\
+ glamor_window.c\
+ glamor_gl_dispatch.c\
+ glamor.h
diff --git a/glamor/glamor.c b/glamor/glamor.c
new file mode 100644
index 000000000..ee83fd3e9
--- /dev/null
+++ b/glamor/glamor.c
@@ -0,0 +1,401 @@
+/*
+ * 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.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;
+}
+
+void
+glamor_set_pixmap_texture(PixmapPtr pixmap, int w, int h, unsigned int tex)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ glamor_pixmap_private *pixmap_priv;
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ assert(pixmap_priv);
+ pixmap_priv->tex = tex;
+
+ /* Create a framebuffer object wrapping the texture so that we can render
+ * to it.
+ */
+ pixmap_priv->gl_fbo = 1;
+ if (tex != 0) {
+ glamor_pixmap_ensure_fb(pixmap);
+ pixmap_priv->gl_tex = 1;
+ }
+ else {
+ pixmap_priv->fb = 0;
+ pixmap_priv->gl_tex = 0;
+ }
+ screen->ModifyPixmapHeader(pixmap, w, h, 0, 0,
+ (((w * pixmap->drawable.bitsPerPixel +
+ 7) / 8) + 3) & ~3,
+ NULL);
+}
+
+/* Set screen pixmap. If tex equal to 0, means it is called from ephyr. */
+void
+glamor_set_screen_pixmap_texture(ScreenPtr screen, int w, int h, unsigned int tex)
+{
+ PixmapPtr pixmap = screen->GetScreenPixmap(screen);
+ glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+
+ glamor_set_pixmap_texture(pixmap, w, h, tex);
+ glamor_priv->screen_fbo = pixmap_priv->fb;
+ pixmap_priv->pending_op.type = GLAMOR_PENDING_NONE;
+}
+
+
+
+#define GLAMOR_PIXMAP_MEMORY 0
+#define GLAMOR_PIXMAP_TEXTURE 1
+
+
+
+static PixmapPtr
+glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
+ unsigned int usage)
+{
+ PixmapPtr pixmap;
+ GLenum format;
+ GLuint tex;
+ int type = GLAMOR_PIXMAP_TEXTURE;
+ glamor_pixmap_private *pixmap_priv;
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+ if (w > 32767 || h > 32767)
+ return NullPixmap;
+
+ if (!glamor_check_fbo_size(glamor_priv, w,h)
+ || !glamor_check_fbo_depth(depth)
+ || usage == GLAMOR_CREATE_PIXMAP_CPU) {
+ /* MESA can only support upto MAX_WIDTH*MAX_HEIGHT fbo.
+ If we exceed such limitation, we have to use framebuffer.*/
+ type = GLAMOR_PIXMAP_MEMORY;
+ pixmap = fbCreatePixmap (screen, w, h, depth, usage);
+ screen->ModifyPixmapHeader(pixmap, w, h, 0, 0,
+ (((w * pixmap->drawable.bitsPerPixel +
+ 7) / 8) + 3) & ~3,
+ NULL);
+#if 0
+ if (usage != GLAMOR_CREATE_PIXMAP_CPU)
+ glamor_fallback("choose cpu memory for pixmap %p ,"
+ " %d x %d depth %d\n", pixmap, w, h, depth);
+#endif
+ } else
+ pixmap = fbCreatePixmap (screen, 0, 0, depth, usage);
+
+ if (dixAllocatePrivates(&pixmap->devPrivates, PRIVATE_PIXMAP) != TRUE) {
+ fbDestroyPixmap(pixmap);
+ ErrorF("Fail to allocate privates for PIXMAP.\n");
+ return NullPixmap;
+ }
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ pixmap_priv->container = pixmap;
+ pixmap_priv->glamor_priv = glamor_priv;
+
+ if (w == 0 || h == 0 || type == GLAMOR_PIXMAP_MEMORY)
+ return pixmap;
+
+ switch (depth) {
+#if 0
+ case 8:
+ format = GL_ALPHA;
+ break;
+#endif
+ case 24:
+ format = GL_RGB;
+ break;
+ default:
+ format = GL_RGBA;
+ break;
+ }
+
+ /* Create the texture used to store the pixmap's data. */
+ 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_set_pixmap_texture(pixmap, w, h, tex);
+ return pixmap;
+}
+
+static Bool
+glamor_destroy_pixmap(PixmapPtr pixmap)
+{
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+ if (pixmap->refcnt == 1) {
+ glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
+ if (pixmap_priv->fb)
+ dispatch->glDeleteFramebuffers(1, &pixmap_priv->fb);
+ if (pixmap_priv->tex)
+ dispatch->glDeleteTextures(1, &pixmap_priv->tex);
+ if (pixmap_priv->pbo)
+ dispatch->glDeleteBuffers(1, &pixmap_priv->pbo);
+ dixFreePrivates(pixmap->devPrivates, PRIVATE_PIXMAP);
+ }
+
+ return fbDestroyPixmap(pixmap);
+}
+
+static void
+glamor_block_handler(void *data, OSTimePtr timeout, void *last_select_mask)
+{
+ glamor_gl_dispatch *dispatch = data;
+ dispatch->glFlush();
+}
+
+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;
+ }
+
+ dixSetPrivate(&screen->devPrivates, glamor_screen_private_key, glamor_priv);
+
+ if (!dixRegisterPrivateKey(glamor_pixmap_private_key,PRIVATE_PIXMAP,
+ sizeof(glamor_pixmap_private))) {
+ 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);
+
+ if (!RegisterBlockAndWakeupHandlers(glamor_block_handler,
+ glamor_wakeup_handler,
+ (void*)&glamor_priv->dispatch)) {
+ goto fail;
+ }
+
+ glamor_set_debug_level(&glamor_debug_level);
+ glamor_priv->saved_close_screen = screen->CloseScreen;
+ screen->CloseScreen = glamor_close_screen;
+
+ glamor_priv->saved_create_gc = screen->CreateGC;
+ screen->CreateGC = glamor_create_gc;
+
+ glamor_priv->saved_create_pixmap = screen->CreatePixmap;
+ screen->CreatePixmap = glamor_create_pixmap;
+
+ glamor_priv->saved_destroy_pixmap = screen->DestroyPixmap;
+ screen->DestroyPixmap = glamor_destroy_pixmap;
+
+ glamor_priv->saved_get_spans = screen->GetSpans;
+ screen->GetSpans = glamor_get_spans;
+
+ glamor_priv->saved_get_image = screen->GetImage;
+ screen->GetImage = miGetImage;
+
+ glamor_priv->saved_change_window_attributes = screen->ChangeWindowAttributes;
+ screen->ChangeWindowAttributes = glamor_change_window_attributes;
+
+ glamor_priv->saved_copy_window = screen->CopyWindow;
+ screen->CopyWindow = glamor_copy_window;
+
+ glamor_priv->saved_bitmap_to_region = screen->BitmapToRegion;
+ screen->BitmapToRegion = glamor_bitmap_to_region;
+
+#ifdef RENDER
+ glamor_priv->saved_composite = ps->Composite;
+ ps->Composite = glamor_composite;
+ glamor_priv->saved_trapezoids = ps->Trapezoids;
+ ps->Trapezoids = glamor_trapezoids;
+ glamor_priv->saved_glyphs = ps->Glyphs;
+ ps->Glyphs = glamor_glyphs;
+ glamor_priv->saved_triangles = ps->Triangles;
+ ps->Triangles = glamor_triangles;
+ glamor_init_composite_shaders(screen);
+ glamor_priv->saved_create_picture = ps->CreatePicture;
+ ps->CreatePicture = glamor_create_picture;
+ glamor_priv->saved_destroy_picture = ps->DestroyPicture;
+ ps->DestroyPicture = glamor_destroy_picture;
+
+ glamor_priv->saved_unrealize_glyph = ps->UnrealizeGlyph;
+ ps->UnrealizeGlyph = glamor_glyph_unrealize;
+#endif
+ glamor_init_solid_shader(screen);
+ glamor_init_tile_shader(screen);
+ glamor_init_putimage_shaders(screen);
+ glamor_init_finish_access_shaders(screen);
+ glamor_pixmap_init(screen);
+
+#ifdef GLAMOR_GLES2
+ glamor_priv->gl_flavor = GLAMOR_GL_ES2;
+#else
+ glamor_priv->gl_flavor = GLAMOR_GL_DESKTOP;
+#endif
+
+ return TRUE;
+
+fail:
+ free(glamor_priv);
+ dixSetPrivate(&screen->devPrivates, glamor_screen_private_key, NULL);
+ return FALSE;
+}
+
+Bool
+glamor_close_screen(int idx, ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+#ifdef RENDER
+ PictureScreenPtr ps = GetPictureScreenIfSet(screen);
+#endif
+ glamor_glyphs_fini(screen);
+ screen->CloseScreen = glamor_priv->saved_close_screen;
+ screen->CreateGC = glamor_priv->saved_create_gc;
+ screen->CreatePixmap = glamor_priv->saved_create_pixmap;
+ screen->DestroyPixmap = glamor_priv->saved_destroy_pixmap;
+ screen->GetSpans = glamor_priv->saved_get_spans;
+ screen->ChangeWindowAttributes = glamor_priv->saved_change_window_attributes;
+ screen->CopyWindow = glamor_priv->saved_copy_window;
+ screen->BitmapToRegion = glamor_priv->saved_bitmap_to_region;
+#ifdef RENDER
+ if (ps) {
+ ps->Composite = glamor_priv->saved_composite;
+ ps->Trapezoids = glamor_priv->saved_trapezoids;
+ ps->Glyphs = glamor_priv->saved_glyphs;
+ ps->Triangles = glamor_priv->saved_triangles;
+ ps->CreatePicture = glamor_priv->saved_create_picture;
+ }
+#endif
+ if (glamor_priv->vb)
+ free(glamor_priv->vb);
+ free(glamor_priv);
+ return screen->CloseScreen(idx, screen);
+
+}
+
+void
+glamor_fini(ScreenPtr screen)
+{
+/* Do nothing currently. */
+}
diff --git a/glamor/glamor.h b/glamor/glamor.h
new file mode 100644
index 000000000..e8719fb2f
--- /dev/null
+++ b/glamor/glamor.h
@@ -0,0 +1,63 @@
+/*
+ * 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_H
+#define GLAMOR_H
+
+#include "scrnintstr.h"
+#ifdef GLAMOR_FOR_XORG
+#include "xf86str.h"
+#endif
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "gcstruct.h"
+#include "picturestr.h"
+#include "fb.h"
+#include "fbpict.h"
+
+#endif /* GLAMOR_H */
+
+
+#define GLAMOR_INVERTED_Y_AXIS 1
+#define GLAMOR_HOSTX 2
+#define GLAMOR_VALID_FLAGS (GLAMOR_INVERTED_Y_AXIS | GLAMOR_HOSTX)
+
+#define GLAMOR_EGL_EXTERNAL_BUFFER 3
+
+extern _X_EXPORT Bool glamor_init(ScreenPtr screen, unsigned int flags);
+extern _X_EXPORT void glamor_fini(ScreenPtr screen);
+extern _X_EXPORT void glamor_set_screen_pixmap_texture(ScreenPtr screen, int w, int h, unsigned int tex);
+extern _X_EXPORT Bool glamor_glyphs_init (ScreenPtr pScreen);
+void glamor_set_pixmap_texture(PixmapPtr pixmap, int w, int h, unsigned int tex);
+
+#ifdef GLAMOR_FOR_XORG
+extern _X_EXPORT Bool glamor_egl_init(ScrnInfoPtr scrn, int fd);
+extern _X_EXPORT Bool glamor_create_egl_screen_image(ScreenPtr screen, int handle, int stride);
+extern _X_EXPORT Bool glamor_create_egl_pixmap_image(PixmapPtr pixmap, int handle, int stride);
+extern _X_EXPORT Bool glamor_close_egl_screen(ScreenPtr screen);
+extern _X_EXPORT void glamor_free_egl_screen(int scrnIndex, int flags);
+#endif
diff --git a/glamor/glamor_copyarea.c b/glamor/glamor_copyarea.c
new file mode 100644
index 000000000..ec57520e8
--- /dev/null
+++ b/glamor/glamor_copyarea.c
@@ -0,0 +1,401 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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;
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+ int dst_x_off, dst_y_off, src_x_off, src_y_off, i;
+
+ 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);
+
+ if (src_pixmap_priv->pending_op.type == GLAMOR_PENDING_FILL)
+ return FALSE;
+
+ if (gc) {
+ if (gc->alu != GXcopy) {
+ glamor_delayed_fallback(screen, "non-copy ALU\n");
+ return FALSE;
+ }
+ if (!glamor_pm_is_solid(dst, gc->planemask)) {
+ glamor_delayed_fallback(screen, "non-solid planemask\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;
+ }
+ glamor_validate_pixmap(dst_pixmap);
+
+ dispatch->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, src_pixmap_priv->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);
+ src_y_off += dy;
+
+ 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);
+ }
+ }
+ 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 = &glamor_priv->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;
+ int flush_needed = 0;
+
+ src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
+ dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv)) {
+ glamor_delayed_fallback(dst->pScreen, "dst has no fbo.\n");
+ goto fail;
+ }
+
+ if (!src_pixmap_priv->gl_fbo) {
+#ifndef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
+ glamor_delayed_fallback(dst->pScreen, "src has no fbo.\n");
+ goto fail;
+#else
+ src_status = glamor_upload_pixmap_to_texture(src_pixmap);
+ if (src_status != GLAMOR_UPLOAD_DONE)
+ goto fail;
+#endif
+ }
+ else
+ flush_needed = 1;
+
+ if (gc) {
+ glamor_set_alu(dispatch, gc->alu);
+ if (!glamor_set_planemask(dst_pixmap, gc->planemask))
+ goto fail;
+ if (gc->alu != GXcopy) {
+ glamor_set_destination_pixmap_priv_nc(src_pixmap_priv);
+ glamor_validate_pixmap(src_pixmap);
+ }
+ }
+
+ glamor_set_destination_pixmap_priv_nc(dst_pixmap_priv);
+ glamor_validate_pixmap(dst_pixmap);
+
+ pixmap_priv_get_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->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, GL_FALSE,
+ 2 * sizeof(float),
+ vertices);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+
+ if (GLAMOR_PIXMAP_PRIV_NO_PENDING(src_pixmap_priv)) {
+ glamor_get_drawable_deltas(src, src_pixmap, &src_x_off, &src_y_off);
+ dx += src_x_off;
+ dy += src_y_off;
+ pixmap_priv_get_scale(src_pixmap_priv, &src_xscale, &src_yscale);
+
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glBindTexture(GL_TEXTURE_2D, src_pixmap_priv->tex);
+#ifndef GLAMOR_GLES2
+ dispatch->glEnable(GL_TEXTURE_2D);
+#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_no_revert[0], 1);
+ dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[0], 0);
+
+ }
+ else {
+ GLAMOR_CHECK_PENDING_FILL(dispatch, glamor_priv, src_pixmap_priv);
+ }
+
+ for (i = 0; i < nbox; i++) {
+
+ glamor_set_normalize_vcoords(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);
+
+ if (GLAMOR_PIXMAP_PRIV_NO_PENDING(src_pixmap_priv))
+ glamor_set_normalize_tcoords(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);
+ if (GLAMOR_PIXMAP_PRIV_NO_PENDING(src_pixmap_priv)) {
+ 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. */
+ if (flush_needed)
+ dispatch->glFlush();
+ return TRUE;
+
+fail:
+ glamor_set_alu(dispatch, GXcopy);
+ glamor_set_planemask(dst_pixmap, ~0);
+ return FALSE;
+}
+
+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_access_t dst_access;
+ PixmapPtr dst_pixmap, src_pixmap, temp_pixmap = NULL;
+ DrawablePtr temp_src = src;
+ glamor_pixmap_private *dst_pixmap_priv, *src_pixmap_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;
+
+ 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;
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv)) {
+ glamor_fallback("dest pixmap %p has no fbo. \n", dst_pixmap);
+ goto fail;
+ }
+
+ 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->fb == dst_pixmap_priv->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;
+ }
+ }
+ }
+ /* XXX need revisit to handle overlapped area copying. */
+
+#ifndef GLAMOR_GLES2
+ if ((overlaped
+ || !src_pixmap_priv->gl_tex || !dst_pixmap_priv->gl_tex )
+ && glamor_copy_n_to_n_fbo_blit(src, dst, gc, box, nbox, dx, dy)) {
+ goto done;
+ return;
+ }
+#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))) {
+
+ temp_pixmap = (*screen->CreatePixmap)(screen,
+ bound.x2 - bound.x1,
+ bound.y2 - bound.y1,
+ src_pixmap->drawable.depth,
+ overlaped ? 0 : GLAMOR_CREATE_PIXMAP_CPU);
+ if (!temp_pixmap)
+ goto fail;
+ glamor_transform_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_transform_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)) {
+ goto done;
+ }
+
+
+ fail:
+ 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 (gc && gc->alu != GXcopy)
+ dst_access = GLAMOR_ACCESS_RW;
+ else
+ dst_access = GLAMOR_ACCESS_WO;
+
+ 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_finish_access(dst);
+ }
+
+done:
+ glamor_clear_delayed_fallbacks(src->pScreen);
+ glamor_clear_delayed_fallbacks(dst->pScreen);
+ if (temp_src != src) {
+ (*screen->DestroyPixmap)(temp_pixmap);
+ }
+}
+
+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;
+}
diff --git a/glamor/glamor_copywindow.c b/glamor/glamor_copywindow.c
new file mode 100644
index 000000000..1e840a934
--- /dev/null
+++ b/glamor/glamor_copywindow.c
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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..2249ac800
--- /dev/null
+++ b/glamor/glamor_core.c
@@ -0,0 +1,495 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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->gl_fbo == 0)
+ return 'm';
+ if (pixmap_priv->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);
+
+ 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);
+ 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);
+}
+
+void
+glamor_init_finish_access_shaders(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->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 *fs_source =
+ GLAMOR_DEFAULT_PRECISION
+ "varying vec2 source_texture;\n"
+ "uniform sampler2D sampler;\n"
+ "uniform int no_revert;\n"
+ "uniform int swap_rb;\n"
+ "void main()\n"
+ "{\n"
+ " if (no_revert == 1) \n"
+ " { \n"
+ " if (swap_rb == 1) \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 == 1) \n"
+ " gl_FragColor = texture2D(sampler, source_texture).argb;\n"
+ " else \n"
+ " gl_FragColor = texture2D(sampler, source_texture).abgr;\n"
+ " } \n"
+ "}\n";
+
+ const char *set_alpha_source =
+ GLAMOR_DEFAULT_PRECISION
+ "varying vec2 source_texture;\n"
+ "uniform sampler2D sampler;\n"
+ "uniform int no_revert;\n"
+ "uniform int swap_rb;\n"
+ "void main()\n"
+ "{\n"
+ " if (no_revert == 1) \n"
+ " { \n"
+ " if (swap_rb == 1) \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 == 1) \n"
+ " gl_FragColor = vec4(1, texture2D(sampler, source_texture).rgb);\n"
+ " else \n"
+ " gl_FragColor = vec4(1, texture2D(sampler, source_texture).bgr);\n"
+ " } \n"
+ "}\n";
+ GLint fs_prog, vs_prog, avs_prog, set_alpha_prog;
+ GLint sampler_uniform_location;
+
+ 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);
+ fs_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER, fs_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);
+ set_alpha_prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER, set_alpha_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_no_revert[0] =
+ dispatch->glGetUniformLocation(glamor_priv->finish_access_prog[0], "no_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_no_revert[0],1);
+ dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[0],0);
+ dispatch->glUseProgram(0);
+
+ glamor_priv->finish_access_no_revert[1] =
+ dispatch->glGetUniformLocation(glamor_priv->finish_access_prog[1], "no_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_no_revert[1],1);
+ dispatch->glUniform1i(sampler_uniform_location, 0);
+ dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[1],0);
+ dispatch->glUseProgram(0);
+
+}
+
+void
+glamor_finish_access(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);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ return;
+
+ if ( pixmap_priv->access_mode != GLAMOR_ACCESS_RO) {
+ glamor_restore_pixmap_to_texture(pixmap);
+ }
+
+ if (pixmap_priv->pbo != 0 && pixmap_priv->pbo_valid) {
+ assert(glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP);
+ dispatch->glBindBuffer (GL_PIXEL_PACK_BUFFER, 0);
+ dispatch->glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
+ pixmap_priv->pbo_valid = FALSE;
+ dispatch->glDeleteBuffers(1, &pixmap_priv->pbo);
+ pixmap_priv->pbo = 0;
+ } else {
+ free(pixmap->devPrivate.ptr);
+ }
+
+ 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);
+ 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);
+ if (gc->stipple)
+ glamor_finish_access(&gc->stipple->drawable);
+}
+
+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 = miCopyPlane,
+ .PolyPoint = miPolyPoint,
+ .Polylines = glamor_poly_lines,
+ .PolySegment = miPolySegment,
+ .PolyRectangle = miPolyRectangle,
+ .PolyArc = miPolyArc,
+ .FillPolygon = miFillPolygon,
+ .PolyFillRect = glamor_poly_fill_rect,
+ .PolyFillArc = miPolyFillArc,
+ .PolyText8 = miPolyText8,
+ .PolyText16 = miPolyText16,
+ .ImageText8 = miImageText8,
+ .ImageText16 = miImageText16,
+ .ImageGlyphBlt = miImageGlyphBlt,
+ .PolyGlyphBlt = miPolyGlyphBlt,
+ .PushPixels = 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.
+ */
+static 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);
+ }
+ }
+ 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);
+ }
+ }
+ }
+ /* 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);
+ }
+ } 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);
+ return ret;
+}
+
+/* Borrow from cairo. */
+Bool
+glamor_gl_has_extension(char *extension)
+{
+ const char *gl_extensions;
+ char *pext;
+ int ext_len;
+ ext_len = strlen(extension);
+
+ gl_extensions = (const char*)glGetString(GL_EXTENSIONS);
+ pext = (char*)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..48682e802
--- /dev/null
+++ b/glamor/glamor_debug.h
@@ -0,0 +1,82 @@
+#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__ ); \
+ AbortServer(); \
+ } 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)
+
+
+#endif
diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c
new file mode 100644
index 000000000..921023eae
--- /dev/null
+++ b/glamor/glamor_egl.c
@@ -0,0 +1,384 @@
+/*
+ * 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_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+#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
+
+#include <gbm.h>
+
+#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>
+
+#define GLAMOR_FOR_XORG
+
+#include <glamor.h>
+#include "glamor_gl_dispatch.h"
+
+#define GLAMOR_VERSION_MAJOR 0
+#define GLAMOR_VERSION_MINOR 1
+#define GLAMOR_VERSION_PATCH 0
+
+static const char glamor_name[] = "glamor";
+
+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;
+ EGLImageKHR root;
+ EGLint major, minor;
+
+ CreateScreenResourcesProcPtr CreateScreenResources;
+ CloseScreenProcPtr CloseScreen;
+ int fd;
+ int front_buffer_handle;
+ int cpp;
+ struct gbm_device *gbm;
+
+ PFNEGLCREATEDRMIMAGEMESA egl_create_drm_image_mesa;
+ PFNEGLEXPORTDRMIMAGEMESA egl_export_drm_image_mesa;
+ PFNEGLCREATEIMAGEKHRPROC egl_create_image_khr;
+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC egl_image_target_texture2d_oes;
+ struct glamor_gl_dispatch *dispatch;
+};
+
+int xf86GlamorEGLPrivateIndex = -1;
+
+static struct glamor_egl_screen_private* glamor_get_egl_screen_private(ScrnInfoPtr scrn)
+{
+ return (struct glamor_egl_screen_private *) scrn->privates[xf86GlamorEGLPrivateIndex].ptr;
+}
+
+static EGLImageKHR
+_glamor_create_egl_image(struct glamor_egl_screen_private *glamor_egl, int width, int height, int stride, int name)
+{
+ 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 / 4;
+ image = glamor_egl->egl_create_image_khr (glamor_egl->display,
+ glamor_egl->context,
+ EGL_DRM_BUFFER_MESA,
+ (void*)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);
+ return TRUE;
+}
+
+
+Bool
+glamor_create_egl_screen_image(ScreenPtr screen, int handle, int stride)
+{
+ ScrnInfoPtr scrn = xf86Screens[screen->myNum];
+ struct glamor_egl_screen_private *glamor_egl = glamor_get_egl_screen_private(scrn);
+ EGLImageKHR image;
+ GLuint texture;
+
+ if (!glamor_get_flink_name(glamor_egl->fd, handle, &glamor_egl->front_buffer_handle)) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Couldn't flink front buffer handle\n");
+ return FALSE;
+ }
+
+ if (glamor_egl->root) {
+ eglDestroyImageKHR(glamor_egl->display, glamor_egl->root);
+ glamor_egl->root = EGL_NO_IMAGE_KHR;
+ }
+
+ image = _glamor_create_egl_image( glamor_egl,
+ scrn->virtualX,
+ scrn->virtualY,
+ stride,
+ glamor_egl->front_buffer_handle);
+ if (image == EGL_NO_IMAGE_KHR)
+ return FALSE;
+
+ glamor_create_texture_from_image(glamor_egl, image, &texture);
+ glamor_set_screen_pixmap_texture(screen, scrn->virtualX, scrn->virtualY, texture);
+ glamor_egl->root = image;
+ return TRUE;
+}
+
+/*
+ * This function will be called from the dri buffer allocation.
+ * It is somehow very familiar with the create screen image.
+ * XXX the egl image here is not stored at any data structure.
+ * Does this cause a leak problem?
+ */
+Bool
+glamor_create_egl_pixmap_image(PixmapPtr pixmap, int handle, int stride)
+{
+ ScreenPtr screen = pixmap->drawable.pScreen;
+ ScrnInfoPtr scrn = xf86Screens[screen->myNum];
+ struct glamor_egl_screen_private *glamor_egl = glamor_get_egl_screen_private(scrn);
+ EGLImageKHR image;
+ GLuint texture;
+ int name;
+ if (!glamor_get_flink_name(glamor_egl->fd, handle, &name)) {
+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
+ "Couldn't flink pixmap handle\n");
+ return FALSE;
+ }
+
+ image = _glamor_create_egl_image( glamor_egl,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ stride,
+ name);
+ if (image == EGL_NO_IMAGE_KHR)
+ return FALSE;
+
+ glamor_create_texture_from_image(glamor_egl, image, &texture);
+ glamor_set_pixmap_texture(pixmap, pixmap->drawable.width, pixmap->drawable.height, texture);
+ return TRUE;
+}
+
+Bool
+glamor_close_egl_screen(ScreenPtr screen)
+{
+ ScrnInfoPtr scrn = xf86Screens[screen->myNum];
+ struct glamor_egl_screen_private *glamor_egl = glamor_get_egl_screen_private(scrn);
+ glamor_fini(screen);
+
+ eglDestroyImageKHR(glamor_egl->display, glamor_egl->root);
+
+
+ glamor_egl->root = EGL_NO_IMAGE_KHR;
+
+ return TRUE;
+}
+
+
+
+static Bool
+glamor_egl_has_extension(struct glamor_egl_screen_private *glamor_egl, char *extension)
+{
+ const char *egl_extensions;
+ char *pext;
+ int ext_len;
+ ext_len = strlen(extension);
+
+ egl_extensions = (const char*)eglQueryString(glamor_egl->display, EGL_EXTENSIONS);
+ pext = (char*)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;
+}
+
+
+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 (xf86GlamorEGLPrivateIndex == -1)
+ xf86GlamorEGLPrivateIndex = xf86AllocateScrnInfoPrivateIndex();
+
+ scrn->privates[xf86GlamorEGLPrivateIndex].ptr = glamor_egl;
+
+ glamor_egl->fd = fd;
+
+ glamor_egl->display = eglGetDRMDisplayMESA(glamor_egl->fd);
+
+ if (glamor_egl->display == EGL_NO_DISPLAY) {
+ 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);
+#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; \
+ }
+
+ GLAMOR_CHECK_EGL_EXTENSION(MESA_drm_image);
+ GLAMOR_CHECK_EGL_EXTENSION(KHR_gl_renderbuffer_image);
+#ifdef GLAMOR_GLES2
+ GLAMOR_CHECK_EGL_EXTENSION(KHR_surfaceless_gles2);
+#else
+ GLAMOR_CHECK_EGL_EXTENSION(KHR_surfaceless_opengl);
+#endif
+
+ glamor_egl->egl_export_drm_image_mesa = (PFNEGLEXPORTDRMIMAGEMESA)
+ eglGetProcAddress("eglExportDRMImageMESA");
+ glamor_egl->egl_create_image_khr = (PFNEGLCREATEIMAGEKHRPROC)
+ eglGetProcAddress("eglCreateImageKHR");
+
+ glamor_egl->egl_image_target_texture2d_oes = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)
+ eglGetProcAddress("glEGLImageTargetTexture2DOES");
+
+ if (!glamor_egl->egl_create_image_khr
+ || !glamor_egl->egl_export_drm_image_mesa
+ || !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;
+ }
+
+
+
+ return TRUE;
+}
+
+void
+glamor_free_egl_screen(int scrnIndex, int flags)
+{
+ ScrnInfoPtr scrn = xf86Screens[scrnIndex];
+ struct glamor_egl_screen_private *glamor_egl = glamor_get_egl_screen_private(scrn);
+
+ if (glamor_egl != NULL)
+ {
+ if (!(flags & GLAMOR_EGL_EXTERNAL_BUFFER)) {
+ eglMakeCurrent(glamor_egl->display,
+ EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ eglTerminate(glamor_egl->display);
+ }
+ free(glamor_egl);
+ }
+}
+
+/* egl version. */
+
+Bool
+glamor_gl_dispatch_init(ScreenPtr screen, struct glamor_gl_dispatch *dispatch, int gl_version)
+{
+ ScrnInfoPtr scrn = xf86Screens[screen->myNum];
+ struct glamor_egl_screen_private *glamor_egl = glamor_get_egl_screen_private(scrn);
+ if (!glamor_gl_dispatch_init_impl(dispatch, gl_version, eglGetProcAddress))
+ return FALSE;
+ glamor_egl->dispatch = dispatch;
+ return TRUE;
+}
diff --git a/glamor/glamor_fill.c b/glamor/glamor_fill.c
new file mode 100644
index 000000000..7254167cb
--- /dev/null
+++ b/glamor/glamor_fill.c
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "glamor_priv.h"
+
+/** @file glamor_fillspans.c
+ *
+ * GC fill implementation, based loosely on fb_fill.c
+ */
+
+void
+glamor_fill(DrawablePtr drawable,
+ GCPtr gc,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(drawable);
+ int off_x, off_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;
+ return;
+ break;
+ case FillTiled:
+ if (!glamor_tile(dst_pixmap,
+ gc->tile.pixmap,
+ x + off_x,
+ y + off_y,
+ width,
+ height,
+ gc->alu,
+ gc->planemask,
+ drawable->x + x + off_x - gc->patOrg.x,
+ drawable->y + y + off_y - gc->patOrg.y))
+ goto fail;
+ break;
+ }
+ return;
+fail:
+ 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);
+ }
+return;
+
+}
+
+void
+glamor_init_solid_shader(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->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->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");
+}
+
+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_get_pixmap_private(pixmap);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+ int x1 = x;
+ int x2 = x + width;
+ int y1 = y;
+ int y2 = y + height;
+ GLfloat color[4];
+ float vertices[8];
+ GLfloat xscale, yscale;
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) {
+ glamor_fallback("dest %p has no fbo.\n", pixmap);
+ goto fail;
+ }
+ glamor_set_alu(dispatch, alu);
+ if (!glamor_set_planemask(pixmap, planemask)) {
+ glamor_fallback("Failedto set planemask in glamor_solid.\n");
+ goto fail;
+ }
+
+ glamor_get_rgba_from_pixel(fg_pixel,
+ &color[0],
+ &color[1],
+ &color[2],
+ &color[3],
+ format_for_pixmap(pixmap));
+#ifdef GLAMOR_DELAYED_FILLING
+ if (x == 0 && y == 0
+ && width == pixmap->drawable.width
+ && height == pixmap->drawable.height
+ && pixmap_priv->fb != glamor_priv->screen_fbo ) {
+ pixmap_priv->pending_op.type = GLAMOR_PENDING_FILL;
+ memcpy(&pixmap_priv->pending_op.fill.color4fv,
+ color, 4*sizeof(GLfloat));
+ pixmap_priv->pending_op.fill.colori = fg_pixel;
+ return TRUE;
+ }
+#endif
+ glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+ glamor_validate_pixmap(pixmap);
+
+ dispatch->glUseProgram(glamor_priv->solid_prog);
+
+ dispatch->glUniform4fv(glamor_priv->solid_color_uniform_location, 1, color);
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, GL_FALSE,
+ 2 * sizeof(float), vertices);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+ pixmap_priv_get_scale(pixmap_priv, &xscale, &yscale);
+
+ glamor_set_normalize_vcoords(xscale, yscale, x1, y1, x2, y2,
+ glamor_priv->yInverted,
+ vertices);
+ dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glUseProgram(0);
+ return TRUE;
+fail:
+ glamor_set_alu(dispatch, GXcopy);
+ glamor_set_planemask(pixmap, ~0);
+ return FALSE;
+}
+
+
diff --git a/glamor/glamor_fillspans.c b/glamor/glamor_fillspans.c
new file mode 100644
index 000000000..9a97da250
--- /dev/null
+++ b/glamor/glamor_fillspans.c
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+/** @file glamor_fillspans.c
+ *
+ * FillSpans implementation, taken from fb_fillsp.c
+ */
+#include "glamor_priv.h"
+
+void
+glamor_fill_spans(DrawablePtr drawable,
+ GCPtr gc,
+ int n,
+ DDXPointPtr points,
+ int *widths,
+ int sorted)
+{
+ DDXPointPtr ppt;
+ int nbox;
+ BoxPtr pbox;
+ int x1, x2, y;
+ RegionPtr pClip = fbGetCompositeClip(gc);
+
+ 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--) {
+ if (pbox->y1 > y || pbox->y2 <= y)
+ continue;
+
+ if (x1 < pbox->x1)
+ x1 = pbox->x1;
+
+ if (x2 > pbox->x2)
+ x2 = pbox->x2;
+
+ if (x2 <= x1)
+ continue;
+ glamor_fill (drawable,gc,
+ x1, y,
+ x2 - x1 , 1);
+ pbox++;
+ }
+ }
+ return;
+fail:
+ 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);
+ }
+}
diff --git a/glamor/glamor_getspans.c b/glamor/glamor_getspans.c
new file mode 100644
index 000000000..224af1ba5
--- /dev/null
+++ b/glamor/glamor_getspans.c
@@ -0,0 +1,110 @@
+/*
+ * 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>
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "glamor_priv.h"
+
+void
+glamor_get_spans(DrawablePtr drawable,
+ int wmax,
+ DDXPointPtr points,
+ int *widths,
+ int count,
+ char *dst)
+{
+ PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
+ GLenum format, type;
+ int no_alpha, no_revert;
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(drawable->pScreen);
+ glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+ PixmapPtr temp_pixmap = NULL;
+ int i;
+ uint8_t *readpixels_dst = (uint8_t *)dst;
+ int x_off, y_off;
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) {
+ glamor_fallback("pixmap has no fbo.\n");
+ goto fail;
+ }
+
+ if (glamor_get_tex_format_type_from_pixmap(pixmap,
+ &format,
+ &type,
+ &no_alpha,
+ &no_revert
+ )) {
+ glamor_fallback("unknown depth. %d \n",
+ drawable->depth);
+ goto fail;
+ }
+
+ glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+ glamor_validate_pixmap(pixmap);
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) {
+ /* XXX prepare whole pixmap is not efficient. */
+ temp_pixmap = glamor_es2_pixmap_read_prepare(pixmap, &format,
+ &type, no_alpha, no_revert);
+ pixmap_priv = glamor_get_pixmap_private(temp_pixmap);
+ glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+ }
+
+ glamor_get_drawable_deltas(drawable, pixmap, &x_off, &y_off);
+ for (i = 0; i < count; i++) {
+ if (glamor_priv->yInverted) {
+ dispatch->glReadPixels(points[i].x + x_off,
+ (points[i].y + y_off),
+ widths[i],
+ 1,
+ format, type,
+ readpixels_dst);
+ } else {
+ dispatch->glReadPixels(points[i].x + x_off,
+ pixmap->drawable.height - 1 - (points[i].y + y_off),
+ widths[i],
+ 1,
+ format, type,
+ readpixels_dst);
+ }
+ readpixels_dst += PixmapBytePad(widths[i], drawable->depth);
+ }
+ if (temp_pixmap)
+ pixmap->drawable.pScreen->DestroyPixmap(temp_pixmap);
+ return;
+
+fail:
+ glamor_fallback("from %p (%c)\n", drawable,
+ glamor_get_drawable_location(drawable));
+ if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RO)) {
+ fbGetSpans(drawable, wmax, points, widths, count, dst);
+ glamor_finish_access(drawable);
+ }
+}
diff --git a/glamor/glamor_gl_dispatch.c b/glamor/glamor_gl_dispatch.c
new file mode 100644
index 000000000..823262494
--- /dev/null
+++ b/glamor/glamor_gl_dispatch.c
@@ -0,0 +1,73 @@
+#include "glamor_priv.h"
+
+#define INIT_FUNC(dst,func_name,get) \
+ dst->func_name = get(#func_name); \
+ if (dst->func_name == NULL) \
+ { ErrorF("Failed to get fun %s", #func_name); \
+ goto fail; }
+
+Bool
+glamor_gl_dispatch_init_impl(struct glamor_gl_dispatch *dispatch,
+ int gl_version,
+ void *(*get_proc_address)(const char*))
+{
+ INIT_FUNC(dispatch, glMatrixMode, get_proc_address);
+ INIT_FUNC(dispatch, glLoadIdentity, get_proc_address);
+ INIT_FUNC(dispatch, glViewport, get_proc_address);
+ INIT_FUNC(dispatch, glRasterPos2i, get_proc_address);
+ INIT_FUNC(dispatch, glDrawArrays, get_proc_address);
+ INIT_FUNC(dispatch, glReadPixels, get_proc_address);
+ INIT_FUNC(dispatch, glDrawPixels, 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, 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, glLogicOp, 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, glMapBuffer, get_proc_address);
+ INIT_FUNC(dispatch, glUnmapBuffer, 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, glBlitFramebuffer, 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, glUniform4f, get_proc_address);
+ INIT_FUNC(dispatch, glUniform4fv, get_proc_address);
+ INIT_FUNC(dispatch, glCreateProgram, 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, 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..c519667f6
--- /dev/null
+++ b/glamor/glamor_gl_dispatch.h
@@ -0,0 +1,101 @@
+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 );
+
+ /* 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 (*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);
+ 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 (*glUniform4f) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+ void (*glUniform4fv) (GLint location, GLsizei count, const GLfloat *value);
+ GLuint (*glCreateProgram) (void);
+ GLuint (*glCreateShader) (GLenum type);
+ void (*glCompileShader) (GLuint shader);
+ void (*glAttachShader) (GLuint program, 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;
+
+Bool
+glamor_gl_dispatch_init_impl(struct glamor_gl_dispatch *dispatch,
+ int gl_version,
+ void *(*get_proc_address)(const char*));
+
+
+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..f734d1313
--- /dev/null
+++ b/glamor/glamor_glext.h
@@ -0,0 +1,32 @@
+#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
+
+#endif
diff --git a/glamor/glamor_glyphs.c b/glamor/glamor_glyphs.c
new file mode 100644
index 000000000..af6ec71a1
--- /dev/null
+++ b/glamor/glamor_glyphs.c
@@ -0,0 +1,860 @@
+/*
+ * 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
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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))
+
+typedef struct {
+ PicturePtr source;
+ glamor_composite_rect_t rects[GLYPH_BUFFER_SIZE];
+ int count;
+} glamor_glyph_buffer_t;
+
+struct glamor_glyph
+{
+ glamor_glyph_cache_t *cache;
+ uint16_t x, y;
+ uint16_t size, pos;
+};
+
+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 dixGetPrivate (&glyph->devPrivates, &glamor_glyph_key);
+}
+
+static inline void
+glamor_glyph_set_private (GlyphPtr glyph, struct glamor_glyph *priv)
+{
+ dixSetPrivate (&glyph->devPrivates, &glamor_glyph_key, priv);
+}
+
+
+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);
+ }
+ 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;
+ CARD32 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,
+ 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;
+ }
+ 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, 0))
+ 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;
+ GCPtr gc;
+
+ gc = GetScratchGC (pCachePixmap->drawable.depth, screen);
+ if (!gc)
+ return;
+
+ ValidateGC (&pCachePixmap->drawable, gc);
+
+ scratch = pGlyphPixmap;
+#if 0
+ /* Create a temporary bo to stream the updates to the cache */
+ if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth ||
+ !uxa_pixmap_is_offscreen (scratch))
+ {
+ scratch = screen->CreatePixmap (screen,
+ glyph->info.width,
+ glyph->info.height,
+ pCachePixmap->drawable.depth, 0);
+ if (scratch)
+ {
+ if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth)
+ {
+ 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);
+ uxa_composite (PictOpSrc, pGlyphPicture, NULL, picture,
+ 0, 0,
+ 0, 0,
+ 0, 0, glyph->info.width, glyph->info.height);
+ FreePicture (picture, 0);
+ }
+ }
+ else
+ {
+ glamor_copy_area (&pGlyphPixmap->drawable,
+ &scratch->drawable,
+ gc,
+ 0, 0,
+ glyph->info.width, glyph->info.height, 0, 0);
+ }
+ }
+ else
+ {
+ scratch = pGlyphPixmap;
+ }
+ }
+#endif
+ glamor_copy_area (&scratch->drawable, &pCachePixmap->drawable, gc,
+ 0, 0, glyph->info.width, glyph->info.height, x, y);
+
+ 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 = dixLookupPrivate (&glyph->devPrivates, &glamor_glyph_key);
+ if (priv == NULL)
+ return;
+
+ priv->cache->glyphs[priv->pos] = NULL;
+
+ glamor_glyph_set_private (glyph, NULL);
+ free (priv);
+}
+
+/* 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;
+}
+
+/**
+ * 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.
+ */
+static Bool
+glamor_glyphs_intersect (int nlist, GlyphListPtr list, GlyphPtr * glyphs)
+{
+ int x1, x2, y1, y2;
+ int n;
+ int x, y;
+ BoxRec extents;
+ Bool first = TRUE;
+
+ x = 0;
+ y = 0;
+ extents.x1 = 0;
+ extents.y1 = 0;
+ extents.x2 = 0;
+ extents.y2 = 0;
+ while (nlist--)
+ {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ list++;
+ while (n--)
+ {
+ GlyphPtr glyph = *glyphs++;
+
+ if (glyph->info.width == 0 || glyph->info.height == 0)
+ {
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ continue;
+ }
+
+ x1 = x - glyph->info.x;
+ if (x1 < MINSHORT)
+ x1 = MINSHORT;
+ y1 = y - glyph->info.y;
+ if (y1 < MINSHORT)
+ y1 = MINSHORT;
+ x2 = x1 + glyph->info.width;
+ if (x2 > MAXSHORT)
+ x2 = MAXSHORT;
+ y2 = y1 + glyph->info.height;
+ if (y2 > MAXSHORT)
+ y2 = MAXSHORT;
+
+ if (first)
+ {
+ extents.x1 = x1;
+ extents.y1 = y1;
+ extents.x2 = x2;
+ extents.y2 = y2;
+ first = FALSE;
+ }
+ else
+ {
+ if (x1 < extents.x2 && x2 > extents.x1 &&
+ y1 < extents.y2 && y2 > extents.y1)
+ {
+ return TRUE;
+ }
+
+ 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;
+ }
+ }
+
+ return FALSE;
+}
+
+
+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 (ScreenPtr screen, GlyphPtr glyph, int *out_x, int *out_y)
+{
+ glamor_screen_private *glamor = glamor_get_screen_private (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;
+ 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;
+ 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;
+
+ priv = glamor_glyph_get_private (evicted);
+ if (priv->size >= s)
+ {
+ cache->glyphs[i] = NULL;
+ glamor_glyph_set_private (evicted, NULL);
+ pos = cache->evict & glamor_glyph_size_to_mask (size);
+ }
+ else
+ priv = NULL;
+ break;
+ }
+ if (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)
+ {
+ if (priv != NULL)
+ free (priv);
+
+ priv = glamor_glyph_get_private (evicted);
+ glamor_glyph_set_private (evicted, NULL);
+ cache->glyphs[pos + s] = NULL;
+ }
+ }
+ }
+ /* And pick a new eviction position */
+ cache->evict = rand () % GLYPH_CACHE_SIZE;
+ }
+
+ if (priv == NULL)
+ {
+ priv = malloc (sizeof (struct glamor_glyph));
+ if (priv == NULL)
+ return NULL;
+ }
+
+ glamor_glyph_set_private (glyph, priv);
+ 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);
+
+ *out_x = priv->x;
+ *out_y = priv->y;
+ return cache->picture;
+}
+
+static glamor_glyph_cache_result_t
+glamor_buffer_glyph (ScreenPtr screen,
+ glamor_glyph_buffer_t * buffer,
+ GlyphPtr glyph, int x_glyph, int y_glyph)
+{
+ glamor_screen_private *glamor_screen = glamor_get_screen_private (screen);
+ unsigned int format = (GlyphPicture (glyph)[screen->myNum])->format;
+ glamor_composite_rect_t *rect;
+ PicturePtr source;
+ struct glamor_glyph *priv;
+ int x, y;
+ PicturePtr glyph_picture = GlyphPicture (glyph)[screen->myNum];
+ glamor_glyph_cache_t *cache;
+
+ if (PICT_FORMAT_BPP (format) == 1)
+ format = PICT_a8;
+
+ cache = &glamor_screen->glyphCaches[PICT_FORMAT_RGB (glyph_picture->format) != 0];
+
+ if (buffer->source && buffer->source != cache->picture)
+ return GLAMOR_GLYPH_NEED_FLUSH;
+
+ if (buffer->count == GLYPH_BUFFER_SIZE)
+ return GLAMOR_GLYPH_NEED_FLUSH;
+
+ priv = glamor_glyph_get_private (glyph);
+
+ if (priv)
+ {
+ rect = &buffer->rects[buffer->count++];
+ rect->x_src = priv->x;
+ rect->y_src = priv->y;
+ if (buffer->source == NULL) buffer->source = priv->cache->picture;
+ }
+ else
+ {
+ source = glamor_glyph_cache (screen, glyph, &x, &y);
+ if (source != NULL)
+ {
+ rect = &buffer->rects[buffer->count++];
+ rect->x_src = x;
+ rect->y_src = y;
+ if (buffer->source == NULL) buffer->source = source;
+ }
+ else
+ {
+ source = GlyphPicture (glyph)[screen->myNum];
+ if (buffer->source && buffer->source != source)
+ return GLAMOR_GLYPH_NEED_FLUSH;
+ buffer->source = source;
+
+ rect = &buffer->rects[buffer->count++];
+ rect->x_src = 0;
+ rect->y_src = 0;
+ }
+ }
+
+ rect->x_dst = x_glyph - glyph->info.x;
+ rect->y_dst = y_glyph - glyph->info.y;
+ rect->width = glyph->info.width;
+ rect->height = glyph->info.height;
+
+ /* Couldn't find the glyph in the cache, use the glyph picture directly */
+
+ return GLAMOR_GLYPH_SUCCESS;
+}
+
+
+static void
+glamor_glyphs_flush_mask (PicturePtr mask, glamor_glyph_buffer_t * buffer)
+{
+#ifdef RENDER
+ glamor_composite_rects (PictOpAdd, buffer->source, NULL, mask,
+ buffer->count, buffer->rects);
+#endif
+ buffer->count = 0;
+ buffer->source = NULL;
+}
+
+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)
+{
+ 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 };
+ CARD32 component_alpha;
+ glamor_glyph_buffer_t buffer;
+
+ GCPtr gc;
+
+ glamor_glyph_extents (nlist, list, glyphs, &extents);
+
+ if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
+ return;
+ 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;
+ }
+
+ mask_pixmap = screen->CreatePixmap (screen, width, height,
+ mask_format->depth,
+ CREATE_PIXMAP_USAGE_SCRATCH);
+ if (!mask_pixmap)
+ return;
+ component_alpha = NeedsComponent (mask_format->format);
+ mask = CreatePicture (0, &mask_pixmap->drawable,
+ mask_format, CPComponentAlpha,
+ &component_alpha, serverClient, &error);
+ if (!mask)
+ {
+ screen->DestroyPixmap (mask_pixmap);
+ return;
+ }
+ gc = GetScratchGC (mask_pixmap->drawable.depth, screen);
+ ValidateGC (&mask_pixmap->drawable, gc);
+ glamor_fill (&mask_pixmap->drawable, gc, 0, 0, width, height);
+ FreeScratchGC (gc);
+ x = -extents.x1;
+ y = -extents.y1;
+
+ buffer.count = 0;
+ buffer.source = NULL;
+ while (nlist--)
+ {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ while (n--)
+ {
+ glyph = *glyphs++;
+
+ if (glyph->info.width > 0 && glyph->info.height > 0 &&
+ glamor_buffer_glyph (screen, &buffer, glyph, x,
+ y) == GLAMOR_GLYPH_NEED_FLUSH)
+ {
+
+ glamor_glyphs_flush_mask (mask, &buffer);
+
+ glamor_buffer_glyph (screen, &buffer, glyph, x, y);
+ }
+
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ list++;
+ }
+
+ if (buffer.count)
+ glamor_glyphs_flush_mask (mask, &buffer);
+
+ x = extents.x1;
+ y = extents.y1;
+ CompositePicture (op,
+ src,
+ mask,
+ dst,
+ x_src + x - x_dst,
+ y_src + y - y_dst, 0, 0, x, y, width, height);
+ FreePicture (mask, 0);
+ screen->DestroyPixmap (mask_pixmap);
+}
+
+static void
+glamor_glyphs_flush_dst (CARD8 op,
+ PicturePtr src,
+ PicturePtr dst,
+ glamor_glyph_buffer_t * buffer,
+ INT16 x_src, INT16 y_src, INT16 x_dst, INT16 y_dst)
+{
+ int i;
+ glamor_composite_rect_t *rect = &buffer->rects[0];
+ for (i = 0; i < buffer->count; i++, rect++)
+ {
+ rect->x_mask = rect->x_src;
+ rect->y_mask = rect->y_src;
+ rect->x_src = x_src + rect->x_dst - x_dst;
+ rect->y_src = y_src + rect->y_dst - y_dst;
+ }
+
+ glamor_composite_rects (op, src, buffer->source, dst,
+ buffer->count, &buffer->rects[0]);
+
+ buffer->count = 0;
+ buffer->source = NULL;
+}
+
+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;
+ glamor_glyph_buffer_t buffer;
+
+ buffer.count = 0;
+ buffer.source = NULL;
+ while (nlist--)
+ {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ while (n--)
+ {
+ glyph = *glyphs++;
+
+ if (glyph->info.width > 0 && glyph->info.height > 0 &&
+ glamor_buffer_glyph (screen, &buffer, glyph, x,
+ y) == GLAMOR_GLYPH_NEED_FLUSH)
+ {
+ glamor_glyphs_flush_dst (op, src, dst,
+ &buffer, x_src, y_src, x_dst, y_dst);
+ glamor_buffer_glyph (screen, &buffer, glyph, x, y);
+ }
+
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ list++;
+ }
+
+ if (buffer.count)
+ glamor_glyphs_flush_dst (op, src, dst, &buffer,
+ x_src, y_src, x_dst, y_dst);
+}
+
+void
+glamor_glyphs (CARD8 op,
+ PicturePtr src,
+ PicturePtr dst,
+ PictFormatPtr mask_format,
+ INT16 x_src,
+ INT16 y_src, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
+{
+ /* If we don't have a mask format but all the glyphs have the same format
+ * and don't intersect, use the glyph format as mask format for the full
+ * benefits of the glyph cache.
+ */
+ if (!mask_format)
+ {
+ Bool same_format = TRUE;
+ int i;
+
+ mask_format = list[0].format;
+
+ for (i = 0; i < nlist; i++)
+ {
+ if (mask_format->format != list[i].format->format)
+ {
+ same_format = FALSE;
+ break;
+ }
+ }
+
+ if (!same_format || (mask_format->depth != 1 &&
+ glamor_glyphs_intersect (nlist, list, glyphs)))
+ {
+ mask_format = NULL;
+ }
+ }
+
+ if (mask_format)
+ glamor_glyphs_via_mask (op, src, dst, mask_format,
+ x_src, y_src, nlist, list, glyphs);
+ else
+ glamor_glyphs_to_dst (op, src, dst, x_src, y_src, nlist, list, glyphs);
+}
diff --git a/glamor/glamor_picture.c b/glamor/glamor_picture.c
new file mode 100644
index 000000000..c94c07cd7
--- /dev/null
+++ b/glamor/glamor_picture.c
@@ -0,0 +1,93 @@
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "glamor_priv.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;
+ glamor_pixmap_private *pixmap_priv;
+ assert(picture->pDrawable);
+ pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ assert(GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv) == 1);
+ 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)
+{
+ if (!picture || !picture->pDrawable)
+ return;
+
+ glamor_finish_access(picture->pDrawable);
+}
+
+/*
+ * We should already has 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;
+ glamor_screen_private *glamor_priv;
+
+ if (!picture || !picture->pDrawable)
+ return 0;
+
+ glamor_priv = glamor_get_screen_private(picture->pDrawable->pScreen);
+ pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ assert(pixmap_priv);
+
+ pixmap_priv->is_picture = 1;
+ pixmap_priv->pict_format = picture->format;
+ return glamor_priv->saved_create_picture(picture);
+}
+
+void
+glamor_destroy_picture(PicturePtr picture)
+{
+ PixmapPtr pixmap;
+ glamor_pixmap_private *pixmap_priv;
+ glamor_screen_private *glamor_priv;
+
+ if (!picture || !picture->pDrawable)
+ return;
+
+ glamor_priv = glamor_get_screen_private(picture->pDrawable->pScreen);
+ pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ assert(pixmap_priv);
+
+ pixmap_priv->is_picture = 0;
+ pixmap_priv->pict_format = 0;
+ glamor_priv->saved_destroy_picture(picture);
+}
+
+void glamor_picture_format_fixup(PicturePtr picture, glamor_pixmap_private *pixmap_priv)
+{
+ pixmap_priv->pict_format = picture->format;
+}
+
diff --git a/glamor/glamor_pixmap.c b/glamor/glamor_pixmap.c
new file mode 100644
index 000000000..28ad57a4d
--- /dev/null
+++ b/glamor/glamor_pixmap.c
@@ -0,0 +1,752 @@
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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;
+}
+
+
+static void
+_glamor_pixmap_validate_filling(glamor_screen_private *glamor_priv,
+ glamor_pixmap_private *pixmap_priv)
+{
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+ GLfloat vertices[8];
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, GL_FALSE,
+ 2 * sizeof(float), vertices);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glUseProgram(glamor_priv->solid_prog);
+ dispatch->glUniform4fv(glamor_priv->solid_color_uniform_location,
+ 1, pixmap_priv->pending_op.fill.color4fv);
+ vertices[0] = -1;
+ vertices[1] = -1;
+ vertices[2] = 1;
+ vertices[3] = -1;
+ vertices[4] = 1;
+ vertices[5] = 1;
+ vertices[6] = -1;
+ vertices[7] = 1;
+ dispatch->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glUseProgram(0);
+ pixmap_priv->pending_op.type = GLAMOR_PENDING_NONE;
+}
+
+
+glamor_pixmap_validate_function_t pixmap_validate_funcs[] = {
+ NULL,
+ _glamor_pixmap_validate_filling
+};
+
+void
+glamor_pixmap_init(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_priv->pixmap_validate_funcs = pixmap_validate_funcs;
+}
+
+void
+glamor_validate_pixmap(PixmapPtr pixmap)
+{
+ glamor_pixmap_validate_function_t validate_op;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(pixmap->drawable.pScreen);
+ glamor_pixmap_private *pixmap_priv =
+ glamor_get_pixmap_private(pixmap);
+
+ validate_op = glamor_priv->pixmap_validate_funcs[pixmap_priv->pending_op.type];
+ if (validate_op) {
+ (*validate_op)(glamor_priv, pixmap_priv);
+ }
+}
+
+void
+glamor_set_destination_pixmap_priv_nc(glamor_pixmap_private *pixmap_priv)
+{
+ glamor_gl_dispatch *dispatch = &pixmap_priv->glamor_priv->dispatch;
+ dispatch->glBindFramebuffer(GL_FRAMEBUFFER, pixmap_priv->fb);
+#ifndef GLAMOR_GLES2
+ dispatch->glMatrixMode(GL_PROJECTION);
+ dispatch->glLoadIdentity();
+ dispatch->glMatrixMode(GL_MODELVIEW);
+ dispatch->glLoadIdentity();
+#endif
+ dispatch->glViewport(0, 0,
+ pixmap_priv->container->drawable.width,
+ pixmap_priv->container->drawable.height);
+
+}
+
+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;
+}
+
+
+
+void
+glamor_set_alu(struct glamor_gl_dispatch *dispatch, unsigned char alu)
+{
+#ifndef GLAMOR_GLES2
+ if (alu == GXcopy) {
+ dispatch->glDisable(GL_COLOR_LOGIC_OP);
+ return;
+ }
+ 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:
+ FatalError("unknown logic op\n");
+ }
+#else
+ if (alu != GXcopy)
+ ErrorF("unsupported alu %x \n", alu);
+#endif
+}
+
+
+
+
+/**
+ * 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, GLenum format, GLenum type, GLuint tex)
+{
+ 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 = &glamor_priv->dispatch;
+ unsigned int stride, row_length;
+ void *texels;
+ GLenum iformat;
+
+ switch (pixmap->drawable.depth) {
+#if 0
+ case 8:
+ iformat = GL_ALPHA;
+ break;
+#endif
+ case 24:
+ iformat = GL_RGB;
+ break;
+ default:
+ iformat = GL_RGBA;
+ break;
+ }
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) {
+ iformat = format;
+ }
+
+ stride = pixmap->devKind;
+ row_length = (stride * 8) / pixmap->drawable.bitsPerPixel;
+
+ dispatch->glBindTexture(GL_TEXTURE_2D, tex);
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
+ dispatch->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ dispatch->glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
+ }
+ else {
+ dispatch->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ }
+
+ if (pixmap_priv->pbo && pixmap_priv->pbo_valid) {
+ texels = NULL;
+ dispatch->glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixmap_priv->pbo);
+ }
+ else
+ texels = pixmap->devPrivate.ptr;
+
+ dispatch->glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ iformat,
+ pixmap->drawable.width,
+ pixmap->drawable.height, 0,
+ format, type, texels);
+}
+
+
+/*
+ * Load texture from the pixmap's data pointer and then
+ * draw the texture to the fbo, and flip the y axis.
+ * */
+
+static void
+_glamor_upload_pixmap_to_texture(PixmapPtr pixmap, GLenum format,
+ GLenum type, int no_alpha, int no_revert,
+ int flip)
+{
+
+ 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 = &glamor_priv->dispatch;
+ static float vertices[8] = {-1, -1,
+ 1, -1,
+ 1, 1,
+ -1, 1};
+ 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;
+
+ GLuint tex;
+ int need_flip;
+ need_flip = (flip && !glamor_priv->yInverted);
+
+ /* Try fast path firstly, upload the pixmap to the texture attached
+ * to the fbo directly. */
+ if (no_alpha == 0 && no_revert == 1 && !need_flip) {
+ __glamor_upload_pixmap_to_texture(pixmap, format, type, pixmap_priv->tex);
+ return;
+ }
+
+
+ if (need_flip)
+ ptexcoords = texcoords;
+ else
+ ptexcoords = texcoords_inv;
+
+ /* Slow path, we need to flip y or wire alpha to 1. */
+ 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);
+ dispatch->glGenTextures(1, &tex);
+
+ __glamor_upload_pixmap_to_texture(pixmap, format, type, tex);
+ 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_no_revert[no_alpha], no_revert);
+ dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha],0);
+
+ 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);
+}
+
+void
+glamor_pixmap_ensure_fb(PixmapPtr pixmap)
+{
+ int status;
+ glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
+ glamor_gl_dispatch *dispatch = &pixmap_priv->glamor_priv->dispatch;
+
+ if (pixmap_priv->fb == 0)
+ dispatch->glGenFramebuffers(1, &pixmap_priv->fb);
+ assert(pixmap_priv->tex != 0);
+ dispatch->glBindFramebuffer(GL_FRAMEBUFFER, pixmap_priv->fb);
+ dispatch->glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ pixmap_priv->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;
+ }
+
+ LogMessageVerb(X_INFO, 0,
+ "destination is framebuffer incomplete: %s [%#x]\n",
+ str, status);
+ assert(0);
+ }
+}
+
+/*
+ * 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, int no_alpha, int no_revert)
+{
+ int need_fbo;
+ 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 = &glamor_priv->dispatch;
+
+ if (!glamor_check_fbo_size(glamor_priv, pixmap->drawable.width , pixmap->drawable.height)
+ || !glamor_check_fbo_depth(pixmap->drawable.depth)) {
+ glamor_fallback("upload failed reason: bad size or depth %d x %d @depth %d \n",
+ pixmap->drawable.width, pixmap->drawable.height, pixmap->drawable.depth);
+ return -1;
+ }
+
+ if (GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ return 0;
+
+ if (no_alpha != 0 || no_revert == 0 || !glamor_priv->yInverted)
+ need_fbo = 1;
+ else
+ need_fbo = 0;
+
+ if (pixmap_priv->tex == 0)
+ dispatch->glGenTextures(1, &pixmap_priv->tex);
+
+ if (need_fbo) {
+ dispatch->glBindTexture(GL_TEXTURE_2D, pixmap_priv->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, GL_RGBA, pixmap->drawable.width,
+ pixmap->drawable.height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glamor_pixmap_ensure_fb(pixmap);
+ }
+
+ return 0;
+}
+
+enum glamor_pixmap_status
+glamor_upload_pixmap_to_texture(PixmapPtr pixmap)
+{
+ GLenum format, type;
+ int no_alpha, no_revert;
+
+ if (glamor_get_tex_format_type_from_pixmap(pixmap,
+ &format,
+ &type,
+ &no_alpha,
+ &no_revert)) {
+ glamor_fallback("Unknown pixmap depth %d.\n", pixmap->drawable.depth);
+ return GLAMOR_UPLOAD_FAILED;
+ }
+ if (glamor_pixmap_upload_prepare(pixmap, no_alpha, no_revert))
+ return GLAMOR_UPLOAD_FAILED;
+ glamor_debug_output(GLAMOR_DEBUG_TEXTURE_DYNAMIC_UPLOAD,
+ "Uploading pixmap %p %dx%d depth%d.\n",
+ pixmap,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ pixmap->drawable.depth);
+ _glamor_upload_pixmap_to_texture(pixmap, format, type, no_alpha, no_revert, 1);
+ return GLAMOR_UPLOAD_DONE;
+}
+
+#if 0
+enum glamor_pixmap_status
+glamor_upload_pixmap_to_texure_from_data(PixmapPtr pixmap, void *data)
+{
+ enum glamor_pixmap_status upload_status;
+ glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ assert(pixmap_priv->pbo_valid == 0);
+ assert(pixmap->devPrivate.ptr == NULL);
+ pixmap->devPrivate.ptr = data;
+ upload_status = glamor_upload_pixmap_to_texture(pixmap);
+ pixmap->devPrivate.ptr = NULL;
+ return upload_status;
+}
+#endif
+
+void
+glamor_restore_pixmap_to_texture(PixmapPtr pixmap)
+{
+ GLenum format, type;
+ int no_alpha, no_revert;
+
+ if (glamor_get_tex_format_type_from_pixmap(pixmap,
+ &format,
+ &type,
+ &no_alpha,
+ &no_revert)) {
+ ErrorF("Unknown pixmap depth %d.\n", pixmap->drawable.depth);
+ assert(0);
+ }
+
+ in_restore = 1;
+ _glamor_upload_pixmap_to_texture(pixmap, format, type, no_alpha, no_revert, 1);
+ in_restore = 0;
+}
+
+/*
+ * 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.
+ * */
+
+PixmapPtr
+glamor_es2_pixmap_read_prepare(PixmapPtr source, GLenum *format,
+ GLenum *type, int no_alpha, int no_revert)
+{
+ glamor_pixmap_private *source_priv;
+ glamor_screen_private *glamor_priv;
+ ScreenPtr screen;
+ PixmapPtr temp_pixmap;
+ glamor_pixmap_private *temp_pixmap_priv;
+ glamor_gl_dispatch *dispatch;
+ static float vertices[8] = {-1, -1,
+ 1, -1,
+ 1, 1,
+ -1, 1};
+ static float texcoords[8] = {0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1};
+
+ int swap_rb = 0;
+
+ screen = source->drawable.pScreen;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ source_priv = glamor_get_pixmap_private(source);
+ dispatch = &glamor_priv->dispatch;
+ if (*format == GL_BGRA) {
+ *format = GL_RGBA;
+ swap_rb = 1;
+ }
+
+
+ temp_pixmap = (*screen->CreatePixmap)(screen,
+ source->drawable.width,
+ source->drawable.height,
+ source->drawable.depth,
+ 0);
+
+ temp_pixmap_priv = glamor_get_pixmap_private(temp_pixmap);
+
+ dispatch->glBindTexture(GL_TEXTURE_2D, temp_pixmap_priv->tex);
+ dispatch->glTexImage2D(GL_TEXTURE_2D, 0, *format, source->drawable.width,
+ source->drawable.height, 0,
+ *format, *type, NULL);
+
+ 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),
+ texcoords);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glBindTexture(GL_TEXTURE_2D, source_priv->tex);
+
+ glamor_set_destination_pixmap_priv_nc(temp_pixmap_priv);
+
+ dispatch->glUseProgram(glamor_priv->finish_access_prog[no_alpha]);
+ dispatch->glUniform1i(glamor_priv->finish_access_no_revert[no_alpha], no_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);
+ return temp_pixmap;
+}
+
+
+/**
+ * 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, row_length, y;
+ GLenum format, type, gl_access, gl_usage;
+ int no_alpha, no_revert;
+ uint8_t *data = NULL, *read;
+ PixmapPtr temp_pixmap = NULL;
+ ScreenPtr screen;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(pixmap->drawable.pScreen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+
+ screen = pixmap->drawable.pScreen;
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
+ return TRUE;
+ if (glamor_get_tex_format_type_from_pixmap(pixmap,
+ &format,
+ &type,
+ &no_alpha,
+ &no_revert)) {
+ ErrorF("Unknown pixmap depth %d.\n", pixmap->drawable.depth);
+ assert(0); // Should never happen.
+ return FALSE;
+ }
+
+ pixmap_priv->access_mode = access;
+ 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;
+
+ glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+ /* XXX we may don't need to validate it on GPU here,
+ * we can just validate it on CPU. */
+ glamor_validate_pixmap(pixmap);
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
+ && ((format != GL_RGBA && format != GL_RGB && format != GL_ALPHA) || no_revert != 1)) {
+
+ temp_pixmap = glamor_es2_pixmap_read_prepare(pixmap, &format, &type, no_alpha, no_revert);
+
+ }
+ switch (access) {
+ case GLAMOR_ACCESS_RO:
+ gl_access = GL_READ_ONLY;
+ gl_usage = GL_STREAM_READ;
+ break;
+ case GLAMOR_ACCESS_WO:
+ data = malloc(stride * pixmap->drawable.height);
+ goto done;
+ break;
+ 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);
+ }
+ if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) {
+ data = malloc(stride * pixmap->drawable.height);
+ }
+ row_length = (stride * 8) / pixmap->drawable.bitsPerPixel;
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
+ dispatch->glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ dispatch->glPixelStorei(GL_PACK_ROW_LENGTH, row_length);
+ }
+ else {
+ dispatch->glPixelStorei(GL_PACK_ALIGNMENT, 4);
+ // dispatch->glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+ }
+ 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) {
+ if (pixmap_priv->pbo == 0)
+ dispatch->glGenBuffers (1, &pixmap_priv->pbo);
+ dispatch->glBindBuffer (GL_PIXEL_PACK_BUFFER, pixmap_priv->pbo);
+ dispatch->glBufferData (GL_PIXEL_PACK_BUFFER,
+ stride * pixmap->drawable.height,
+ NULL, gl_usage);
+ dispatch->glReadPixels (0, 0,
+ row_length, pixmap->drawable.height,
+ format, type, 0);
+ data = dispatch->glMapBuffer (GL_PIXEL_PACK_BUFFER, gl_access);
+ pixmap_priv->pbo_valid = TRUE;
+
+ if (!glamor_priv->yInverted) {
+ assert(glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP);
+ dispatch->glPixelStorei(GL_PACK_INVERT_MESA, 0);
+ }
+ dispatch->glBindBuffer (GL_PIXEL_PACK_BUFFER, 0);
+
+ } else {
+ if (type == GL_UNSIGNED_SHORT_1_5_5_5_REV)
+ type = GL_UNSIGNED_SHORT_5_5_5_1;
+ dispatch->glReadPixels (0, 0,
+ pixmap->drawable.width, pixmap->drawable.height,
+ format, type, data);
+ }
+ } else {
+ data = malloc(stride * pixmap->drawable.height);
+ assert(data);
+ if (access != GLAMOR_ACCESS_WO) {
+ if (pixmap_priv->pbo == 0)
+ dispatch->glGenBuffers(1, &pixmap_priv->pbo);
+ dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, pixmap_priv->pbo);
+ dispatch->glBufferData(GL_PIXEL_PACK_BUFFER,
+ stride * pixmap->drawable.height,
+ NULL, GL_STREAM_READ);
+ dispatch->glReadPixels (0, 0, row_length, pixmap->drawable.height,
+ format, type, 0);
+ read = dispatch->glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
+
+ for (y = 0; y < pixmap->drawable.height; y++)
+ memcpy(data + y * stride,
+ read + (pixmap->drawable.height - y - 1) * stride, stride);
+ dispatch->glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
+ dispatch->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+ pixmap_priv->pbo_valid = FALSE;
+ dispatch->glDeleteBuffers(1, &pixmap_priv->pbo);
+ pixmap_priv->pbo = 0;
+ }
+ }
+
+ dispatch->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+done:
+ pixmap->devPrivate.ptr = data;
+
+ if (temp_pixmap) {
+ (*screen->DestroyPixmap)(temp_pixmap);
+ }
+
+ return TRUE;
+}
+
+
+
+static void
+_glamor_destroy_upload_pixmap(PixmapPtr pixmap)
+{
+ glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
+ glamor_gl_dispatch *dispatch = &pixmap_priv->glamor_priv->dispatch;
+
+ assert(pixmap_priv->gl_fbo == 0);
+ if (pixmap_priv->fb)
+ dispatch->glDeleteFramebuffers(1, &pixmap_priv->fb);
+ if (pixmap_priv->tex)
+ dispatch->glDeleteTextures(1, &pixmap_priv->tex);
+ if (pixmap_priv->pbo)
+ dispatch->glDeleteBuffers(1, &pixmap_priv->pbo);
+ pixmap_priv->fb = pixmap_priv->tex = pixmap_priv->pbo = 0;
+
+}
+
+void glamor_destroy_upload_pixmap(PixmapPtr pixmap)
+{
+ _glamor_destroy_upload_pixmap(pixmap);
+}
+
diff --git a/glamor/glamor_polyfillrect.c b/glamor/glamor_polyfillrect.c
new file mode 100644
index 000000000..3cc4b527d
--- /dev/null
+++ b/glamor/glamor_polyfillrect.c
@@ -0,0 +1,110 @@
+/*
+ * 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>
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "glamor_priv.h"
+
+/** @file glamor_fillspans.c
+ *
+ * GC PolyFillRect implementation, taken straight from fb_fill.c
+ */
+
+void
+glamor_poly_fill_rect(DrawablePtr drawable,
+ GCPtr gc,
+ int nrect,
+ xRectangle *prect)
+{
+ int fullX1, fullX2, fullY1, fullY2;
+ int xorg, yorg;
+ int n;
+ register BoxPtr pbox;
+ RegionPtr pClip = fbGetCompositeClip(gc);
+ if (gc->fillStyle != FillSolid && gc->fillStyle != FillTiled) {
+ goto fail;
+ }
+
+ 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;
+ prect++;
+
+ 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;
+ glamor_fill(drawable,
+ gc,
+ x1,
+ y1,
+ x2 - x1,
+ y2 - y1);
+ }
+ }
+ return;
+
+fail:
+ 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);
+ }
+}
diff --git a/glamor/glamor_polylines.c b/glamor/glamor_polylines.c
new file mode 100644
index 000000000..d93b60209
--- /dev/null
+++ b/glamor/glamor_polylines.c
@@ -0,0 +1,179 @@
+/*
+ * 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>
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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.
+ */
+void
+glamor_poly_lines(DrawablePtr drawable, GCPtr gc, int mode, int n,
+ DDXPointPtr points)
+{
+ xRectangle *rects;
+ int x1, x2, y1, y2;
+ int i;
+ int x_min = MAXSHORT;
+ int x_max = MINSHORT;
+ int y_min = MAXSHORT;
+ int y_max = MINSHORT;
+ DrawablePtr temp_dest;
+ PixmapPtr temp_pixmap;
+ GCPtr temp_gc = NULL;
+ /* 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 fail;
+ }
+ if (gc->lineStyle != LineSolid ||
+ gc->fillStyle != FillSolid) {
+ glamor_fallback("non-solid fill line style %d, fill style %d\n",
+ gc->lineStyle, gc->fillStyle);
+ 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;
+
+fail:
+ for(i = 0; i < n; i++)
+ {
+ if (x_min > points[i].x)
+ x_min = points[i].x;
+ if (x_max < points[i].x)
+ x_max = points[i].x;
+
+ if (y_min > points[i].y)
+ y_min = points[i].y;
+ if (y_max < points[i].y)
+ y_max = points[i].y;
+ }
+
+ temp_pixmap = drawable->pScreen->CreatePixmap(drawable->pScreen,
+ x_max - x_min + 1, y_max - y_min + 1,
+ drawable->depth,
+ 0);
+ if (temp_pixmap) {
+ temp_dest = &temp_pixmap->drawable;
+ temp_gc = GetScratchGC(temp_dest->depth, temp_dest->pScreen);
+ ValidateGC(temp_dest, temp_gc);
+ for(i = 0; i < n; i++)
+ {
+ points[i].x -= x_min;
+ points[i].y -= y_min;
+ }
+ (void)glamor_copy_area(drawable,
+ temp_dest,
+ temp_gc,
+ x_min, y_min,
+ x_max - x_min + 1, y_max - y_min + 1,
+ 0, 0);
+
+ }
+ else
+ temp_dest = drawable;
+
+ if (gc->lineWidth == 0) {
+ if (glamor_prepare_access(temp_dest, GLAMOR_ACCESS_RW)) {
+ if (glamor_prepare_access_gc(gc)) {
+ fbPolyLine(temp_dest, gc, mode, n, points);
+ glamor_finish_access_gc(gc);
+ }
+ glamor_finish_access(temp_dest);
+ }
+ }
+ else {
+ /* fb calls mi functions in the lineWidth != 0 case. */
+ fbPolyLine(drawable, gc, mode, n, points);
+ }
+ if (temp_dest != drawable) {
+ (void)glamor_copy_area(temp_dest,
+ drawable,
+ temp_gc,
+ 0, 0,
+ x_max - x_min + 1, y_max - y_min + 1,
+ x_min, y_min);
+ drawable->pScreen->DestroyPixmap(temp_pixmap);
+ for(i = 0; i < n; i++)
+ {
+ points[i].x += x_min;
+ points[i].y += y_min;
+ }
+
+ FreeScratchGC(temp_gc);
+ }
+}
diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h
new file mode 100644
index 000000000..5f82c7883
--- /dev/null
+++ b/glamor/glamor_priv.h
@@ -0,0 +1,569 @@
+/*
+ * 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_DIX_CONFIG_H
+#include <dix-config.h>
+#include <xorg-config.h>
+#endif
+
+
+#include "glamor.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"
+
+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;
+} glamor_composite_shader;
+
+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 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 glamor_screen_private;
+struct glamor_pixmap_private;
+typedef void (*glamor_pixmap_validate_function_t)(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_NUM_GLYPH_CACHES 4
+#define GLAMOR_NUM_GLYPH_CACHE_FORMATS 2
+
+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"
+
+typedef struct glamor_screen_private {
+ CloseScreenProcPtr saved_close_screen;
+ CreateGCProcPtr saved_create_gc;
+ CreatePixmapProcPtr saved_create_pixmap;
+ DestroyPixmapProcPtr saved_destroy_pixmap;
+ GetSpansProcPtr saved_get_spans;
+ GetImageProcPtr saved_get_image;
+ CompositeProcPtr saved_composite;
+ TrapezoidsProcPtr saved_trapezoids;
+ GlyphsProcPtr saved_glyphs;
+ ChangeWindowAttributesProcPtr saved_change_window_attributes;
+ CopyWindowProcPtr saved_copy_window;
+ BitmapToRegionProcPtr saved_bitmap_to_region;
+ TrianglesProcPtr saved_triangles;
+ CreatePictureProcPtr saved_create_picture;
+ DestroyPictureProcPtr saved_destroy_picture;
+ UnrealizeGlyphProcPtr saved_unrealize_glyph;
+
+ int yInverted;
+ int screen_fbo;
+ GLuint vbo;
+ int vbo_offset;
+ int vbo_size;
+ char *vb;
+ int vb_stride;
+ enum glamor_gl_flavor gl_flavor;
+ int has_pack_invert;
+ int has_fbo_blit;
+ int max_fbo_size;
+
+ /* glamor_finishaccess */
+ GLint finish_access_prog[2];
+ GLint finish_access_no_revert[2];
+ GLint finish_access_swap_rb[2];
+
+ /* glamor_solid */
+ GLint solid_prog;
+ GLint solid_color_uniform_location;
+
+ /* glamor_tile */
+ GLint tile_prog;
+
+ /* glamor_putimage */
+ GLint put_image_xybitmap_prog;
+ GLint put_image_xybitmap_fg_uniform_location;
+ GLint put_image_xybitmap_bg_uniform_location;
+
+ /* glamor_composite */
+ glamor_composite_shader composite_shader[SHADER_SOURCE_COUNT]
+ [SHADER_MASK_COUNT]
+ [SHADER_IN_COUNT];
+ Bool has_source_coords, has_mask_coords;
+ int render_nr_verts;
+ glamor_pixmap_validate_function_t *pixmap_validate_funcs;
+ glamor_glyph_cache_t glyph_caches[GLAMOR_NUM_GLYPH_CACHES];
+ char delayed_fallback_string[GLAMOR_DELAYED_STRING_MAX + 1];
+ int delayed_fallback_pending;
+
+ glamor_glyph_cache_t glyphCaches[GLAMOR_NUM_GLYPH_CACHE_FORMATS];
+ Bool glyph_cache_initialized;
+ struct glamor_gl_dispatch dispatch;
+} glamor_screen_private;
+
+typedef enum glamor_access {
+ GLAMOR_ACCESS_RO,
+ GLAMOR_ACCESS_RW,
+ GLAMOR_ACCESS_WO,
+} glamor_access_t;
+
+enum _glamor_pending_op_type{
+ GLAMOR_PENDING_NONE,
+ GLAMOR_PENDING_FILL
+};
+
+typedef struct _glamor_pending_fill {
+ unsigned int type;
+ GLfloat color4fv[4];
+ CARD32 colori;
+} glamor_pending_fill;
+
+typedef union _glamor_pending_op {
+ unsigned int type;
+ glamor_pending_fill fill;
+} glamor_pending_op;
+
+/*
+ * glamor_pixmap_private - glamor pixmap's private structure.
+ * @gl_fbo: The pixmap is attached to a fbo originally.
+ * @gl_tex: The pixmap is in a gl texture originally.
+ * @pbo_valid: The pbo has a valid copy of the pixmap's data.
+ * @is_picture: The drawable is attached to a picture.
+ * @tex: attached texture.
+ * @fb: attached fbo.
+ * @pbo: attached pbo.
+ * @access_mode: access mode during the prepare/finish pair.
+ * @pict_format: the corresponding picture's format.
+ * #pending_op: currently only support pending filling.
+ * @container: The corresponding pixmap's pointer.
+ **/
+
+typedef struct glamor_pixmap_private {
+ unsigned char gl_fbo:1;
+ unsigned char gl_tex:1;
+ unsigned char pbo_valid:1;
+ unsigned char is_picture:1;
+ GLuint tex;
+ GLuint fb;
+ GLuint pbo;
+ glamor_access_t access_mode;
+ PictFormatShort pict_format;
+ glamor_pending_op pending_op;
+ PixmapPtr container;
+ glamor_screen_private *glamor_priv;
+} 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 glamor_pixmap_private *
+glamor_get_pixmap_private(PixmapPtr pixmap)
+{
+ return dixLookupPrivate(&pixmap->devPrivates, glamor_pixmap_private_key);
+}
+
+
+/**
+ * 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_close_screen(int idx, ScreenPtr screen);
+
+
+/* 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);
+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);
+const Bool glamor_get_drawable_location(const DrawablePtr drawable);
+void glamor_get_drawable_deltas(DrawablePtr drawable, PixmapPtr pixmap,
+ int *x, int *y);
+Bool glamor_create_gc(GCPtr gc);
+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);
+
+/* 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);
+
+
+PixmapPtr
+glamor_es2_pixmap_read_prepare(PixmapPtr source, GLenum *format,
+ GLenum *type, int no_alpha, int no_revert);
+
+void 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(char *extension);
+int glamor_gl_get_version(void);
+
+#define GLAMOR_GL_VERSION_ENCODE(major, minor) ( \
+ ((major) * 256) \
+ + ((minor) * 1))
+
+
+
+
+/* glamor_fill.c */
+void glamor_fill(DrawablePtr drawable,
+ GCPtr gc,
+ int x,
+ int y,
+ int width,
+ int height);
+Bool glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height,
+ unsigned char alu, unsigned long planemask,
+ unsigned long fg_pixel);
+void glamor_solid_fail_region(PixmapPtr pixmap,
+ int x, int y, int width, int height);
+
+/* 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);
+
+/* 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);
+
+void
+glamor_glyph_unrealize (ScreenPtr screen, GlyphPtr glyph);
+/* 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);
+
+/* glamor_render.c */
+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_trapezoids(CARD8 op,
+ PicturePtr src, PicturePtr dst,
+ PictFormatPtr mask_format, INT16 x_src, INT16 y_src,
+ int ntrap, xTrapezoid *traps);
+void glamor_init_composite_shaders(ScreenPtr screen);
+void glamor_composite_rects(CARD8 op,
+ PicturePtr src, PicturePtr mask, PicturePtr dst,
+ int nrect, glamor_composite_rect_t *rects);
+
+/* 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);
+
+/* 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);
+/**
+ * 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);
+
+/**
+ * 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);
+/**
+ * Ensure to have a fbo attached to the pixmap.
+ * If the pixmap already has one fbo then do nothing.
+ * Otherwise, it will generate a new fbo, and bind
+ * the pixmap's texture to the fbo.
+ * The pixmap must has a valid texture before call this
+ * API, othersie, it will trigger a assert.
+ */
+void
+glamor_pixmap_ensure_fb(PixmapPtr pixmap);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * Destroy all the resources allocated on the uploading
+ * phase, includs the tex and fbo.
+ **/
+void
+glamor_destroy_upload_pixmap(PixmapPtr pixmap);
+
+void
+glamor_validate_pixmap(PixmapPtr pixmap);
+
+int
+glamor_create_picture(PicturePtr picture);
+
+Bool
+glamor_prepare_access_picture(PicturePtr picture, glamor_access_t access);
+
+void
+glamor_finish_access_picture(PicturePtr picture);
+
+void
+glamor_destroy_picture(PicturePtr picture);
+
+enum glamor_pixmap_status
+glamor_upload_picture_to_texture(PicturePtr picture);
+
+void
+glamor_picture_format_fixup(PicturePtr picture, glamor_pixmap_private *pixmap_priv);
+
+#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_DELAYED_FILLING
+
+
+
+#endif /* GLAMOR_PRIV_H */
diff --git a/glamor/glamor_putimage.c b/glamor/glamor_putimage.c
new file mode 100644
index 000000000..cdcde5e7e
--- /dev/null
+++ b/glamor/glamor_putimage.c
@@ -0,0 +1,417 @@
+/*
+ * 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>
+ *
+ */
+
+
+/** @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);
+ dispatch->glEnable(GL_TEXTURE_2D);
+
+ /* 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);
+ }
+}
+#endif
+
+
+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_screen_private *glamor_priv =
+ glamor_get_screen_private(drawable->pScreen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+ PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
+ glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
+ GLenum type, format, iformat;
+ RegionPtr clip;
+ BoxPtr pbox;
+ int nbox;
+ int src_stride = PixmapBytePad(w, drawable->depth);
+ int x_off, y_off;
+ float vertices[8], texcoords[8];
+ GLfloat xscale, yscale, txscale, tyscale;
+ GLuint tex;
+ int no_alpha, no_revert;
+ if (image_format == XYBitmap) {
+ assert(depth == 1);
+ goto fail;
+ return;
+ }
+
+ 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;
+ }
+ glamor_set_alu(dispatch, gc->alu);
+
+ if (glamor_get_tex_format_type_from_pixmap(pixmap,
+ &format,
+ &type,
+ &no_alpha,
+ &no_revert
+ )) {
+ glamor_fallback("unknown depth. %d \n",
+ drawable->depth);
+ goto fail;
+ }
+
+ /* XXX consider to reuse a function to do the following work. */
+ glamor_set_destination_pixmap_priv_nc(pixmap_priv);
+ glamor_validate_pixmap(pixmap);
+ 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),
+ texcoords);
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
+ dispatch->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ dispatch->glPixelStorei(GL_UNPACK_ROW_LENGTH, src_stride * 8 /
+ pixmap->drawable.bitsPerPixel);
+ }
+ else {
+ dispatch->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+// dispatch->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ }
+
+ dispatch->glGenTextures(1, &tex);
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glBindTexture(GL_TEXTURE_2D, tex);
+ if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) {
+ iformat = format;
+ }
+ else {
+ iformat = GL_RGBA;
+ }
+
+ dispatch->glTexImage2D(GL_TEXTURE_2D, 0, iformat,
+ w, h, 0,
+ format, type, bits);
+
+ 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_no_revert[no_alpha], no_revert);
+ dispatch->glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha], 0);
+
+ x += drawable->x;
+ y += drawable->y;
+
+ glamor_get_drawable_deltas(drawable, pixmap, &x_off, &y_off);
+ clip = fbGetCompositeClip(gc);
+
+ txscale = 1.0/w;
+ tyscale = 1.0/h;
+ pixmap_priv_get_scale(pixmap_priv, &xscale, &yscale);
+
+ for (nbox = REGION_NUM_RECTS(clip),
+ pbox = REGION_RECTS(clip);
+ nbox--;
+ pbox++)
+ {
+ int x1 = x;
+ int y1 = y;
+ int x2 = x + w;
+ int y2 = y + h;
+
+ if (x1 < pbox->x1)
+ x1 = pbox->x1;
+ if (y1 < pbox->y1)
+ y1 = pbox->y1;
+ if (x2 > pbox->x2)
+ x2 = pbox->x2;
+ if (y2 > pbox->y2)
+ y2 = pbox->y2;
+ if (x1 >= x2 || y1 >= y2)
+ continue;
+
+ glamor_set_normalize_tcoords( txscale, tyscale,
+ x1 - x, y1 - y,
+ x2 - x, y2 - y,
+ 1,
+ texcoords);
+
+ glamor_set_normalize_vcoords( xscale, yscale,
+ x1 + x_off, y1 + y_off,
+ x2 + x_off, y2 + y_off,
+ glamor_priv->yInverted,
+ vertices);
+
+ 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);
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
+ dispatch->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glamor_set_alu(dispatch, GXcopy);
+ glamor_set_planemask(pixmap, ~0);
+ return;
+
+fail:
+ glamor_set_planemask(pixmap, ~0);
+ glamor_fallback("to %p (%c)\n",
+ drawable, glamor_get_drawable_location(drawable));
+ if (glamor_prepare_access(&pixmap->drawable, GLAMOR_ACCESS_RW)) {
+ fbPutImage(&pixmap->drawable, gc, depth, x, y, w, h, left_pad, image_format,
+ bits);
+ glamor_finish_access(&pixmap->drawable);
+ }
+}
diff --git a/glamor/glamor_render.c b/glamor/glamor_render.c
new file mode 100644
index 000000000..d649c9813
--- /dev/null
+++ b/glamor/glamor_render.c
@@ -0,0 +1,1446 @@
+/*
+ * 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>
+ *
+ */
+
+/** @file glamor_render.c
+ *
+ * Render acceleration implementation
+ */
+
+#include "glamor_priv.h"
+
+#ifdef RENDER
+#include "mipict.h"
+#include "fbpict.h"
+
+//#include "glu3/glu3.h"
+
+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;
+};
+
+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},
+};
+
+static GLuint
+glamor_create_composite_fs(glamor_gl_dispatch *dispatch, struct shader_key *key)
+{
+ 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"
+ "vec4 get_source()\n"
+ "{\n"
+ " return texture2D(source_sampler, source_texture);\n"
+ "}\n";
+ const char *source_pixmap_fetch =
+ GLAMOR_DEFAULT_PRECISION
+ "varying vec2 source_texture;\n"
+ "uniform sampler2D source_sampler;\n"
+ "vec4 get_source()\n"
+ "{\n"
+ " return vec4(texture2D(source_sampler, source_texture).rgb, 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"
+ "vec4 get_mask()\n"
+ "{\n"
+ " return texture2D(mask_sampler, mask_texture);\n"
+ "}\n";
+ const char *mask_pixmap_fetch =
+ GLAMOR_DEFAULT_PRECISION
+ "varying vec2 mask_texture;\n"
+ "uniform sampler2D mask_sampler;\n"
+ "vec4 get_mask()\n"
+ "{\n"
+ " return vec4(texture2D(mask_sampler, mask_texture).rgb, 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",
+ 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 = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch = &glamor->dispatch;
+
+ vs = glamor_create_composite_vs(dispatch, key);
+ if (vs == 0)
+ return;
+ fs = glamor_create_composite_fs(dispatch, key);
+ if (fs == 0)
+ return;
+
+ 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);
+ }
+
+ 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);
+ }
+ }
+}
+
+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;
+}
+#define GLAMOR_COMPOSITE_VBO_SIZE 8192
+
+static void
+glamor_reset_composite_vbo(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_priv->vbo_offset = 0;
+ glamor_priv->vbo_size = GLAMOR_COMPOSITE_VBO_SIZE;
+ glamor_priv->render_nr_verts = 0;
+}
+
+
+void
+glamor_init_composite_shaders(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_priv->vb = malloc(GLAMOR_COMPOSITE_VBO_SIZE);
+ assert(glamor_priv->vb != NULL);
+ glamor_reset_composite_vbo(screen);
+}
+
+static Bool
+glamor_set_composite_op(ScreenPtr screen,
+ CARD8 op, PicturePtr dest, PicturePtr mask)
+{
+ GLenum source_blend, dest_blend;
+ struct blendinfo *op_info;
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+
+ 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 (source_blend != GL_ZERO) {
+ glamor_fallback("Dual-source composite blending not supported\n");
+ return GL_FALSE;
+ }
+ 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;
+ }
+
+ if (source_blend == GL_ONE && dest_blend == GL_ZERO) {
+ dispatch->glDisable(GL_BLEND);
+ } else {
+ dispatch->glEnable(GL_BLEND);
+ dispatch->glBlendFunc(source_blend, dest_blend);
+ }
+ return TRUE;
+}
+
+static void
+glamor_set_composite_texture(ScreenPtr screen, int unit, PicturePtr picture,
+ glamor_pixmap_private *pixmap_priv)
+{
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+ dispatch->glActiveTexture(GL_TEXTURE0 + unit);
+ dispatch->glBindTexture(GL_TEXTURE_2D, pixmap_priv->tex);
+ 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);
+#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) {
+ 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 PictFilterBilinear:
+ default:
+ 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
+}
+
+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,
+ CARD16 width,
+ CARD16 height)
+{
+ RegionRec region;
+
+ 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 (!miComputeCompositeRegion(&region,
+ source, NULL, dest,
+ x_source, y_source,
+ 0, 0,
+ x_dest, y_dest,
+ width, height))
+ return TRUE;
+
+ glamor_copy_n_to_n(source->pDrawable,
+ dest->pDrawable, NULL,
+ REGION_RECTS(&region),
+ REGION_NUM_RECTS(&region),
+ x_source - x_dest, y_source - y_dest,
+ FALSE, FALSE, 0, NULL);
+ REGION_UNINIT(dest->pDrawable->pScreen,
+ &region);
+ return TRUE;
+}
+
+static void
+glamor_setup_composite_vbo(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+
+ 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);
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
+
+ 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);
+ }
+}
+
+static 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 = &glamor_priv->dispatch;
+ if (!glamor_priv->render_nr_verts)
+ return;
+ dispatch->glBufferData(GL_ARRAY_BUFFER, glamor_priv->vbo_offset, glamor_priv->vb,
+ GL_STREAM_DRAW);
+
+ dispatch->glDrawArrays(GL_TRIANGLES, 0, glamor_priv->render_nr_verts);
+ glamor_reset_composite_vbo(screen);
+}
+
+static void
+glamor_emit_composite_rect(ScreenPtr screen,
+ const float *src_coords,
+ const float *mask_coords,
+ const float *dst_coords)
+{
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+
+ if (glamor_priv->vbo_offset + 6 * glamor_priv->vb_stride >
+ glamor_priv->vbo_size)
+ {
+ glamor_flush_composite_rects(screen);
+ }
+
+ if (glamor_priv->vbo_offset == 0) {
+ if (glamor_priv->vbo == 0)
+ dispatch->glGenBuffers(1, &glamor_priv->vbo);
+
+ glamor_setup_composite_vbo(screen);
+ }
+
+ 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);
+ glamor_emit_composite_vert(screen, src_coords, mask_coords, dst_coords, 0);
+ glamor_emit_composite_vert(screen, src_coords, mask_coords, dst_coords, 2);
+ glamor_emit_composite_vert(screen, src_coords, mask_coords, dst_coords, 3);
+}
+
+
+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 Bool
+glamor_composite_with_shader(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ int nrect,
+ glamor_composite_rect_t *rects)
+{
+ ScreenPtr screen = dest->pDrawable->pScreen;
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+ PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable);
+ PixmapPtr source_pixmap = NULL, mask_pixmap = NULL;
+ glamor_pixmap_private *source_pixmap_priv = NULL;
+ glamor_pixmap_private *mask_pixmap_priv = NULL;
+ glamor_pixmap_private *dest_pixmap_priv = NULL;
+ GLfloat dst_xscale, dst_yscale;
+ GLfloat mask_xscale = 1, mask_yscale = 1, src_xscale = 1, src_yscale = 1;
+ struct shader_key key;
+ glamor_composite_shader *shader;
+ RegionRec region;
+ float vertices[8], source_texcoords[8], mask_texcoords[8];
+ int i;
+ BoxPtr box;
+ int dest_x_off, dest_y_off;
+ int source_x_off, source_y_off;
+ int mask_x_off, mask_y_off;
+ enum glamor_pixmap_status source_status = GLAMOR_NONE;
+ enum glamor_pixmap_status mask_status = GLAMOR_NONE;
+ PictFormatShort saved_source_format = 0;
+ float src_matrix[9], mask_matrix[9];
+ GLfloat source_solid_color[4], mask_solid_color[4];
+
+ dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
+
+ 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->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 {
+ glamor_fallback("gradient source\n");
+ 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 {
+ glamor_fallback("gradient mask\n");
+ goto fail;
+ }
+ } else {
+ key.mask = SHADER_MASK_TEXTURE_ALPHA;
+ }
+
+ if (!mask->componentAlpha) {
+ key.in = SHADER_IN_NORMAL;
+ } else {
+ /* We only handle two CA modes. */
+ if (op == PictOpAdd)
+ key.in = SHADER_IN_CA_SOURCE;
+ else if (op == PictOpOutReverse) {
+ 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->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 = glamor_get_drawable_pixmap(source->pDrawable);
+ source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
+ if (source_pixmap == dest_pixmap) {
+ glamor_fallback("source == dest\n");
+ goto fail;
+ }
+ if (!source_pixmap_priv || source_pixmap_priv->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
+ }
+ else if (source_pixmap_priv->pending_op.type == GLAMOR_PENDING_FILL) {
+ key.source = SHADER_SOURCE_SOLID;
+ memcpy(source_solid_color, source_pixmap_priv->pending_op.fill.color4fv, 4 * sizeof(float));
+ }
+ }
+ if (key.mask == SHADER_MASK_TEXTURE ||
+ key.mask == SHADER_MASK_TEXTURE_ALPHA) {
+ mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable);
+ mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap);
+ if (mask_pixmap == dest_pixmap) {
+ glamor_fallback("mask == dest\n");
+ goto fail;
+ }
+ if (!mask_pixmap_priv || mask_pixmap_priv->gl_fbo == 0) {
+#ifdef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
+ mask_status = GLAMOR_UPLOAD_PENDING;
+#else
+ glamor_fallback("no texture in mask\n");
+ goto fail;
+#endif
+ }
+ else if (mask_pixmap_priv->pending_op.type == GLAMOR_PENDING_FILL) {
+ key.mask = SHADER_MASK_SOLID;
+ memcpy(mask_solid_color, mask_pixmap_priv->pending_op.fill.color4fv, 4 * sizeof(float));
+ }
+ }
+#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
+ glamor_set_destination_pixmap_priv_nc(dest_pixmap_priv);
+ glamor_validate_pixmap(dest_pixmap);
+ if (!glamor_set_composite_op(screen, op, 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;
+ }
+
+ dispatch->glUseProgram(shader->prog);
+
+
+ if (key.source == SHADER_SOURCE_SOLID) {
+ glamor_set_composite_solid(dispatch, source_solid_color, shader->source_uniform_location);
+ } else {
+ glamor_set_composite_texture(screen, 0, source, source_pixmap_priv);
+ }
+ if (key.mask != SHADER_MASK_NONE) {
+ if (key.mask == SHADER_MASK_SOLID) {
+ glamor_set_composite_solid(dispatch, mask_solid_color, shader->mask_uniform_location);
+ } else {
+ glamor_set_composite_texture(screen, 1, mask, mask_pixmap_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);
+
+ glamor_get_drawable_deltas(dest->pDrawable, dest_pixmap,
+ &dest_x_off, &dest_y_off);
+ pixmap_priv_get_scale(dest_pixmap_priv, &dst_xscale, &dst_yscale);
+
+
+
+ if (glamor_priv->has_source_coords) {
+ 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);
+ glamor_picture_get_matrixf(source, src_matrix);
+ }
+
+ if (glamor_priv->has_mask_coords) {
+ 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);
+ glamor_picture_get_matrixf(mask, mask_matrix);
+ }
+
+ while (nrect--) {
+ 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;
+ y_dest = rects->y_dst;
+ x_source = rects->x_src;
+ y_source = rects->y_src;
+ x_mask = rects->x_mask;
+ y_mask = rects->y_mask;
+ width = rects->width;
+ height = rects->height;
+
+ x_dest += dest->pDrawable->x;
+ y_dest += dest->pDrawable->y;
+ if (source->pDrawable) {
+ x_source += source->pDrawable->x;
+ y_source += source->pDrawable->y;
+ }
+ if (mask && mask->pDrawable) {
+ x_mask += mask->pDrawable->x;
+ y_mask += mask->pDrawable->y;
+ }
+
+ if (!miComputeCompositeRegion(&region,
+ source, mask, dest,
+ x_source, y_source,
+ x_mask, y_mask,
+ x_dest, y_dest,
+ width, height))
+ continue;
+
+ x_source += source_x_off;
+ y_source += source_y_off;
+ x_mask += mask_x_off;
+ y_mask += mask_y_off;
+
+ box = REGION_RECTS(&region);
+ for (i = 0; i < REGION_NUM_RECTS(&region); i++) {
+ int vx1 = box[i].x1 + dest_x_off;
+ int vx2 = box[i].x2 + dest_x_off;
+ int vy1 = box[i].y1 + dest_y_off;
+ int vy2 = box[i].y2 + dest_y_off;
+ glamor_set_normalize_vcoords(dst_xscale, dst_yscale, vx1, vy1, vx2, vy2,
+ glamor_priv->yInverted, vertices);
+
+ if (key.source != SHADER_SOURCE_SOLID) {
+ int tx1 = box[i].x1 + x_source - x_dest;
+ int ty1 = box[i].y1 + y_source - y_dest;
+ int tx2 = box[i].x2 + x_source - x_dest;
+ int ty2 = box[i].y2 + y_source - y_dest;
+ if (source->transform)
+ glamor_set_transformed_normalize_tcoords(src_matrix, src_xscale, src_yscale,
+ tx1, ty1, tx2, ty2,
+ glamor_priv->yInverted,
+ source_texcoords);
+ else
+ glamor_set_normalize_tcoords(src_xscale, src_yscale, tx1, ty1, tx2, ty2,
+ glamor_priv->yInverted, source_texcoords);
+ }
+
+ if (key.mask != SHADER_MASK_NONE && key.mask != SHADER_MASK_SOLID) {
+ float tx1 = box[i].x1 + x_mask - x_dest;
+ float ty1 = box[i].y1 + y_mask - y_dest;
+ float tx2 = box[i].x2 + x_mask - x_dest;
+ float ty2 = box[i].y2 + y_mask - y_dest;
+ if (mask->transform)
+ glamor_set_transformed_normalize_tcoords(mask_matrix, mask_xscale, mask_yscale,
+ tx1, ty1, tx2, ty2,
+ glamor_priv->yInverted,
+ mask_texcoords);
+ else
+ glamor_set_normalize_tcoords(mask_xscale, mask_yscale, tx1, ty1, tx2, ty2,
+ glamor_priv->yInverted, mask_texcoords);
+ }
+ glamor_emit_composite_rect(screen, source_texcoords,
+ mask_texcoords, vertices);
+ }
+ rects++;
+ }
+ glamor_flush_composite_rects(screen);
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_MASK);
+ REGION_UNINIT(dst->pDrawable->pScreen, &region);
+ 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);
+ if (saved_source_format)
+ source->format = saved_source_format;
+ return TRUE;
+
+ fail:
+ if (saved_source_format)
+ source->format = saved_source_format;
+
+ dispatch->glDisable(GL_BLEND);
+ dispatch->glUseProgram(0);
+ return FALSE;
+}
+
+static PicturePtr
+glamor_convert_gradient_picture(ScreenPtr screen,
+ PicturePtr source,
+ int x_source,
+ int y_source,
+ int width,
+ int height)
+{
+ PixmapPtr pixmap;
+ PicturePtr dst;
+ int error;
+ PictFormatShort format;
+
+ if (!source->pDrawable)
+ format = PICT_a8r8g8b8;
+ else
+ format = source->format;
+
+ pixmap = screen->CreatePixmap(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);
+ screen->DestroyPixmap(pixmap);
+ if (!dst)
+ return NULL;
+
+ ValidatePicture(dst);
+
+ fbComposite(PictOpSrc, source, NULL, dst, x_source, y_source,
+ 0, 0, 0, 0, width, height);
+ return dst;
+}
+
+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)
+{
+ 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;
+ PicturePtr temp_src = source, temp_mask = mask;
+ int x_temp_src, y_temp_src, x_temp_mask, y_temp_mask;
+ glamor_composite_rect_t rect;
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+
+ x_temp_src = x_source;
+ y_temp_src = y_source;
+ x_temp_mask = x_mask;
+ y_temp_mask = y_mask;
+
+ dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
+ /* Currently. Always fallback to cpu if destination is in CPU memory. */
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) {
+ goto fail;
+ }
+
+ if (source->pDrawable) {
+ source_pixmap = glamor_get_drawable_pixmap(source->pDrawable);
+ source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
+ }
+
+ if (mask && mask->pDrawable) {
+ mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable);
+ mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap);
+ }
+
+ if ((!source->pDrawable && (source->pSourcePict->type != SourcePictTypeSolidFill))
+ || (source->pDrawable
+ && !GLAMOR_PIXMAP_PRIV_HAS_FBO(source_pixmap_priv)
+ && ((width * height * 4
+ < (source_pixmap->drawable.width * source_pixmap->drawable.height))
+ || !(glamor_check_fbo_size(glamor_priv, source_pixmap->drawable.width,
+ source_pixmap->drawable.height))))) {
+ temp_src = glamor_convert_gradient_picture(screen, source, x_source, y_source, width, height);
+ if (!temp_src) {
+ temp_src = source;
+ goto fail;
+ }
+ x_temp_src = y_temp_src = 0;
+ }
+
+ if (mask
+ && ((!mask->pDrawable && (mask->pSourcePict->type != SourcePictTypeSolidFill))
+ || (mask->pDrawable
+ && (!GLAMOR_PIXMAP_PRIV_HAS_FBO(mask_pixmap_priv))
+ && ((width * height * 4
+ < (mask_pixmap->drawable.width * mask_pixmap->drawable.height))
+ || !(glamor_check_fbo_size(glamor_priv, mask_pixmap->drawable.width,
+ mask_pixmap->drawable.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, x_mask, y_mask, width, height);
+ if (!temp_mask) {
+ temp_mask = mask;
+ goto fail;
+ }
+ x_temp_mask = y_temp_mask = 0;
+ }
+ /* Do two-pass PictOpOver componentAlpha, until we enable
+ * dual source color blending.
+ */
+
+ if (mask && mask->componentAlpha) {
+ if (op == PictOpOver) {
+ glamor_composite(PictOpOutReverse,
+ temp_src, temp_mask, dest,
+ x_temp_src, y_temp_src,
+ x_temp_mask, y_temp_mask,
+ x_dest, y_dest,
+ width, height);
+ glamor_composite(PictOpAdd,
+ temp_src, temp_mask, dest,
+ x_temp_src, y_temp_src,
+ x_temp_mask, y_temp_mask,
+ x_dest, y_dest,
+ width, height);
+ goto done;
+
+ } else if (op != PictOpAdd && op != PictOpOutReverse) {
+ glamor_fallback("glamor_composite(): component alpha\n");
+ goto fail;
+ }
+ }
+
+ if (!mask) {
+ if (glamor_composite_with_copy(op, temp_src, dest,
+ x_temp_src, y_temp_src,
+ x_dest, y_dest,
+ width, height))
+ goto done;
+ }
+
+ rect.x_src = x_temp_src;
+ rect.y_src = y_temp_src;
+ rect.x_mask = x_temp_mask;
+ rect.y_mask = y_temp_mask;
+ rect.x_dst = x_dest;
+ rect.y_dst = y_dest;
+ rect.width = width;
+ rect.height = height;
+ if (glamor_composite_with_shader(op, temp_src, temp_mask, dest, 1, &rect))
+ goto done;
+
+fail:
+
+ 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));
+
+ dispatch->glUseProgram(0);
+ dispatch->glDisable(GL_BLEND);
+ if (glamor_prepare_access_picture(dest, GLAMOR_ACCESS_RW)) {
+ if (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_finish_access_picture(source);
+ }
+ glamor_finish_access_picture(dest);
+ }
+done:
+ if (temp_src != source)
+ FreePicture(temp_src, 0);
+ if (temp_mask != mask)
+ FreePicture(temp_mask, 0);
+}
+
+
+/**
+ * Creates an appropriate picture to upload our alpha mask into (which
+ * we calculated in system memory)
+ */
+static PicturePtr
+glamor_create_mask_picture(ScreenPtr screen,
+ PicturePtr dst,
+ PictFormatPtr pict_format,
+ CARD16 width,
+ CARD16 height)
+{
+ 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;
+ }
+
+ pixmap = screen->CreatePixmap(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);
+ screen->DestroyPixmap(pixmap);
+ return picture;
+}
+
+/**
+ * glamor_trapezoids is a copy of miTrapezoids that does all the trapezoid
+ * accumulation in system memory.
+ */
+void
+glamor_trapezoids(CARD8 op,
+ PicturePtr src, PicturePtr dst,
+ PictFormatPtr mask_format, INT16 x_src, INT16 y_src,
+ int ntrap, xTrapezoid *traps)
+{
+ 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;
+
+ /* 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;
+ }
+
+ miTrapezoidBounds(ntrap, traps, &bounds);
+
+ if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+ return;
+
+ 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);
+ picture = glamor_create_mask_picture(screen, dst, mask_format,
+ width, height);
+ if (!picture)
+ return;
+
+ image = pixman_image_create_bits(picture->format,
+ width, height,
+ NULL, stride);
+ if (!image) {
+ FreePicture(picture, 0);
+ return;
+ }
+
+ 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;
+ CompositePicture(op, src, picture, dst,
+ x_rel, y_rel,
+ 0, 0,
+ bounds.x1, bounds.y1,
+ bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
+
+ pixman_image_unref(image);
+
+ FreePicture(picture, 0);
+}
+
+void
+glamor_composite_rects(CARD8 op,
+ PicturePtr src, PicturePtr mask, PicturePtr dst,
+ int nrect, glamor_composite_rect_t *rects)
+{
+ int n;
+ glamor_composite_rect_t *r;
+
+ ValidatePicture(src);
+ ValidatePicture(dst);
+
+ if (glamor_composite_with_shader(op, src, mask, dst, nrect, rects))
+ return;
+
+ n = nrect;
+ r = rects;
+
+ while (n--) {
+ CompositePicture(op,
+ 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++;
+ }
+}
+
+#endif /* RENDER */
diff --git a/glamor/glamor_setspans.c b/glamor/glamor_setspans.c
new file mode 100644
index 000000000..bb4bffdd9
--- /dev/null
+++ b/glamor/glamor_setspans.c
@@ -0,0 +1,110 @@
+/*
+ * 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>
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "glamor_priv.h"
+
+void
+glamor_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
+ DDXPointPtr points, int *widths, int n, int sorted)
+{
+ PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(drawable);
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(drawable->pScreen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->dispatch;
+ GLenum format, type;
+ int no_alpha, no_revert, i;
+ uint8_t *drawpixels_src = (uint8_t *)src;
+ RegionPtr clip = fbGetCompositeClip(gc);
+ BoxRec *pbox;
+ int x_off, y_off;
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_ES2) {
+ glamor_fallback("ES2 fallback.\n");
+ goto fail;
+ }
+
+ if (glamor_get_tex_format_type_from_pixmap(dest_pixmap,
+ &format,
+ &type,
+ &no_alpha,
+ &no_revert
+ )) {
+ glamor_fallback("unknown depth. %d \n",
+ drawable->depth);
+ goto fail;
+ }
+
+
+ if (glamor_set_destination_pixmap(dest_pixmap))
+ goto fail;
+
+ glamor_validate_pixmap(dest_pixmap);
+ if (!glamor_set_planemask(dest_pixmap, gc->planemask))
+ goto fail;
+ glamor_set_alu(dispatch, gc->alu);
+ 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 < n; i++) {
+
+ n = REGION_NUM_RECTS(clip);
+ pbox = REGION_RECTS(clip);
+ while (n--) {
+ if (pbox->y1 > points[i].y)
+ break;
+ dispatch->glScissor(pbox->x1,
+ points[i].y + y_off,
+ pbox->x2 - pbox->x1,
+ 1);
+ dispatch->glEnable(GL_SCISSOR_TEST);
+ dispatch->glRasterPos2i(points[i].x + x_off,
+ points[i].y + y_off);
+ dispatch->glDrawPixels(widths[i],
+ 1,
+ format, type,
+ drawpixels_src);
+ }
+ drawpixels_src += PixmapBytePad(widths[i], drawable->depth);
+ }
+ glamor_set_planemask(dest_pixmap, ~0);
+ glamor_set_alu(dispatch, GXcopy);
+ dispatch->glDisable(GL_SCISSOR_TEST);
+ return;
+fail:
+
+ 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, n, sorted);
+ glamor_finish_access(drawable);
+ }
+}
diff --git a/glamor/glamor_tile.c b/glamor/glamor_tile.c
new file mode 100644
index 000000000..687cc6a41
--- /dev/null
+++ b/glamor/glamor_tile.c
@@ -0,0 +1,194 @@
+/*
+ * 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>
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#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_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch = &glamor_priv->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"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = texture2D(sampler, tile_texture);\n"
+ "}\n";
+ GLint fs_prog, vs_prog;
+ GLint sampler_uniform_location;
+
+ 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);
+ dispatch->glUseProgram(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_gl_dispatch *dispatch = &glamor_priv->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;
+
+ src_pixmap_priv = glamor_get_pixmap_private(tile);
+ dst_pixmap_priv = glamor_get_pixmap_private(pixmap);
+
+ if (((tile_x != 0) && (tile_x + width > tile->drawable.width))
+ || ((tile_y != 0) && (tile_y + height > tile->drawable.height))) {
+ ErrorF("tile_x = %d tile_y = %d \n", tile_x, tile_y);
+ goto fail;
+ }
+ if (glamor_priv->tile_prog == 0) {
+ glamor_fallback("Tiling unsupported\n");
+ goto fail;
+ }
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv)) {
+ glamor_fallback("dest has no fbo.\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;
+ }
+ if (alu != GXcopy) {
+ glamor_set_destination_pixmap_priv_nc(src_pixmap_priv);
+ glamor_validate_pixmap(tile);
+ }
+
+ glamor_set_destination_pixmap_priv_nc(dst_pixmap_priv);
+ glamor_validate_pixmap(pixmap);
+ pixmap_priv_get_scale(dst_pixmap_priv, &dst_xscale, &dst_yscale);
+
+ glamor_set_alu(dispatch, alu);
+
+ if (GLAMOR_PIXMAP_PRIV_NO_PENDING(src_pixmap_priv)) {
+ pixmap_priv_get_scale(src_pixmap_priv, &src_xscale, &src_yscale);
+ dispatch->glUseProgram(glamor_priv->tile_prog);
+
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glBindTexture(GL_TEXTURE_2D, src_pixmap_priv->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_normalize_tcoords(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);
+ }
+ else {
+ GLAMOR_CHECK_PENDING_FILL(dispatch, glamor_priv, src_pixmap_priv);
+ }
+
+ glamor_set_normalize_vcoords(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);
+
+ if (GLAMOR_PIXMAP_PRIV_NO_PENDING(src_pixmap_priv)) {
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+#ifndef GLAMOR_GLES2
+ dispatch->glDisable(GL_TEXTURE_2D);
+#endif
+ }
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glUseProgram(0);
+ glamor_set_alu(dispatch, GXcopy);
+ glamor_set_planemask(pixmap, ~0);
+ return TRUE;
+
+fail:
+ return FALSE;
+}
diff --git a/glamor/glamor_triangles.c b/glamor/glamor_triangles.c
new file mode 100644
index 000000000..168d485f0
--- /dev/null
+++ b/glamor/glamor_triangles.c
@@ -0,0 +1,61 @@
+/*
+ * 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>
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "glamor_priv.h"
+
+void
+glamor_triangles (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc,
+ INT16 ySrc,
+ int ntris,
+ xTriangle *tris)
+{
+
+ if (glamor_prepare_access(pDst->pDrawable, GLAMOR_ACCESS_RW)) {
+ if (pSrc->pDrawable == NULL ||
+ glamor_prepare_access(pSrc->pDrawable, GLAMOR_ACCESS_RO))
+ {
+
+ fbTriangles(op,
+ pSrc, pDst, maskFormat, xSrc, ySrc, ntris, tris);
+ }
+ if (pSrc->pDrawable != NULL)
+ glamor_finish_access(pSrc->pDrawable);
+
+ glamor_finish_access(pDst->pDrawable);
+ }
+}
+
+
diff --git a/glamor/glamor_utils.h b/glamor/glamor_utils.h
new file mode 100644
index 000000000..fe5bd4e1e
--- /dev/null
+++ b/glamor/glamor_utils.h
@@ -0,0 +1,542 @@
+#ifndef GLAMOR_PRIV_H
+#error This file can only be included by glamor_priv.h
+#endif
+
+#ifndef __GLAMOR_UTILS_H__
+#define __GLAMOR_UTILS_H__
+
+#define v_from_x_coord_x(_xscale_, _x_) ( 2 * (_x_) * (_xscale_) - 1.0)
+#define v_from_x_coord_y(_yscale_, _y_) (-2 * (_y_) * (_yscale_) + 1.0)
+#define v_from_x_coord_y_inverted(_yscale_, _y_) (2 * (_y_) * (_yscale_) - 1.0)
+#define t_from_x_coord_x(_xscale_, _x_) ((_x_) * (_xscale_))
+#define t_from_x_coord_y(_yscale_, _y_) (1.0 - (_y_) * (_yscale_))
+#define t_from_x_coord_y_inverted(_yscale_, _y_) ((_y_) * (_yscale_))
+
+#define pixmap_priv_get_scale(_pixmap_priv_, _pxscale_, _pyscale_) \
+ do { \
+ *(_pxscale_) = 1.0 / (_pixmap_priv_)->container->drawable.width; \
+ *(_pyscale_) = 1.0 / (_pixmap_priv_)->container->drawable.height; \
+ } while(0)
+
+
+#define xFixedToFloat(_val_) ((float)xFixedToInt(_val_) \
+ + ((float)xFixedFrac(_val_) / 65536.0))
+
+#define glamor_picture_get_matrixf(_picture_, _matrix_) \
+ do { \
+ int _i_; \
+ if ((_picture_)->transform) \
+ { \
+ for(_i_ = 0; _i_ < 3; _i_++) \
+ { \
+ (_matrix_)[_i_ * 3 + 0] = \
+ xFixedToFloat((_picture_)->transform->matrix[_i_][0]); \
+ (_matrix_)[_i_ * 3 + 1] = \
+ xFixedToFloat((_picture_)->transform->matrix[_i_][1]); \
+ (_matrix_)[_i_ * 3 + 2] = \
+ xFixedToFloat((_picture_)->transform->matrix[_i_][2]); \
+ } \
+ } \
+ } while(0)
+
+#define glamor_set_transformed_point(matrix, xscale, yscale, texcoord, \
+ x, y, yInverted) \
+ do { \
+ float result[4]; \
+ int i; \
+ float tx, ty; \
+ \
+ for (i = 0; i < 3; i++) { \
+ result[i] = (matrix)[i * 3] * (x) + (matrix)[i * 3 + 1] * (y) \
+ + (matrix)[i * 3 + 2]; \
+ } \
+ tx = result[0] / result[2]; \
+ ty = result[1] / result[2]; \
+ \
+ (texcoord)[0] = t_from_x_coord_x(xscale, tx); \
+ if (yInverted) \
+ (texcoord)[1] = t_from_x_coord_y_inverted(yscale, ty); \
+ else \
+ (texcoord)[1] = t_from_x_coord_y(yscale, ty); \
+ } while(0)
+
+
+#define glamor_set_transformed_normalize_tcoords( matrix, \
+ xscale, \
+ yscale, \
+ tx1, ty1, tx2, ty2, \
+ yInverted, texcoords) \
+ do { \
+ glamor_set_transformed_point(matrix, xscale, yscale, \
+ texcoords, tx1, ty1, \
+ yInverted); \
+ glamor_set_transformed_point(matrix, xscale, yscale, \
+ texcoords + 2, tx2, ty1, \
+ yInverted); \
+ glamor_set_transformed_point(matrix, xscale, yscale, \
+ texcoords + 4, tx2, ty2, \
+ yInverted); \
+ glamor_set_transformed_point(matrix, xscale, yscale, \
+ texcoords + 6, tx1, ty2, \
+ yInverted); \
+ } while (0)
+
+#define glamor_set_normalize_tcoords(xscale, yscale, x1, y1, x2, y2, \
+ yInverted, vertices) \
+ do { \
+ (vertices)[0] = t_from_x_coord_x(xscale, x1); \
+ (vertices)[2] = t_from_x_coord_x(xscale, x2); \
+ (vertices)[4] = (vertices)[2]; \
+ (vertices)[6] = (vertices)[0]; \
+ if (yInverted) { \
+ (vertices)[1] = t_from_x_coord_y_inverted(yscale, y1); \
+ (vertices)[5] = t_from_x_coord_y_inverted(yscale, y2); \
+ } \
+ else { \
+ (vertices)[1] = t_from_x_coord_y(yscale, y1); \
+ (vertices)[5] = t_from_x_coord_y(yscale, y2); \
+ } \
+ (vertices)[3] = (vertices)[1]; \
+ (vertices)[7] = (vertices)[5]; \
+ } while(0)
+
+
+#define glamor_set_normalize_vcoords(xscale, yscale, x1, y1, x2, y2, \
+ yInverted, vertices) \
+ do { \
+ (vertices)[0] = v_from_x_coord_x(xscale, x1); \
+ (vertices)[2] = v_from_x_coord_x(xscale, x2); \
+ (vertices)[4] = (vertices)[2]; \
+ (vertices)[6] = (vertices)[0]; \
+ if (yInverted) { \
+ (vertices)[1] = v_from_x_coord_y_inverted(yscale, y1); \
+ (vertices)[5] = v_from_x_coord_y_inverted(yscale, y2); \
+ } \
+ else { \
+ (vertices)[1] = v_from_x_coord_y(yscale, y1); \
+ (vertices)[5] = v_from_x_coord_y(yscale, y2); \
+ } \
+ (vertices)[3] = (vertices)[1]; \
+ (vertices)[7] = (vertices)[5]; \
+ } while(0)
+
+
+inline static void
+glamor_calculate_boxes_bound(BoxPtr bound, BoxPtr boxes, int nbox)
+{
+ int x_min, y_min;
+ int x_max, y_max;
+ int i;
+ x_min = y_min = MAXSHORT;
+ x_max = y_max = MINSHORT;
+ for(i = 0; i < nbox; i++)
+ {
+ if (x_min > boxes[i].x1)
+ x_min = boxes[i].x1;
+ if (y_min > boxes[i].y1)
+ y_min = boxes[i].y1;
+
+ if (x_max < boxes[i].x2)
+ x_max = boxes[i].x2;
+ if (y_max < boxes[i].y2)
+ y_max = boxes[i].y2;
+ }
+ bound->x1 = x_min;
+ bound->y1 = y_min;
+ bound->x2 = x_max;
+ bound->y2 = y_max;
+}
+
+inline static void
+glamor_transform_boxes(BoxPtr boxes, int nbox, int dx, int dy)
+{
+ int i;
+ for (i = 0; i < nbox; i++)
+ {
+ boxes[i].x1 += dx;
+ boxes[i].y1 += dy;
+ boxes[i].x2 += dx;
+ boxes[i].y2 += dy;
+ }
+}
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+#define glamor_check_fbo_size(_glamor_,_w_, _h_) ((_w_) > 0 && (_h_) > 0 \
+ && (_w_) < _glamor_->max_fbo_size \
+ && (_h_) < _glamor_->max_fbo_size)
+
+#define glamor_check_fbo_depth(_depth_) ( \
+ _depth_ == 8 \
+ || _depth_ == 15 \
+ || _depth_ == 16 \
+ || _depth_ == 24 \
+ || _depth_ == 30 \
+ || _depth_ == 32)
+
+
+#define GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv) (pixmap_priv->is_picture == 1)
+#define GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv) (pixmap_priv->gl_fbo == 1)
+
+#define GLAMOR_PIXMAP_PRIV_NEED_VALIDATE(pixmap_priv) \
+ (GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv) \
+ && (pixmap_priv->pending_op.type != GLAMOR_PENDING_NONE))
+
+#define GLAMOR_PIXMAP_PRIV_NO_PENDING(pixmap_priv) \
+ (pixmap_priv->pending_op.type == GLAMOR_PENDING_NONE)
+
+#define GLAMOR_CHECK_PENDING_FILL(_dispatch_, _glamor_priv_, _pixmap_priv_) do \
+ { \
+ if (_pixmap_priv_->pending_op.type == GLAMOR_PENDING_FILL) { \
+ _dispatch_->glUseProgram(_glamor_priv_->solid_prog); \
+ _dispatch_->glUniform4fv(_glamor_priv_->solid_color_uniform_location, 1, \
+ _pixmap_priv_->pending_op.fill.color4fv); \
+ } \
+ } while(0)
+
+
+/**
+ * Borrow from uxa.
+ */
+static inline CARD32
+format_for_depth(int depth)
+{
+ switch (depth) {
+ case 1: return PICT_a1;
+ case 4: return PICT_a4;
+ case 8: return PICT_a8;
+ case 15: return PICT_x1r5g5b5;
+ case 16: return PICT_r5g6b5;
+ default:
+ case 24: return PICT_x8r8g8b8;
+#if XORG_VERSION_CURRENT >= 10699900
+ case 30: return PICT_x2r10g10b10;
+#endif
+ case 32: return PICT_a8r8g8b8;
+ }
+}
+
+static inline CARD32
+format_for_pixmap(PixmapPtr pixmap)
+{
+ glamor_pixmap_private *pixmap_priv;
+ PictFormatShort pict_format;
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ if (GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv))
+ pict_format = pixmap_priv->pict_format;
+ else
+ pict_format = format_for_depth(pixmap->drawable.depth);
+
+ return pict_format;
+}
+
+/*
+ * Map picture's format to the correct gl texture format and type.
+ * no_alpha is used to indicate whehter we need to wire alpha to 1.
+ *
+ * Return 0 if find a matched texture type. Otherwise return -1.
+ **/
+#ifndef GLAMOR_GLES2
+static inline int
+glamor_get_tex_format_type_from_pictformat(PictFormatShort format,
+ GLenum *tex_format,
+ GLenum *tex_type,
+ int *no_alpha,
+ int *no_revert)
+{
+ *no_alpha = 0;
+ *no_revert = 1;
+ switch (format) {
+ case PICT_a1:
+ *tex_format = GL_COLOR_INDEX;
+ *tex_type = GL_BITMAP;
+ break;
+ case PICT_b8g8r8x8:
+ *no_alpha = 1;
+ case PICT_b8g8r8a8:
+ *tex_format = GL_BGRA;
+ *tex_type = GL_UNSIGNED_INT_8_8_8_8;
+ break;
+
+ case PICT_x8r8g8b8:
+ *no_alpha = 1;
+ case PICT_a8r8g8b8:
+ *tex_format = GL_BGRA;
+ *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ break;
+ case PICT_x8b8g8r8:
+ *no_alpha = 1;
+ case PICT_a8b8g8r8:
+ *tex_format = GL_RGBA;
+ *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ break;
+ case PICT_x2r10g10b10:
+ *no_alpha = 1;
+ case PICT_a2r10g10b10:
+ *tex_format = GL_BGRA;
+ *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ break;
+ case PICT_x2b10g10r10:
+ *no_alpha = 1;
+ case PICT_a2b10g10r10:
+ *tex_format = GL_RGBA;
+ *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ break;
+
+ case PICT_r5g6b5:
+ *tex_format = GL_RGB;
+ *tex_type = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case PICT_b5g6r5:
+ *tex_format = GL_RGB;
+ *tex_type = GL_UNSIGNED_SHORT_5_6_5_REV;
+ break;
+ case PICT_x1b5g5r5:
+ *no_alpha = 1;
+ case PICT_a1b5g5r5:
+ *tex_format = GL_RGBA;
+ *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ break;
+
+ case PICT_x1r5g5b5:
+ *no_alpha = 1;
+ case PICT_a1r5g5b5:
+ *tex_format = GL_BGRA;
+ *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ break;
+ case PICT_a8:
+ *tex_format = GL_ALPHA;
+ *tex_type = GL_UNSIGNED_BYTE;
+ break;
+ case PICT_x4r4g4b4:
+ *no_alpha = 1;
+ case PICT_a4r4g4b4:
+ *tex_format = GL_BGRA;
+ *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
+ break;
+
+ case PICT_x4b4g4r4:
+ *no_alpha = 1;
+ case PICT_a4b4g4r4:
+ *tex_format = GL_RGBA;
+ *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
+ break;
+
+ default:
+ LogMessageVerb(X_INFO, 0, "fail to get matched format for %x \n", format);
+ return -1;
+ }
+ return 0;
+}
+#else
+#define IS_LITTLE_ENDIAN (IMAGE_BYTE_ORDER == LSBFirst)
+
+static inline int
+glamor_get_tex_format_type_from_pictformat(PictFormatShort format,
+ GLenum *tex_format,
+ GLenum *tex_type,
+ int *no_alpha,
+ int *no_revert)
+{
+ *no_alpha = 0;
+ *no_revert = IS_LITTLE_ENDIAN;
+
+ switch (format) {
+ case PICT_b8g8r8x8:
+ *no_alpha = 1;
+ case PICT_b8g8r8a8:
+ *tex_format = GL_BGRA;
+ *tex_type = GL_UNSIGNED_BYTE;
+ *no_revert = !IS_LITTLE_ENDIAN;
+ break;
+
+ case PICT_x8r8g8b8:
+ *no_alpha = 1;
+ case PICT_a8r8g8b8:
+ *tex_format = GL_BGRA;
+ *tex_type = GL_UNSIGNED_BYTE;
+ break;
+
+ case PICT_x8b8g8r8:
+ *no_alpha = 1;
+ case PICT_a8b8g8r8:
+ *tex_format = GL_RGBA;
+ *tex_type = GL_UNSIGNED_BYTE;
+ break;
+
+ case PICT_x2r10g10b10:
+ *no_alpha = 1;
+ case PICT_a2r10g10b10:
+ *tex_format = GL_BGRA;
+ *tex_type = GL_UNSIGNED_INT_10_10_10_2;
+ *no_revert = TRUE;
+ break;
+
+ case PICT_x2b10g10r10:
+ *no_alpha = 1;
+ case PICT_a2b10g10r10:
+ *tex_format = GL_RGBA;
+ *tex_type = GL_UNSIGNED_INT_10_10_10_2;
+ *no_revert = TRUE;
+ break;
+
+ case PICT_r5g6b5:
+ *tex_format = GL_RGB;
+ *tex_type = GL_UNSIGNED_SHORT_5_6_5;
+ *no_revert = TRUE;
+ break;
+
+ case PICT_b5g6r5:
+ *tex_format = GL_RGB;
+ *tex_type = GL_UNSIGNED_SHORT_5_6_5;
+ *no_revert = FALSE;
+ break;
+
+ case PICT_x1b5g5r5:
+ *no_alpha = 1;
+ case PICT_a1b5g5r5:
+ *tex_format = GL_RGBA;
+ *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ *no_revert = TRUE;
+ break;
+
+ case PICT_x1r5g5b5:
+ *no_alpha = 1;
+ case PICT_a1r5g5b5:
+ *tex_format = GL_BGRA;
+ *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ *no_revert = TRUE;
+ break;
+
+ case PICT_a8:
+ *tex_format = GL_ALPHA;
+ *tex_type = GL_UNSIGNED_BYTE;
+ *no_revert = TRUE;
+ break;
+
+ case PICT_x4r4g4b4:
+ *no_alpha = 1;
+ case PICT_a4r4g4b4:
+ *tex_format = GL_BGRA;
+ *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
+ *no_revert = TRUE;
+ break;
+
+ case PICT_x4b4g4r4:
+ *no_alpha = 1;
+ case PICT_a4b4g4r4:
+ *tex_format = GL_RGBA;
+ *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
+ *no_revert = TRUE;
+ break;
+
+ default:
+ LogMessageVerb(X_INFO, 0, "fail to get matched format for %x \n", format);
+ return -1;
+ }
+ return 0;
+}
+
+
+#endif
+
+
+static inline int
+glamor_get_tex_format_type_from_pixmap(PixmapPtr pixmap,
+ GLenum *format,
+ GLenum *type,
+ int *no_alpha,
+ int *no_revert)
+{
+ glamor_pixmap_private *pixmap_priv;
+ PictFormatShort pict_format;
+
+ pixmap_priv = glamor_get_pixmap_private(pixmap);
+ if (GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv))
+ pict_format = pixmap_priv->pict_format;
+ else
+ pict_format = format_for_depth(pixmap->drawable.depth);
+
+ return glamor_get_tex_format_type_from_pictformat(pict_format,
+ format, type,
+ no_alpha, no_revert);
+}
+
+
+/* borrowed from uxa */
+static inline Bool
+glamor_get_rgba_from_pixel(CARD32 pixel,
+ float * red,
+ float * green,
+ float * blue,
+ float * alpha,
+ CARD32 format)
+{
+ int rbits, bbits, gbits, abits;
+ int rshift, bshift, gshift, ashift;
+
+ rbits = PICT_FORMAT_R(format);
+ gbits = PICT_FORMAT_G(format);
+ bbits = PICT_FORMAT_B(format);
+ abits = PICT_FORMAT_A(format);
+
+ if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
+ rshift = gshift = bshift = ashift = 0;
+ } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
+ bshift = 0;
+ gshift = bbits;
+ rshift = gshift + gbits;
+ ashift = rshift + rbits;
+ } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
+ rshift = 0;
+ gshift = rbits;
+ bshift = gshift + gbits;
+ ashift = bshift + bbits;
+#if XORG_VERSION_CURRENT >= 10699900
+ } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
+ ashift = 0;
+ rshift = abits;
+ if (abits == 0)
+ rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
+ gshift = rshift + rbits;
+ bshift = gshift + gbits;
+#endif
+ } else {
+ return FALSE;
+ }
+#define COLOR_INT_TO_FLOAT(_fc_, _p_, _s_, _bits_) \
+ *_fc_ = (((_p_) >> (_s_)) & (( 1 << (_bits_)) - 1)) \
+ / (float)((1<<(_bits_)) - 1)
+
+ if (rbits)
+ COLOR_INT_TO_FLOAT(red, pixel, rshift, rbits);
+ else
+ *red = 0;
+
+ if (gbits)
+ COLOR_INT_TO_FLOAT(green, pixel, gshift, gbits);
+ else
+ *green = 0;
+
+ if (bbits)
+ COLOR_INT_TO_FLOAT(blue, pixel, bshift, bbits);
+ else
+ *blue = 0;
+
+ if (abits)
+ COLOR_INT_TO_FLOAT(alpha, pixel, ashift, abits);
+ else
+ *alpha = 1;
+
+ return TRUE;
+}
+
+
+
+
+
+
+#endif
diff --git a/glamor/glamor_window.c b/glamor/glamor_window.c
new file mode 100644
index 000000000..05555b204
--- /dev/null
+++ b/glamor/glamor_window.c
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "glamor_priv.h"
+
+/** @file glamor_window.c
+ *
+ * Screen Change Window Attribute implementation.
+ */
+
+
+static void
+glamor_fixup_window_pixmap(DrawablePtr pDrawable, PixmapPtr *ppPixmap)
+{
+ PixmapPtr pPixmap = *ppPixmap;
+ glamor_pixmap_private *pixmap_priv;
+
+ if (pPixmap->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
+ {
+ pixmap_priv = glamor_get_pixmap_private(pPixmap);
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) {
+ glamor_fallback("pixmap %p has no fbo\n", pPixmap);
+ goto fail;
+ }
+ glamor_debug_output(GLAMOR_DEBUG_UNIMPL, "To be implemented.\n");
+ }
+ return;
+
+fail:
+ GLAMOR_PANIC(" We can't fall back to fbFixupWindowPixmap, as the fb24_32ReformatTile"
+ " is broken for glamor. \n");
+}
+
+Bool
+glamor_change_window_attributes(WindowPtr pWin, unsigned long mask)
+{
+ if (mask & CWBackPixmap) {
+ if (pWin->backgroundState == BackgroundPixmap)
+ glamor_fixup_window_pixmap(&pWin->drawable, &pWin->background.pixmap);
+ }
+
+ if (mask & CWBorderPixmap) {
+ if (pWin->borderIsPixel == FALSE)
+ glamor_fixup_window_pixmap(&pWin->drawable, &pWin->border.pixmap);
+ }
+ return TRUE;
+}
+
+
+