diff options
37 files changed, 9428 insertions, 0 deletions
@@ -0,0 +1,20 @@ +Copyright © 2010,2011 Intel Corporation + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..1ca7dbb --- /dev/null +++ b/Makefile.am @@ -0,0 +1,32 @@ +AUTOMAKE_OPTIONS=nostdinc +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = src + +aclocaldir = $(datadir)/aclocal + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = glamor-egl.pc glamor.pc + +EXTRA_DIST = glamor-egl.pc.in glamor.pc.in autogen.sh + +DISTCHECK_CONFIGURE_FLAGS=\ + --with-xkb-path=$(XKB_BASE_DIRECTORY) \ + --with-xkb-bin-directory=$(XKB_BIN_DIRECTORY) \ + --with-xkb-output='$${datadir}/X11/xkb/compiled' + +.PHONY: ChangeLog INSTALL + +INSTALL: + $(INSTALL_CMD) + +ChangeLog: + $(CHANGELOG_CMD) + +dist-hook: ChangeLog INSTALL + +DIST_SUBDIRS = src + +# gross hack +relink: all + $(AM_V_at)$(MAKE) -C hw relink @@ -0,0 +1,38 @@ +glamor +Open-source X.org graphics common driver based on GL library. + +What is glamor +------------------------ +The glamor module is an open-source 2D graphics common driver for +the X Window System as implemented by X.org. It supports a variety of +graphics chipsets which have OpenGL/EGL/GBM supports. + +Where to get more information about the driver +---------------------------------------------- + + TBD. + +Documentation specific to the glamor common module including +possible configuration options for the xorg.conf file can be found in +the glamor(4) manual page. After installing the module this +documentation can be read with the following command: + + man glamor + +Mailing list for communication with users and developers of +glamor: + + TBD + + Note: Subscription is required before posting, but anyone is + free to subscribe. See instructions (and archives) here: + + http://lists.freedesktop.org/mailman/listinfo/glamor + +To report bugs encountered with the driver, see: + + TBD. + +To see bugs that are targeted to be fixed in the next release: + + TBD. diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..30d679f --- /dev/null +++ b/autogen.sh @@ -0,0 +1,6 @@ +#! /bin/sh + +test -n "$srcdir" || srcdir=`dirname "$0"` +test -n "$srcdir" || srcdir=. +autoreconf --force --install --verbose "$srcdir" +test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..7ac3642 --- /dev/null +++ b/configure.ac @@ -0,0 +1,110 @@ +# Copyright 2011 Zhigang Gong. +# +# 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 +# on the rights to use, copy, modify, merge, publish, distribute, sub +# license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL +# ADAM JACKSON 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. +# +# Process this file with autoconf to produce a configure script + + +# Initialize Autoconf +AC_PREREQ([2.63]) +AC_INIT([glamor-egl], + [1.0.0], + [https://bugs.freedesktop.org/enter_bug.cgi?product=glamor], + [glamor-egl]) + +AC_CONFIG_SRCDIR([Makefile.am]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADERS([config.h]) + +# Initialize Automake +AM_INIT_AUTOMAKE([foreign dist-bzip2]) +AM_MAINTAINER_MODE + +# Initialize libtool +AC_PROG_LIBTOOL + +# Initialize X.Org macros 1.8 or later for MAN_SUBSTS set by XORG_MANPAGE_SECTIONS +m4_ifndef([XORG_MACROS_VERSION], + [m4_fatal([must install xorg-macros 1.8 or later before running autoconf/autogen])]) +XORG_MACROS_VERSION(1.8) +XORG_DEFAULT_OPTIONS + + +# Checks for programs. +# AC_PROG_LN_S + +# Obtain compiler/linker options for dependencies + +PKG_PROG_PKG_CONFIG + +PKG_CHECK_MODULES(XORG, [xorg-server >= 1.10]) +PKG_CHECK_MODULES(DRI2, [dri2proto >= 2.6]) + +LIBDRM="libdrm >= 2.4.23" +LIBGL="gl >= 7.1.0" +LIBPIXMAN="pixman-1 >= 0.21.8" +LIBEGL="egl" +LIBGLESV2="glesv2" +LIBGBM="gbm" + +# Define a configure option for an alternate input module directory +AC_ARG_WITH(xorg-module-dir, + AC_HELP_STRING([--with-xorg-module-dir=DIR], + [Default xorg module directory [[default=$libdir/xorg/modules]]]), + [moduledir="$withval"], + [moduledir="$libdir/xorg/modules"]) + +AC_SUBST([moduledir]) + +# X Server SDK location is required to install evdev header files +# This location is also relayed in the xorg-evdev.pc file +sdkdir=`$PKG_CONFIG --variable=sdkdir xorg-server` +AC_SUBST([sdkdir]) + +AM_CONDITIONAL([GLAMOR_GLES2], [test "x$GLAMOR_GLES2" = xyes]) + +if test "x$GLAMOR_GLES2" = xyes; then + AC_DEFINE(GLAMOR_GLES2,1,[Build glamor over GLES2]) + PKG_CHECK_MODULES(GLESV2, $LIBGLESV2) + REQUIRED_LIBS="$REQUIRED_LIBS $LIBGLESV2" + GLAMOR_GL_CFLAGS="$GLESV2_CFLAGS -DGLAMOR_GLES2" +else + AC_DEFINE(GLAMOR_GL,1,[Build glamor over GL]) + PKG_CHECK_MODULES(GL, $LIBGL) + REQUIRED_LIBS="$REQUIRED_LIBS $LIBGL" + GLAMOR_GL_CFLAGS="$GL_CFLAGS -DGLAMOR_GL" +fi + +AC_SUBST([GLAMOR_GL_CFLAGS]) + +PKG_CHECK_MODULES([LIBDRM], $LIBDRM) +PKG_CHECK_MODULES(EGL, $LIBEGL, [EGL=yes], [EGL=no]) +AM_CONDITIONAL([EGL], [test "x$EGL" = xyes]) + +if test "x$EGL = xyes"; then + PKG_CHECK_MODULES(EGL, $LIBGBM) +fi + + +AC_ARG_ENABLE(glamor-gles2, AS_HELP_STRING([--enable-glamor-gles2], [Build glamor based on gles2 (default: no)]), [GLAMOR_GLES2=$enableval], [GLAMOR_GLES2=no]) + +AC_OUTPUT([Makefile + glamor-egl.pc + glamor.pc + src/Makefile]) diff --git a/glamor-egl.pc.in b/glamor-egl.pc.in new file mode 100644 index 0000000..1779ccf --- /dev/null +++ b/glamor-egl.pc.in @@ -0,0 +1,14 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +moduledir=@moduledir@ +sdkdir=@sdkdir@ +GLAMOR_GL_CFLAGS=@GLAMOR_GL_CFLAGS@ +GLAMOR_EGL_CFLAGS=@GLAMOR_EGL_CFLAGS@ @GLAMOR_EGL_LIBS@ + +Name: glamor-egl +Description: X.Org glamor common library. +Version: @PACKAGE_VERSION@ +Cflags: -I${sdkdir} -L${moduledir} ${GLAMOR_GL_CFLAGS} ${GLAMOR_EGL_CFLAGS} + diff --git a/glamor.pc.in b/glamor.pc.in new file mode 100644 index 0000000..74ecd2e --- /dev/null +++ b/glamor.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +moduledir=@moduledir@ +sdkdir=@sdkdir@ +GLAMOR_GL_CFLAGS=@GLAMOR_GL_CFLAGS@ + +Name: glamor +Description: X.Org glamor common library. +Version: @PACKAGE_VERSION@ +Cflags: -I${sdkdir} -L${moduledir} -lglamor ${GLAMOR_GL_CFLAGS} + diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/m4/.gitignore diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..a382eb5 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,56 @@ +inst_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 GLAMOR_GLES2 +libglamor_la_LIBADD = $(GLESV2_LIBS) +else +libglamor_la_LIBADD = $(GL_LIBS) +endif + +instdir = $(moduledir) + +INCLUDES = \ + $(XORG_INCS) + +AM_CFLAGS = $(XORG_CFLAGS) $(DIX_CFLAGS) $(LIBDRM_CFLAGS) + +libglamor_la_LDFLAGS = -avoid-version + +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 + +sdk_HEADERS = glamor.h + +if EGL +LIBGLAMOR_EGL = libglamor_egl.la +module_LTLIBRARIES = $(LIBGLAMOR_EGL) +libglamor_egl_la_DEPENDENCIES = libglamor.la +libglamor_egl_la_LDFLAGS = -avoid-version -module $(EGL_LIBS) -lglamor +#libglamor_egl_la_LIBADD = $(top_builddir)/src/libglamor.la +libglamor_egl_la_SOURCES = glamor_eglmodule.c $(top_srcdir)/src/glamor_egl.c +libglamor_egl_la_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/src $(LIBDRM_CFLAGS) $(EGL_CFLAGS) +endif + + diff --git a/src/glamor.c b/src/glamor.c new file mode 100644 index 0000000..c96795c --- /dev/null +++ b/src/glamor.c @@ -0,0 +1,462 @@ +/* + * 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; +} + +_X_EXPORT void +glamor_set_pixmap_texture(PixmapPtr pixmap, int w, int h, unsigned int tex) +{ + ScreenPtr screen = pixmap->drawable.pScreen; + glamor_pixmap_private *pixmap_priv; + glamor_screen_private *glamor_priv = + glamor_get_screen_private(screen); + + pixmap_priv = glamor_get_pixmap_private(pixmap); + if (pixmap_priv == NULL) { + pixmap_priv = calloc(sizeof(*pixmap_priv), 1); + dixSetPrivate(&pixmap->devPrivates, + glamor_pixmap_private_key, pixmap_priv); + pixmap_priv->container = pixmap; + pixmap_priv->glamor_priv = glamor_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; + } + + if (pixmap->devKind == 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_screen_private *glamor_priv = + glamor_get_screen_private(screen); + + glamor_set_pixmap_texture(pixmap, w, h, tex); + pixmap_priv = glamor_get_pixmap_private(pixmap); + glamor_priv->screen_fbo = pixmap_priv->fb; +} + + + +#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); + + pixmap_priv = calloc(1, sizeof(*pixmap_priv)); + dixSetPrivate(&pixmap->devPrivates, glamor_pixmap_private_key, + pixmap_priv); + 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; +} + +void +glamor_destroy_textured_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 != NULL) { + 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); + free(pixmap_priv); + } + } +} + +static Bool +glamor_destroy_pixmap(PixmapPtr pixmap) +{ + glamor_destroy_textured_pixmap(pixmap); + return fbDestroyPixmap(pixmap); +} + +void +glamor_block_handler(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv = + glamor_get_screen_private(screen); + glamor_gl_dispatch *dispatch = &glamor_priv->dispatch; + + dispatch->glFlush(); +} + +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, 0)) { + LogMessage(X_WARNING, + "glamor%d: Failed to allocate pixmap private\n", + screen->myNum); + goto fail;; + } + + gl_version = glamor_gl_get_version(); + +#ifndef GLAMOR_GLES2 + if (gl_version < GLAMOR_GL_VERSION_ENCODE(1, 3)) { + ErrorF("Require OpenGL version 1.3 or latter.\n"); + goto fail; + } +#else + if (gl_version < GLAMOR_GL_VERSION_ENCODE(2, 0)) { + ErrorF("Require Open GLES2.0 or latter.\n"); + goto fail; + } +#endif + + glamor_gl_dispatch_init(screen, &glamor_priv->dispatch, + gl_version); + +#ifdef GLAMOR_GLES2 + if (!glamor_gl_has_extension("GL_EXT_texture_format_BGRA8888")) { + ErrorF("GL_EXT_texture_format_BGRA8888 required\n"); + goto fail; + } +#endif + + glamor_priv->has_pack_invert = + glamor_gl_has_extension("GL_MESA_pack_invert"); + glamor_priv->has_fbo_blit = + glamor_gl_has_extension("GL_EXT_framebuffer_blit"); + glamor_priv->dispatch.glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, + &glamor_priv->max_fbo_size); + + if (!RegisterBlockAndWakeupHandlers(_glamor_block_handler, + _glamor_wakeup_handler, + (void *) + &glamor_priv->dispatch)) { + goto fail; + } + + glamor_set_debug_level(&glamor_debug_level); + + if (flags & GLAMOR_USE_SCREEN) { + 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 + if (flags & GLAMOR_USE_PICTURE_SCREEN) { + 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_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; + } + + glamor_init_composite_shaders(screen); +#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/src/glamor.h b/src/glamor.h new file mode 100644 index 0000000..f9da4ad --- /dev/null +++ b/src/glamor.h @@ -0,0 +1,81 @@ +/* + * 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_USE_SCREEN 2 +#define GLAMOR_USE_PICTURE_SCREEN 4 + +#define GLAMOR_VALID_FLAGS (GLAMOR_INVERTED_Y_AXIS \ + | GLAMOR_USE_SCREEN \ + | GLAMOR_USE_PICTURE_SCREEN) + +#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); + +extern _X_EXPORT void glamor_destroy_textured_pixmap(PixmapPtr pixmap); +extern _X_EXPORT void glamor_block_handler(ScreenPtr screen); + +#ifdef GLAMOR_FOR_XORG +extern _X_EXPORT Bool glamor_egl_init(ScrnInfoPtr scrn, int fd); +extern _X_EXPORT Bool glamor_egl_create_textured_screen(ScreenPtr screen, + int handle, + int stride); +extern _X_EXPORT Bool glamor_egl_create_textured_pixmap(PixmapPtr pixmap, + int handle, + int stride); + +extern _X_EXPORT Bool glamor_egl_close_screen(ScreenPtr screen); +extern _X_EXPORT void glamor_egl_free_screen(int scrnIndex, int flags); + +extern _X_EXPORT Bool glamor_egl_init_textured_pixmap(ScreenPtr screen); +extern _X_EXPORT void glamor_egl_destroy_textured_pixmap(PixmapPtr pixmap); +#endif diff --git a/src/glamor_copyarea.c b/src/glamor_copyarea.c new file mode 100644 index 0000000..b49d816 --- /dev/null +++ b/src/glamor_copyarea.c @@ -0,0 +1,440 @@ +/* + * 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/src/glamor_copywindow.c b/src/glamor_copywindow.c new file mode 100644 index 0000000..11b3036 --- /dev/null +++ b/src/glamor_copywindow.c @@ -0,0 +1,62 @@ +/* + * 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/src/glamor_core.c b/src/glamor_core.c new file mode 100644 index 0000000..8ba938f --- /dev/null +++ b/src/glamor_core.c @@ -0,0 +1,542 @@ +/* + * 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/src/glamor_debug.h b/src/glamor_debug.h new file mode 100644 index 0000000..b101749 --- /dev/null +++ b/src/glamor_debug.h @@ -0,0 +1,83 @@ +#ifndef __GLAMOR_DEBUG_H__ +#define __GLAMOR_DEBUG_H__ + + +#define GLAMOR_DELAYED_STRING_MAX 64 + +#define GLAMOR_DEBUG_NONE 0 +#define GLAMOR_DEBUG_UNIMPL 0 +#define GLAMOR_DEBUG_FALLBACK 1 +#define GLAMOR_DEBUG_TEXTURE_DOWNLOAD 2 +#define GLAMOR_DEBUG_TEXTURE_DYNAMIC_UPLOAD 3 + +extern void +AbortServer(void) + _X_NORETURN; + +#define GLAMOR_PANIC(_format_, ...) \ + do { \ + LogMessageVerb(X_NONE, 0, "Glamor Fatal Error" \ + " at %32s line %d: " _format_ "\n", \ + __FUNCTION__, __LINE__, \ + ##__VA_ARGS__ ); \ + exit(1); \ + } while(0) + + + + +#define __debug_output_message(_format_, _prefix_, ...) \ + LogMessageVerb(X_NONE, 0, \ + "%32s:\t" _format_ , \ + /*_prefix_,*/ \ + __FUNCTION__, \ + ##__VA_ARGS__) + +#define glamor_debug_output(_level_, _format_,...) \ + do { \ + if (glamor_debug_level >= _level_) \ + __debug_output_message(_format_, \ + "Glamor debug", \ + ##__VA_ARGS__); \ + } while(0) + + +#define glamor_fallback(_format_,...) \ + do { \ + if (glamor_debug_level >= GLAMOR_DEBUG_FALLBACK) \ + __debug_output_message(_format_, \ + "Glamor fallback", \ + ##__VA_ARGS__);} while(0) + + + +#define glamor_delayed_fallback(_screen_, _format_,...) \ + do { \ + if (glamor_debug_level >= GLAMOR_DEBUG_FALLBACK) { \ + glamor_screen_private *_glamor_priv_; \ + _glamor_priv_ = glamor_get_screen_private(_screen_); \ + _glamor_priv_->delayed_fallback_pending = 1; \ + snprintf(_glamor_priv_->delayed_fallback_string, \ + GLAMOR_DELAYED_STRING_MAX, \ + "glamor delayed fallback: \t%s " _format_ , \ + __FUNCTION__, ##__VA_ARGS__); } } while(0) + + +#define glamor_clear_delayed_fallbacks(_screen_) \ + do { \ + if (glamor_debug_level >= GLAMOR_DEBUG_FALLBACK) { \ + glamor_screen_private *_glamor_priv_; \ + _glamor_priv_ = glamor_get_screen_private(_screen_); \ + _glamor_priv_->delayed_fallback_pending = 0; } } while(0) + +#define glamor_report_delayed_fallbacks(_screen_) \ + do { \ + if (glamor_debug_level >= GLAMOR_DEBUG_FALLBACK) { \ + glamor_screen_private *_glamor_priv_; \ + _glamor_priv_ = glamor_get_screen_private(_screen_); \ + LogMessageVerb(X_INFO, 0, "%s", \ + _glamor_priv_->delayed_fallback_string); \ + _glamor_priv_->delayed_fallback_pending = 0; } } while(0) + + +#endif diff --git a/src/glamor_egl.c b/src/glamor_egl.c new file mode 100644 index 0000000..9e4804a --- /dev/null +++ b/src/glamor_egl.c @@ -0,0 +1,449 @@ +/* + * 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 DevPrivateKeyRec glamor_egl_pixmap_private_key_index; +DevPrivateKey glamor_egl_pixmap_private_key = + &glamor_egl_pixmap_private_key_index; + +static void +glamor_identify(int flags) +{ + xf86Msg(X_INFO, "%s: OpenGL accelerated X.org driver based.\n", + glamor_name); +} + +struct glamor_egl_screen_private { + EGLDisplay display; + EGLContext context; + 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_egl_get_screen_private(ScrnInfoPtr scrn) +{ + return (struct glamor_egl_screen_private *) + scrn->privates[xf86GlamorEGLPrivateIndex].ptr; +} + +static EGLImageKHR +_glamor_egl_create_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_egl_create_textured_screen(ScreenPtr screen, int handle, int stride) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + struct glamor_egl_screen_private *glamor_egl = + glamor_egl_get_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_egl_create_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 textured screen. + * XXX the egl image here is not stored at any data structure. + * Does this cause a leak problem? + */ +Bool +glamor_egl_create_textured_pixmap(PixmapPtr pixmap, int handle, int stride) +{ + ScreenPtr screen = pixmap->drawable.pScreen; + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + struct glamor_egl_screen_private *glamor_egl = + glamor_egl_get_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_egl_create_image(glamor_egl, + pixmap->drawable.width, + pixmap->drawable.height, stride, + name); + if (image == EGL_NO_IMAGE_KHR) { + ErrorF("Failed to create khr image for bo handle %d.\n", handle); + return FALSE; + } + + glamor_create_texture_from_image(glamor_egl, image, &texture); + glamor_set_pixmap_texture(pixmap, pixmap->drawable.width, + pixmap->drawable.height, texture); + dixSetPrivate(&pixmap->devPrivates, glamor_egl_pixmap_private_key, + image); + return TRUE; +} + +void +glamor_egl_destroy_textured_pixmap(PixmapPtr pixmap) +{ + EGLImageKHR image; + ScrnInfoPtr scrn = xf86Screens[pixmap->drawable.pScreen->myNum]; + struct glamor_egl_screen_private *glamor_egl = + glamor_egl_get_screen_private(scrn); + + if (pixmap->refcnt == 1) { + image = dixLookupPrivate(&pixmap->devPrivates, + glamor_egl_pixmap_private_key); + if (image != EGL_NO_IMAGE_KHR) + eglDestroyImageKHR(glamor_egl->display, image); + } + glamor_destroy_textured_pixmap(pixmap); +} + +Bool +glamor_egl_close_screen(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + struct glamor_egl_screen_private *glamor_egl = + glamor_egl_get_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; +} + +Bool +glamor_egl_init_textured_pixmap(ScreenPtr screen) +{ + if (!dixRegisterPrivateKey + (glamor_egl_pixmap_private_key, PRIVATE_PIXMAP, 0)) { + LogMessage(X_WARNING, + "glamor%d: Failed to allocate egl pixmap private\n", + screen->myNum); + return FALSE; + } + return TRUE; +} + +void +glamor_egl_free_screen(int scrnIndex, int flags) +{ + ScrnInfoPtr scrn = xf86Screens[scrnIndex]; + struct glamor_egl_screen_private *glamor_egl = + glamor_egl_get_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); + } +} + +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_egl_get_screen_private(scrn); + if (!glamor_gl_dispatch_init_impl + (dispatch, gl_version, (get_proc_address_t)eglGetProcAddress)) + return FALSE; + glamor_egl->dispatch = dispatch; + return TRUE; +} diff --git a/src/glamor_eglmodule.c b/src/glamor_eglmodule.c new file mode 100644 index 0000000..5281ff4 --- /dev/null +++ b/src/glamor_eglmodule.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 1998 The XFree86 Project, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the XFree86 Project shall + * not be used in advertising or otherwise to promote the sale, use or other + * dealings in this Software without prior written authorization from the + * XFree86 Project. + */ + +#include <xorg-server.h> + +#include "xf86Module.h" + +static XF86ModuleVersionInfo VersRec = { + "glamor_egl", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + 1, 0, 0, + ABI_CLASS_ANSIC, /* Only need the ansic layer */ + ABI_ANSIC_VERSION, + MOD_CLASS_NONE, + {0, 0, 0, 0} /* signature, to be patched into the file by a tool */ +}; + +_X_EXPORT XF86ModuleData glamor_eglModuleData = { &VersRec, NULL, NULL }; diff --git a/src/glamor_fill.c b/src/glamor_fill.c new file mode 100644 index 0000000..7a43251 --- /dev/null +++ b/src/glamor_fill.c @@ -0,0 +1,198 @@ +/* + * 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 + */ + +Bool +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; + 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 TRUE; + 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 TRUE; + +} + +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/src/glamor_fillspans.c b/src/glamor_fillspans.c new file mode 100644 index 0000000..a91e6a9 --- /dev/null +++ b/src/glamor_fillspans.c @@ -0,0 +1,85 @@ +/* + * 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/src/glamor_getspans.c b/src/glamor_getspans.c new file mode 100644 index 0000000..96f5120 --- /dev/null +++ b/src/glamor_getspans.c @@ -0,0 +1,106 @@ +/* + * 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/src/glamor_gl_dispatch.c b/src/glamor_gl_dispatch.c new file mode 100644 index 0000000..788562c --- /dev/null +++ b/src/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 function %s", #func_name); \ + goto fail; } + +_X_EXPORT Bool +glamor_gl_dispatch_init_impl(struct glamor_gl_dispatch *dispatch, + int gl_version, + void *(*get_proc_address) (const char *)) +{ + 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/src/glamor_gl_dispatch.h b/src/glamor_gl_dispatch.h new file mode 100644 index 0000000..5f1831a --- /dev/null +++ b/src/glamor_gl_dispatch.h @@ -0,0 +1,123 @@ +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; + + +typedef void *(*get_proc_address_t) (const char *); + +_X_EXPORT Bool +glamor_gl_dispatch_init_impl(struct glamor_gl_dispatch *dispatch, + int gl_version, + get_proc_address_t get_proc_address); + + +_X_EXPORT Bool +glamor_gl_dispatch_init(ScreenPtr screen, + struct glamor_gl_dispatch *dispatch, + int gl_version); diff --git a/src/glamor_glext.h b/src/glamor_glext.h new file mode 100644 index 0000000..f734d13 --- /dev/null +++ b/src/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/src/glamor_glyphs.c b/src/glamor_glyphs.c new file mode 100644 index 0000000..899dd9d --- /dev/null +++ b/src/glamor_glyphs.c @@ -0,0 +1,851 @@ +/* + * 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/src/glamor_picture.c b/src/glamor_picture.c new file mode 100644 index 0000000..9e8d6ec --- /dev/null +++ b/src/glamor_picture.c @@ -0,0 +1,96 @@ +#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/src/glamor_pixmap.c b/src/glamor_pixmap.c new file mode 100644 index 0000000..f02acc7 --- /dev/null +++ b/src/glamor_pixmap.c @@ -0,0 +1,821 @@ +#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/src/glamor_pixmap.indent.c b/src/glamor_pixmap.indent.c new file mode 100644 index 0000000..f02acc7 --- /dev/null +++ b/src/glamor_pixmap.indent.c @@ -0,0 +1,821 @@ +#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/src/glamor_polyfillrect.c b/src/glamor_polyfillrect.c new file mode 100644 index 0000000..762dfc2 --- /dev/null +++ b/src/glamor_polyfillrect.c @@ -0,0 +1,107 @@ +/* + * 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; + if (!glamor_fill(drawable, gc, x1, y1, x2 - x1, + y2 - y1)) + goto fail; + } + } + 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); + } + return; +} diff --git a/src/glamor_polylines.c b/src/glamor_polylines.c new file mode 100644 index 0000000..01124bb --- /dev/null +++ b/src/glamor_polylines.c @@ -0,0 +1,175 @@ +/* + * 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/src/glamor_priv.h b/src/glamor_priv.h new file mode 100644 index 0000000..66c4359 --- /dev/null +++ b/src/glamor_priv.h @@ -0,0 +1,553 @@ +/* + * 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 <xorg-server.h> + +#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 */ +Bool 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/src/glamor_putimage.c b/src/glamor_putimage.c new file mode 100644 index 0000000..a8cafed --- /dev/null +++ b/src/glamor_putimage.c @@ -0,0 +1,405 @@ +/* + * 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/src/glamor_render.c b/src/glamor_render.c new file mode 100644 index 0000000..7f52c7b --- /dev/null +++ b/src/glamor_render.c @@ -0,0 +1,1531 @@ +/* + * 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(®ion, + 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(®ion), + REGION_NUM_RECTS(®ion), + x_source - x_dest, y_source - y_dest, + FALSE, FALSE, 0, NULL); + REGION_UNINIT(dest->pDrawable->pScreen, ®ion); + 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(®ion, + 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(®ion); + for (i = 0; i < REGION_NUM_RECTS(®ion); 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, ®ion); + 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/src/glamor_setspans.c b/src/glamor_setspans.c new file mode 100644 index 0000000..61163ce --- /dev/null +++ b/src/glamor_setspans.c @@ -0,0 +1,106 @@ +/* + * 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/src/glamor_tile.c b/src/glamor_tile.c new file mode 100644 index 0000000..bd5192c --- /dev/null +++ b/src/glamor_tile.c @@ -0,0 +1,213 @@ +/* + * 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 (src_pixmap_priv == NULL || dst_pixmap_priv == NULL) + goto fail; + + 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/src/glamor_triangles.c b/src/glamor_triangles.c new file mode 100644 index 0000000..3cbdd55 --- /dev/null +++ b/src/glamor_triangles.c @@ -0,0 +1,56 @@ +/* + * 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/src/glamor_utils.h b/src/glamor_utils.h new file mode 100644 index 0000000..265d9ed --- /dev/null +++ b/src/glamor_utils.h @@ -0,0 +1,549 @@ +#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/src/glamor_window.c b/src/glamor_window.c new file mode 100644 index 0000000..f6e4cd1 --- /dev/null +++ b/src/glamor_window.c @@ -0,0 +1,75 @@ +/* + * 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; +} |