Logo Search packages:      
Sourcecode: beryl-core version File versions

texture.c

/*
 * Copyright © 2005 Novell, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Author: David Reveman <davidr@novell.com>
 */

#ifdef HAVE_CONFIG_H
#  include "../config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <beryl.h>
#include <beryl-private.h>

static CompMatrix _identity_matrix = {
      1.0f, 0.0f,
      0.0f, 1.0f,
      0.0f, 0.0f
};

void initTexture(CompScreen * screen, CompTexture * texture)
{
      if (copyTexture)
            texture->mode = TEXTURE_MODE_COPY_DAMAGE;
      else
            texture->mode = TEXTURE_MODE_TFP;

      texture->refCount = 1;
      texture->name = 0;
      texture->target = GL_TEXTURE_2D;
      texture->pixmap = None;
      texture->filter = GL_NEAREST;
      texture->wrap = GL_CLAMP_TO_EDGE;
      texture->matrix = _identity_matrix;
      texture->oldMipmaps = TRUE;
      texture->mipmap = FALSE;

      texture->cmd.width = 0;
      texture->cmd.height = 0;
      texture->cmd.depth = 0;
      texture->cmd.damaged = TRUE;
      texture->cmd.fullDamage = TRUE;
      texture->cmd.damage.x1 = 0;
      texture->cmd.damage.x2 = 0;
      texture->cmd.damage.y1 = 0;
      texture->cmd.damage.y2 = 0;
}

void finiTexture(CompScreen * screen, CompTexture * texture)
{
      if (texture->name)
      {
            releasePixmapFromTexture(screen, texture);
            glDeleteTextures(1, &texture->name);
      }
}

CompTexture *createTexture(CompScreen * screen)
{
      CompTexture *texture;

      texture = (CompTexture *) malloc(sizeof(CompTexture));
      if (!texture)
            return NULL;

      initTexture(screen, texture);

      return texture;
}

void destroyTexture(CompScreen * screen, CompTexture * texture)
{
      texture->refCount--;
      if (texture->refCount)
            return;

      finiTexture(screen, texture);

      free(texture);
}

Bool
imageToTexture(CompScreen * screen,
                     CompTexture * texture,
                     char *image, unsigned int width, unsigned int height)
{
      char *data;
      int i;

      data = malloc(4 * width * height);
      if (!data)
            return FALSE;

      for (i = 0; i < height; i++)
            memcpy(&data[i * width * 4],
                     &image[(height - i - 1) * width * 4], width * 4);

      releasePixmapFromTexture(screen, texture);

      if (screen->textureNonPowerOfTwo ||
            (POWER_OF_TWO(width) && POWER_OF_TWO(height)))
      {
            texture->target = GL_TEXTURE_2D;
            texture->matrix.xx = 1.0f / width;
            texture->matrix.yy = -1.0f / height;
            texture->matrix.y0 = 1.0f;
      }
      else
      {
            texture->target = GL_TEXTURE_RECTANGLE_NV;
            texture->matrix.xx = 1.0f;
            texture->matrix.yy = -1.0f;
            texture->matrix.y0 = height;
      }

      if (!texture->name)
            glGenTextures(1, &texture->name);

      glBindTexture(texture->target, texture->name);

      glTexImage2D(texture->target, 0, GL_RGBA, width, height, 0, GL_BGRA,
#if IMAGE_BYTE_ORDER == MSBFirst
                         GL_UNSIGNED_INT_8_8_8_8_REV,
#else
                         GL_UNSIGNED_BYTE,
#endif
                         data);

      texture->filter = GL_NEAREST;

      glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

      glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
      glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

      texture->wrap = GL_CLAMP_TO_EDGE;
      texture->mipmap = TRUE;

      glBindTexture(texture->target, 0);

      free(data);

      return TRUE;
}

// for hardcoded textures only
Bool
RGBAimageToTexture(CompScreen * screen,
                     CompTexture * texture,
                     char *image, unsigned int width, unsigned int height)
{
      char *data;
      int i;

      data = malloc(4 * width * height);
      if (!data)
            return FALSE;

      for (i = 0; i < height; i++)
            memcpy(&data[i * width * 4],
                     &image[(height - i - 1) * width * 4], width * 4);

      releasePixmapFromTexture(screen, texture);

      if (screen->textureNonPowerOfTwo ||
            (POWER_OF_TWO(width) && POWER_OF_TWO(height)))
      {
            texture->target = GL_TEXTURE_2D;
            texture->matrix.xx = 1.0f / width;
            texture->matrix.yy = -1.0f / height;
            texture->matrix.y0 = 1.0f;
      }
      else
      {
            texture->target = GL_TEXTURE_RECTANGLE_NV;
            texture->matrix.xx = 1.0f;
            texture->matrix.yy = -1.0f;
            texture->matrix.y0 = height;
      }

      if (!texture->name)
            glGenTextures(1, &texture->name);

      glBindTexture(texture->target, texture->name);

      glTexImage2D(texture->target, 0, GL_RGBA, width, height, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, data);

      texture->filter = GL_NEAREST;

      glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

      glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
      glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

      texture->wrap = GL_CLAMP_TO_EDGE;
      texture->mipmap = TRUE;

      glBindTexture(texture->target, 0);

      free(data);

      return TRUE;
}

Bool
readImageToTexture(CompScreen * screen,
                           CompTexture * texture,
                           const char *imageFileName,
                           unsigned int *returnWidth, unsigned int *returnHeight)
{
      void *image;
      int width, height;
      Bool status;

      if (!readImageFromFile(screen->display, imageFileName,
                                       &width, &height, &image))
            return FALSE;

      status = imageToTexture(screen, texture, image, width, height);

      free(image);

      if (returnWidth)
            *returnWidth = width;
      if (returnHeight)
            *returnHeight = height;

      return status;
}

Bool iconToTexture(CompScreen * screen, CompIcon * icon)
{
      return imageToTexture(screen,
                                      &icon->texture,
                                      (char *)(icon + 1), icon->width, icon->height);
}

Bool
bindPixmapToTexture(CompScreen * screen,
                              CompTexture * texture,
                              Pixmap pixmap, int width, int height, int depth)
{
      XVisualInfo *visinfo;
      unsigned int target;
      CompFBConfig *config = &screen->glxPixmapFBConfigs[depth];
      int attribs[] = {
            GLX_TEXTURE_FORMAT_EXT, config->textureFormat,
            GLX_MIPMAP_TEXTURE_EXT, config->mipmap,
            None
      };

      if (texture->mode & (TEXTURE_MODE_COPY | TEXTURE_MODE_COPY_DAMAGE))
      {
            if (texture->name && texture->cmd.width == width
                  && texture->cmd.height == height)
                  return TRUE;
            if (!texture->name)
            {
                  glGenTextures(1, &texture->name);
            }
            texture->pixmap = pixmap;
            texture->cmd.width = width;
            texture->cmd.height = height;
            texture->cmd.depth = depth;

            texture->target = GL_TEXTURE_RECTANGLE_ARB;

            glBindTexture(texture->target, texture->name);

            texture->filter = GL_NEAREST;

            glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
            glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

            glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

            texture->wrap = GL_CLAMP_TO_EDGE;

            texture->matrix.xx = 1.0f;
            texture->matrix.yy = 1.0f;
            texture->matrix.y0 = 0;

            if (depth == 32)
                  glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
                                     width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
            else
                  glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB,
                                     width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);

            glBindTexture(texture->target, 0);

            return TRUE;
      }

      if (screen->useFBConfig)
      {
            if (!config->fbConfig)
            {
                  fprintf(stderr,
                              _("%s: No GLXFBConfig for depth %d\n"),
                              programName, depth);

                  return FALSE;
            }
      }
      else
      {
            visinfo = screen->glxPixmapVisuals[depth];
            if (!visinfo)
            {
                  fprintf(stderr,
                              _("%s: No GL visual for depth %d\n"), programName, depth);

                  return FALSE;
            }
      }

      if (screen->useFBConfig)
            texture->pixmap =
                        (*screen->createPixmap) (screen->display->display,
                                                             config->fbConfig, pixmap, attribs);
      else
            texture->pixmap =
                        glXCreateGLXPixmap(screen->display->display, visinfo, pixmap);

      if (!texture->pixmap)
      {
            fprintf(stderr, _("%s: glXCreate[GLX]Pixmap failed\n"), programName);

            return FALSE;
      }

      if (screen->useFBConfig)
            texture->mipmap = config->mipmap;

      target = 0;
      (*screen->queryDrawable) (screen->display->display,
                                            texture->pixmap,
                                            GLX_TEXTURE_TARGET_EXT, &target);
      switch (target)
      {
      case GLX_TEXTURE_2D_EXT:
            texture->target = GL_TEXTURE_2D;

            texture->matrix.xx = 1.0f / width;
            texture->matrix.yy = -1.0f / height;
            texture->matrix.y0 = 1.0f;
            if (screen->useFBConfig ? config->yInverted : indirectRendering)
            {
                  texture->matrix.yy = 1.0f / height;
                  texture->matrix.y0 = 0;
            }
            break;
      case GLX_TEXTURE_RECTANGLE_EXT:
            texture->target = GL_TEXTURE_RECTANGLE_ARB;

            texture->matrix.xx = 1.0f;
            texture->matrix.yy = -1.0f;
            texture->matrix.y0 = height;
            if (screen->useFBConfig ? config->yInverted : indirectRendering)
            {
                  texture->matrix.yy = 1.0f;
                  texture->matrix.y0 = 0;
            }
            break;
      default:
            fprintf(stderr,
                        _("%s: pixmap 0x%x can't be bound to texture\n"),
                        programName, (int)pixmap);

            glXDestroyGLXPixmap(screen->display->display, texture->pixmap);
            texture->pixmap = None;

            return FALSE;
      }

      if (!texture->name)
            glGenTextures(1, &texture->name);

      glBindTexture(texture->target, texture->name);

      if (!strictBinding)
      {
            (*screen->bindTexImage) (screen->display->display,
                                                 texture->pixmap, GLX_FRONT_LEFT_EXT, NULL);
      }

      texture->filter = GL_NEAREST;

      glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

      glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
      glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

      texture->wrap = GL_CLAMP_TO_EDGE;

      glBindTexture(texture->target, 0);

      return TRUE;
}

void releasePixmapFromTexture(CompScreen * screen, CompTexture * texture)
{
      if (texture->pixmap && texture->mode == TEXTURE_MODE_TFP)
      {
            glEnable(texture->target);
            if (!strictBinding)
            {
                  glBindTexture(texture->target, texture->name);

                  (*screen->releaseTexImage) (screen->display->
                                                            display,
                                                            texture->pixmap, GLX_FRONT_LEFT_EXT);
            }

            glBindTexture(texture->target, 0);
            glDisable(texture->target);

            glXDestroyGLXPixmap(screen->display->display, texture->pixmap);

            texture->pixmap = None;
      }
      if (texture->mode & (TEXTURE_MODE_COPY | TEXTURE_MODE_COPY_DAMAGE))
      {
            if (texture->name)
                  glDeleteTextures(1, &texture->name);
            texture->name = 0;
            texture->pixmap = None;
      }
}

void
enableTexture(CompScreen * screen,
                    CompTexture * texture, CompTextureFilter filter)
{
      glEnable(texture->target);
      glBindTexture(texture->target, texture->name);

      if (strictBinding && texture->mode == TEXTURE_MODE_TFP)
      {
            (*screen->bindTexImage) (screen->display->display,
                                                 texture->pixmap, GLX_FRONT_LEFT_EXT, NULL);
      }
      if (texture->mode == TEXTURE_MODE_COPY
            || (texture->mode == TEXTURE_MODE_COPY_DAMAGE
                  && texture->cmd.damaged))
      {
            CompDisplay *d = screen->display;
            char *addr = 0;
            Pixmap tmpPix;
            Display *dpy = screen->display->display;

            XGCValues gcv;
            GC gc;

            gcv.graphics_exposures = FALSE;
            gcv.subwindow_mode = IncludeInferiors;
            gc = XCreateGC(dpy, texture->pixmap,
                                 GCGraphicsExposures | GCSubwindowMode, &gcv);

            XImage *image = 0;

            Bool shmMode = !noShm &&
                        (texture->cmd.width * texture->cmd.height * 4 < SHM_SIZE);

            int width = texture->cmd.width;
            int height = texture->cmd.height;
            int x = 0;
            int y = 0;

            if (texture->mode == TEXTURE_MODE_COPY_DAMAGE
                  && !texture->cmd.fullDamage)
            {
                  width = texture->cmd.damage.x2 - texture->cmd.damage.x1;
                  height = texture->cmd.damage.y2 - texture->cmd.damage.y1;
                  x = texture->cmd.damage.x1;
                  y = texture->cmd.damage.y1;
            }

            if (width <= 0 || height <= 0)
                  return;

            if (shmMode)
                  tmpPix = XShmCreatePixmap(dpy, texture->pixmap,
                                                        d->shmInfo.shmaddr,
                                                        &d->shmInfo, width, height,
                                                        texture->cmd.depth);
            else
                  tmpPix = XCreatePixmap(dpy, texture->pixmap, width,
                                                   height, texture->cmd.depth);

            if (tmpPix == None)
            {
                  fprintf(stderr,
                              _("%s: Cannot create Pixmap for copy\n"), programName);
                  return;
            }

            XCopyArea(dpy, texture->pixmap, tmpPix, gc, x, y, width,
                          height, 0, 0);
            XSync(dpy, FALSE);

            if (shmMode)
                  addr = d->shmInfo.shmaddr;
            else
            {
                  image = XGetImage(dpy, tmpPix, 0, 0, width, height,
                                            AllPlanes, ZPixmap);
                  if (image)
                        addr = image->data;
            }

            glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, x, y, width,
                                    height, GL_BGRA,
#if IMAGE_BYTE_ORDER == MSBFirst
                                    GL_UNSIGNED_INT_8_8_8_8_REV,
#else
                                    GL_UNSIGNED_BYTE,
#endif
                                    addr);

            texture->cmd.damaged = FALSE;
            texture->cmd.fullDamage = FALSE;
            XFreePixmap(dpy, tmpPix);
            XFreeGC(dpy, gc);
            if (image)
                  XDestroyImage(image);
      }

      if (filter == COMP_TEXTURE_FILTER_FAST)
      {
            if (texture->filter != GL_NEAREST)
            {
                  glTexParameteri(texture->target,
                                          GL_TEXTURE_MIN_FILTER, GL_NEAREST);
                  glTexParameteri(texture->target,
                                          GL_TEXTURE_MAG_FILTER, GL_NEAREST);

                  texture->filter = GL_NEAREST;
            }
      }
      else if (texture->filter != screen->display->textureFilter)
      {
            if (screen->display->textureFilter == GL_LINEAR_MIPMAP_LINEAR)
            {
                  if (screen->textureNonPowerOfTwo && screen->fbo
                        && texture->mipmap)
                  {
                        glTexParameteri(texture->target,
                                                GL_TEXTURE_MIN_FILTER,
                                                GL_LINEAR_MIPMAP_LINEAR);

                        if (texture->filter != GL_LINEAR)
                              glTexParameteri(texture->target,
                                                      GL_TEXTURE_MAG_FILTER, GL_LINEAR);

                        texture->filter = GL_LINEAR_MIPMAP_LINEAR;
                  }
                  else if (texture->filter != GL_LINEAR)
                  {
                        glTexParameteri(texture->target,
                                                GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                        glTexParameteri(texture->target,
                                                GL_TEXTURE_MAG_FILTER, GL_LINEAR);

                        texture->filter = GL_LINEAR;
                  }
            }
            else
            {
                  glTexParameteri(texture->target,
                                          GL_TEXTURE_MIN_FILTER,
                                          screen->display->textureFilter);
                  glTexParameteri(texture->target,
                                          GL_TEXTURE_MAG_FILTER,
                                          screen->display->textureFilter);

                  texture->filter = screen->display->textureFilter;
            }
      }

      if (texture->filter == GL_LINEAR_MIPMAP_LINEAR)
      {
            if (texture->oldMipmaps)
            {
                  (*screen->generateMipmap) (texture->target);
                  texture->oldMipmaps = FALSE;
            }
      }
}

void disableTexture(CompScreen * screen, CompTexture * texture)
{
      if (strictBinding && texture->mode == TEXTURE_MODE_TFP)
      {
            glBindTexture(texture->target, texture->name);

            (*screen->releaseTexImage) (screen->display->display,
                                                      texture->pixmap, GLX_FRONT_LEFT_EXT);
      }

      glBindTexture(texture->target, 0);
      glDisable(texture->target);
}

Generated by  Doxygen 1.6.0   Back to index