Compare commits
	
		
			1 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 2b8e75ad48 | 
| @@ -65,8 +65,6 @@ libmutter_la_SOURCES =				\ | ||||
| 	compositor/meta-shaped-texture.c	\ | ||||
| 	compositor/meta-texture-rectangle.c	\ | ||||
| 	compositor/meta-texture-rectangle.h	\ | ||||
| 	compositor/meta-texture-tower.c		\ | ||||
| 	compositor/meta-texture-tower.h		\ | ||||
| 	compositor/meta-window-actor.c		\ | ||||
| 	compositor/meta-window-actor-private.h	\ | ||||
| 	compositor/meta-window-group.c		\ | ||||
|   | ||||
| @@ -1,10 +0,0 @@ | ||||
| Intro | ||||
| ===== | ||||
|  | ||||
| Fix me. | ||||
|  | ||||
|  | ||||
| Env Vars | ||||
| ======== | ||||
|  | ||||
| MUTTER_DISABLE_MIPMAPS - set to disable use of mipmaped windows. | ||||
| @@ -31,7 +31,6 @@ struct _MetaCompositor | ||||
|   guint           server_time_is_monotonic_time : 1; | ||||
|   guint           show_redraw : 1; | ||||
|   guint           debug       : 1; | ||||
|   guint           no_mipmaps  : 1; | ||||
| }; | ||||
|  | ||||
| struct _MetaCompScreen | ||||
|   | ||||
| @@ -1532,9 +1532,6 @@ meta_compositor_new (MetaDisplay *display) | ||||
|  | ||||
|   compositor->display = display; | ||||
|  | ||||
|   if (g_getenv("META_DISABLE_MIPMAPS")) | ||||
|     compositor->no_mipmaps = TRUE; | ||||
|  | ||||
|   meta_verbose ("Creating %d atoms\n", (int) G_N_ELEMENTS (atom_names)); | ||||
|   XInternAtoms (xdisplay, atom_names, G_N_ELEMENTS (atom_names), | ||||
|                 False, atoms); | ||||
|   | ||||
| @@ -30,7 +30,6 @@ | ||||
| #include <config.h> | ||||
|  | ||||
| #include <meta/meta-shaped-texture.h> | ||||
| #include "meta-texture-tower.h" | ||||
|  | ||||
| #include <clutter/clutter.h> | ||||
| #include <cogl/cogl.h> | ||||
| @@ -64,7 +63,6 @@ G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture, | ||||
|  | ||||
| struct _MetaShapedTexturePrivate | ||||
| { | ||||
|   MetaTextureTower *paint_tower; | ||||
|   Pixmap pixmap; | ||||
|   CoglTexturePixmapX11 *texture; | ||||
|   CoglTexture *mask_texture; | ||||
| @@ -74,8 +72,6 @@ struct _MetaShapedTexturePrivate | ||||
|   cairo_region_t *clip_region; | ||||
|  | ||||
|   guint tex_width, tex_height; | ||||
|  | ||||
|   guint create_mipmaps : 1; | ||||
| }; | ||||
|  | ||||
| static void | ||||
| @@ -102,10 +98,8 @@ meta_shaped_texture_init (MetaShapedTexture *self) | ||||
|  | ||||
|   priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self); | ||||
|  | ||||
|   priv->paint_tower = meta_texture_tower_new (); | ||||
|   priv->texture = NULL; | ||||
|   priv->mask_texture = NULL; | ||||
|   priv->create_mipmaps = TRUE; | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -114,10 +108,6 @@ meta_shaped_texture_dispose (GObject *object) | ||||
|   MetaShapedTexture *self = (MetaShapedTexture *) object; | ||||
|   MetaShapedTexturePrivate *priv = self->priv; | ||||
|  | ||||
|   if (priv->paint_tower) | ||||
|     meta_texture_tower_free (priv->paint_tower); | ||||
|   priv->paint_tower = NULL; | ||||
|  | ||||
|   g_clear_pointer (&priv->pipeline, cogl_object_unref); | ||||
|   g_clear_pointer (&priv->pipeline_unshaped, cogl_object_unref); | ||||
|   g_clear_pointer (&priv->texture, cogl_object_unref); | ||||
| @@ -133,7 +123,6 @@ meta_shaped_texture_paint (ClutterActor *actor) | ||||
| { | ||||
|   MetaShapedTexture *stex = (MetaShapedTexture *) actor; | ||||
|   MetaShapedTexturePrivate *priv = stex->priv; | ||||
|   CoglTexture *paint_tex; | ||||
|   guint tex_width, tex_height; | ||||
|   ClutterActorBox alloc; | ||||
|  | ||||
| @@ -148,29 +137,6 @@ meta_shaped_texture_paint (ClutterActor *actor) | ||||
|   if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex))) | ||||
|     clutter_actor_realize (CLUTTER_ACTOR (stex)); | ||||
|  | ||||
|   /* The GL EXT_texture_from_pixmap extension does allow for it to be | ||||
|    * used together with SGIS_generate_mipmap, however this is very | ||||
|    * rarely supported. Also, even when it is supported there | ||||
|    * are distinct performance implications from: | ||||
|    * | ||||
|    *  - Updating mipmaps that we don't need | ||||
|    *  - Having to reallocate pixmaps on the server into larger buffers | ||||
|    * | ||||
|    * So, we just unconditionally use our mipmap emulation code. If we | ||||
|    * wanted to use SGIS_generate_mipmap, we'd have to  query COGL to | ||||
|    * see if it was supported (no API currently), and then if and only | ||||
|    * if that was the case, set the clutter texture quality to HIGH. | ||||
|    * Setting the texture quality to high without SGIS_generate_mipmap | ||||
|    * support for TFP textures will result in fallbacks to XGetImage. | ||||
|    */ | ||||
|   if (priv->create_mipmaps) | ||||
|     paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower); | ||||
|   else | ||||
|     paint_tex = COGL_TEXTURE (priv->texture); | ||||
|  | ||||
|   if (paint_tex == NULL) | ||||
|     return; | ||||
|  | ||||
|   tex_width = priv->tex_width; | ||||
|   tex_height = priv->tex_height; | ||||
|  | ||||
| @@ -212,7 +178,10 @@ meta_shaped_texture_paint (ClutterActor *actor) | ||||
|       cogl_pipeline_set_layer_texture (pipeline, 1, priv->mask_texture); | ||||
|     } | ||||
|  | ||||
|   cogl_pipeline_set_layer_texture (pipeline, 0, paint_tex); | ||||
|   cogl_pipeline_set_layer_filters (pipeline, 0, | ||||
|                                    COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR, | ||||
|                                    COGL_PIPELINE_FILTER_LINEAR); | ||||
|   cogl_pipeline_set_layer_texture (pipeline, 0, priv->texture); | ||||
|  | ||||
|   { | ||||
|     CoglColor color; | ||||
| @@ -373,28 +342,6 @@ meta_shaped_texture_new (void) | ||||
|   return self; | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex, | ||||
| 					gboolean           create_mipmaps) | ||||
| { | ||||
|   MetaShapedTexturePrivate *priv; | ||||
|  | ||||
|   g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); | ||||
|  | ||||
|   priv = stex->priv; | ||||
|  | ||||
|   create_mipmaps = create_mipmaps != FALSE; | ||||
|  | ||||
|   if (create_mipmaps != priv->create_mipmaps) | ||||
|     { | ||||
|       CoglTexture *base_texture; | ||||
|       priv->create_mipmaps = create_mipmaps; | ||||
|       base_texture = create_mipmaps ? | ||||
|         COGL_TEXTURE (priv->texture) : NULL; | ||||
|       meta_texture_tower_set_base_texture (priv->paint_tower, base_texture); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex, | ||||
|                                       CoglTexture       *mask_texture) | ||||
| @@ -434,8 +381,6 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex, | ||||
|   cogl_texture_pixmap_x11_update_area (priv->texture, | ||||
|                                        x, y, width, height); | ||||
|  | ||||
|   meta_texture_tower_update_area (priv->paint_tower, x, y, width, height); | ||||
|  | ||||
|   clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip); | ||||
| } | ||||
|  | ||||
| @@ -514,10 +459,6 @@ meta_shaped_texture_set_pixmap (MetaShapedTexture *stex, | ||||
|     } | ||||
|   else | ||||
|     set_cogl_texture (stex, NULL); | ||||
|  | ||||
|   if (priv->create_mipmaps) | ||||
|     meta_texture_tower_set_base_texture (priv->paint_tower, | ||||
|                                          COGL_TEXTURE (priv->texture)); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -1,624 +0,0 @@ | ||||
| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | ||||
| /* | ||||
|  * MetaTextureTower | ||||
|  * | ||||
|  * Mipmap emulation by creation of scaled down images | ||||
|  * | ||||
|  * Copyright (C) 2009 Red Hat, 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., 59 Temple Place - Suite 330, Boston, MA | ||||
|  * 02111-1307, USA. | ||||
|  */ | ||||
|  | ||||
| #include <math.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "meta-texture-tower.h" | ||||
| #include "meta-texture-rectangle.h" | ||||
|  | ||||
| #ifndef M_LOG2E | ||||
| #define M_LOG2E 1.4426950408889634074 | ||||
| #endif | ||||
|  | ||||
| #define MAX_TEXTURE_LEVELS 12 | ||||
|  | ||||
| /* If the texture format in memory doesn't match this, then Mesa | ||||
|  * will do the conversion, so things will still work, but it might | ||||
|  * be slow depending on how efficient Mesa is. These should be the | ||||
|  * native formats unless the display is 16bpp. If conversions | ||||
|  * here are a bottleneck, investigate whether we are converting when | ||||
|  * storing window data *into* the texture before adding extra code | ||||
|  * to handle multiple texture formats. | ||||
|  */ | ||||
| #if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||||
| #define TEXTURE_FORMAT COGL_PIXEL_FORMAT_BGRA_8888_PRE | ||||
| #else | ||||
| #define TEXTURE_FORMAT COGL_PIXEL_FORMAT_ARGB_8888_PRE | ||||
| #endif | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|   guint16 x1; | ||||
|   guint16 y1; | ||||
|   guint16 x2; | ||||
|   guint16 y2; | ||||
| } Box; | ||||
|  | ||||
| struct _MetaTextureTower | ||||
| { | ||||
|   int n_levels; | ||||
|   CoglTexture *textures[MAX_TEXTURE_LEVELS]; | ||||
|   CoglOffscreen *fbos[MAX_TEXTURE_LEVELS]; | ||||
|   Box invalid[MAX_TEXTURE_LEVELS]; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * meta_texture_tower_new: | ||||
|  * | ||||
|  * Creates a new texture tower. The base texture has to be set with | ||||
|  * meta_texture_tower_set_base_texture() before use. | ||||
|  * | ||||
|  * Return value: the new texture tower. Free with meta_texture_tower_free() | ||||
|  */ | ||||
| MetaTextureTower * | ||||
| meta_texture_tower_new (void) | ||||
| { | ||||
|   MetaTextureTower *tower; | ||||
|  | ||||
|   tower = g_slice_new0 (MetaTextureTower); | ||||
|  | ||||
|   return tower; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * meta_texture_tower_free: | ||||
|  * @tower: a #MetaTextureTower | ||||
|  * | ||||
|  * Frees a texture tower created with meta_texture_tower_new(). | ||||
|  */ | ||||
| void | ||||
| meta_texture_tower_free (MetaTextureTower *tower) | ||||
| { | ||||
|   g_return_if_fail (tower != NULL); | ||||
|  | ||||
|   meta_texture_tower_set_base_texture (tower, NULL); | ||||
|  | ||||
|   g_slice_free (MetaTextureTower, tower); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * meta_texture_tower_set_base_texture: | ||||
|  * @tower: a #MetaTextureTower | ||||
|  * @texture: the new texture used as a base for scaled down versions | ||||
|  * | ||||
|  * Sets the base texture that is the scaled texture that the | ||||
|  * scaled textures of the tower are derived from. The texture itself | ||||
|  * will be used as level 0 of the tower and will be referenced until | ||||
|  * unset or until the tower is freed. | ||||
|  */ | ||||
| void | ||||
| meta_texture_tower_set_base_texture (MetaTextureTower *tower, | ||||
|                                      CoglTexture      *texture) | ||||
| { | ||||
|   int i; | ||||
|  | ||||
|   g_return_if_fail (tower != NULL); | ||||
|  | ||||
|   if (texture == tower->textures[0]) | ||||
|     return; | ||||
|  | ||||
|   if (tower->textures[0] != NULL) | ||||
|     { | ||||
|       for (i = 1; i < tower->n_levels; i++) | ||||
|         { | ||||
|           if (tower->textures[i] != NULL) | ||||
|             { | ||||
|               cogl_object_unref (tower->textures[i]); | ||||
|               tower->textures[i] = NULL; | ||||
|             } | ||||
|  | ||||
|           if (tower->fbos[i] != NULL) | ||||
|             { | ||||
|               cogl_object_unref (tower->fbos[i]); | ||||
|               tower->fbos[i] = NULL; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|       cogl_object_unref (tower->textures[0]); | ||||
|     } | ||||
|  | ||||
|   tower->textures[0] = texture; | ||||
|  | ||||
|   if (tower->textures[0] != NULL) | ||||
|     { | ||||
|       int width, height; | ||||
|  | ||||
|       cogl_object_ref (tower->textures[0]); | ||||
|  | ||||
|       width = cogl_texture_get_width (tower->textures[0]); | ||||
|       height = cogl_texture_get_height (tower->textures[0]); | ||||
|  | ||||
|       tower->n_levels = 1 + MAX ((int)(M_LOG2E * log (width)), (int)(M_LOG2E * log (height))); | ||||
|       tower->n_levels = MIN(tower->n_levels, MAX_TEXTURE_LEVELS); | ||||
|  | ||||
|       meta_texture_tower_update_area (tower, 0, 0, width, height); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       tower->n_levels = 0; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * meta_texture_tower_update_area: | ||||
|  * @tower: a #MetaTextureTower | ||||
|  * @x: X coordinate of upper left of rectangle that changed | ||||
|  * @y: Y coordinate of upper left of rectangle that changed | ||||
|  * @width: width of rectangle that changed | ||||
|  * @height: height rectangle that changed | ||||
|  * | ||||
|  * Mark a region of the base texture as having changed; the next | ||||
|  * time a scaled down version of the base texture is retrieved, | ||||
|  * the appropriate area of the scaled down texture will be updated. | ||||
|  */ | ||||
| void | ||||
| meta_texture_tower_update_area (MetaTextureTower *tower, | ||||
|                                 int               x, | ||||
|                                 int               y, | ||||
|                                 int               width, | ||||
|                                 int               height) | ||||
| { | ||||
|   int texture_width, texture_height; | ||||
|   Box invalid; | ||||
|   int i; | ||||
|  | ||||
|   g_return_if_fail (tower != NULL); | ||||
|  | ||||
|   if (tower->textures[0] == NULL) | ||||
|     return; | ||||
|  | ||||
|   texture_width = cogl_texture_get_width (tower->textures[0]); | ||||
|   texture_height = cogl_texture_get_height (tower->textures[0]); | ||||
|  | ||||
|   invalid.x1 = x; | ||||
|   invalid.y1 = y; | ||||
|   invalid.x2 = x + width; | ||||
|   invalid.y2 = y + height; | ||||
|  | ||||
|   for (i = 1; i < tower->n_levels; i++) | ||||
|     { | ||||
|       texture_width = MAX (1, texture_width / 2); | ||||
|       texture_height = MAX (1, texture_height / 2); | ||||
|  | ||||
|       invalid.x1 = invalid.x1 / 2; | ||||
|       invalid.y1 = invalid.y1 / 2; | ||||
|       invalid.x2 = MIN (texture_width, (invalid.x2 + 1) / 2); | ||||
|       invalid.y2 = MIN (texture_height, (invalid.y2 + 1) / 2); | ||||
|  | ||||
|       if (tower->invalid[i].x1 == tower->invalid[i].x2 || | ||||
|           tower->invalid[i].y1 == tower->invalid[i].y2) | ||||
|         { | ||||
|           tower->invalid[i] = invalid; | ||||
|         } | ||||
|       else | ||||
|         { | ||||
|           tower->invalid[i].x1 = MIN (tower->invalid[i].x1, invalid.x1); | ||||
|           tower->invalid[i].y1 = MIN (tower->invalid[i].y1, invalid.y1); | ||||
|           tower->invalid[i].x2 = MAX (tower->invalid[i].x2, invalid.x2); | ||||
|           tower->invalid[i].y2 = MAX (tower->invalid[i].y2, invalid.y2); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* It generally looks worse if we scale up a window texture by even a | ||||
|  * small amount than if we scale it down using bilinear filtering, so | ||||
|  * we always pick the *larger* adjacent level. */ | ||||
| #define LOD_BIAS (-0.49) | ||||
|  | ||||
| /* This determines the appropriate level of detail to use when drawing the | ||||
|  * texture, in a way that corresponds to what the GL specification does | ||||
|  * when mip-mapping. This is probably fancier and slower than what we need, | ||||
|  * but we do the computation only once each time we paint a window, and | ||||
|  * its easier to just use the equations from the specification than to | ||||
|  * come up with something simpler. | ||||
|  * | ||||
|  * If window is being painted at an angle from the viewer, then we have to | ||||
|  * pick a point in the texture; we use the middle of the texture (which is | ||||
|  * why the width/height are passed in.) This is not the normal case for | ||||
|  * Meta. | ||||
|  */ | ||||
| static int | ||||
| get_paint_level (int width, int height) | ||||
| { | ||||
|   CoglMatrix projection, modelview, pm; | ||||
|   float v[4]; | ||||
|   double viewport_width, viewport_height; | ||||
|   double u0, v0; | ||||
|   double xc, yc, wc; | ||||
|   double dxdu_, dxdv_, dydu_, dydv_; | ||||
|   double det_, det_sq; | ||||
|   double rho_sq; | ||||
|   double lambda; | ||||
|  | ||||
|   /* See | ||||
|    * http://www.opengl.org/registry/doc/glspec32.core.20090803.pdf | ||||
|    * Section 3.8.9, p. 1.6.2. Here we have | ||||
|    * | ||||
|    *  u(x,y) = x_o; | ||||
|    *  v(x,y) = y_o; | ||||
|    * | ||||
|    * Since we are mapping 1:1 from object coordinates into pixel | ||||
|    * texture coordinates, the clip coordinates are: | ||||
|    * | ||||
|    *  (x_c)                               (x_o)        (u) | ||||
|    *  (y_c) = (M_projection)(M_modelview) (y_o) = (PM) (v) | ||||
|    *  (z_c)                               (z_o)        (0) | ||||
|    *  (w_c)                               (w_o)        (1) | ||||
|    */ | ||||
|  | ||||
|   cogl_get_projection_matrix (&projection); | ||||
|   cogl_get_modelview_matrix (&modelview); | ||||
|  | ||||
|   cogl_matrix_multiply (&pm, &projection, &modelview); | ||||
|  | ||||
|   cogl_get_viewport (v); | ||||
|   viewport_width = v[2]; | ||||
|   viewport_height = v[3]; | ||||
|  | ||||
|   u0 = width / 2.; | ||||
|   v0 = height / 2.; | ||||
|  | ||||
|   xc = pm.xx * u0 + pm.xy * v0 + pm.xw; | ||||
|   yc = pm.yx * u0 + pm.yy * v0 + pm.yw; | ||||
|   wc = pm.wx * u0 + pm.wy * v0 + pm.ww; | ||||
|  | ||||
|   /* We'll simplify the equations below for a bit of micro-optimization. | ||||
|    * The commented out code is the unsimplified version. | ||||
|  | ||||
|   // Partial derivates of window coordinates: | ||||
|   // | ||||
|   //  x_w = 0.5 * viewport_width * x_c / w_c + viewport_center_x | ||||
|   //  y_w = 0.5 * viewport_height * y_c / w_c + viewport_center_y | ||||
|   // | ||||
|   // with respect to u, v, using | ||||
|   // d(a/b)/dx = da/dx * (1/b) - a * db/dx / (b^2) | ||||
|  | ||||
|   dxdu = 0.5 * viewport_width * (pm.xx - pm.wx * (xc/wc)) / wc; | ||||
|   dxdv = 0.5 * viewport_width * (pm.xy - pm.wy * (xc/wc)) / wc; | ||||
|   dydu = 0.5 * viewport_height * (pm.yx - pm.wx * (yc/wc)) / wc; | ||||
|   dydv = 0.5 * viewport_height * (pm.yy - pm.wy * (yc/wc)) / wc; | ||||
|  | ||||
|   // Compute the inverse partials as the matrix inverse | ||||
|   det = dxdu * dydv - dxdv * dydu; | ||||
|  | ||||
|   dudx =   dydv / det; | ||||
|   dudy = - dxdv / det; | ||||
|   dvdx = - dydu / det; | ||||
|   dvdy =   dvdu / det; | ||||
|  | ||||
|   // Scale factor; maximum of the distance in texels for a change of 1 pixel | ||||
|   // in the X direction or 1 pixel in the Y direction | ||||
|   rho = MAX (sqrt (dudx * dudx + dvdx * dvdx), sqrt(dudy * dudy + dvdy * dvdy)); | ||||
|  | ||||
|   // Level of detail | ||||
|   lambda = log2 (rho) + LOD_BIAS; | ||||
|   */ | ||||
|  | ||||
|   /* dxdu * wc, etc */ | ||||
|   dxdu_ = 0.5 * viewport_width * (pm.xx - pm.wx * (xc/wc)); | ||||
|   dxdv_ = 0.5 * viewport_width * (pm.xy - pm.wy * (xc/wc)); | ||||
|   dydu_ = 0.5 * viewport_height * (pm.yx - pm.wx * (yc/wc)); | ||||
|   dydv_ = 0.5 * viewport_height * (pm.yy - pm.wy * (yc/wc)); | ||||
|  | ||||
|   /* det * wc^2 */ | ||||
|   det_ = dxdu_ * dydv_ - dxdv_ * dydu_; | ||||
|   det_sq = det_ * det_; | ||||
|   if (det_sq == 0.0) | ||||
|     return -1; | ||||
|  | ||||
|   /* (rho * det * wc)^2 */ | ||||
|   rho_sq = MAX (dydv_ * dydv_ + dydu_ * dydu_, dxdv_ * dxdv_ + dxdu_ * dxdu_); | ||||
|   lambda = 0.5 * M_LOG2E * log (rho_sq * wc * wc / det_sq) + LOD_BIAS; | ||||
|  | ||||
| #if 0 | ||||
|   g_print ("%g %g %g\n", 0.5 * viewport_width * pm.xx / pm.ww, 0.5 * viewport_height * pm.yy / pm.ww, lambda); | ||||
| #endif | ||||
|  | ||||
|   if (lambda <= 0.) | ||||
|     return 0; | ||||
|   else | ||||
|     return (int)(0.5 + lambda); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| is_power_of_two (int x) | ||||
| { | ||||
|   return (x & (x - 1)) == 0; | ||||
| } | ||||
|  | ||||
| static void | ||||
| texture_tower_create_texture (MetaTextureTower *tower, | ||||
|                               int               level, | ||||
|                               int               width, | ||||
|                               int               height) | ||||
| { | ||||
|   if ((!is_power_of_two (width) || !is_power_of_two (height)) && | ||||
|       meta_texture_rectangle_check (tower->textures[level - 1])) | ||||
|     { | ||||
|       tower->textures[level] = | ||||
|         meta_texture_rectangle_new (width, height, | ||||
|                                     /* data format */ | ||||
|                                     TEXTURE_FORMAT, | ||||
|                                     /* internal cogl format */ | ||||
|                                     TEXTURE_FORMAT, | ||||
|                                     /* rowstride */ | ||||
|                                     width * 4, | ||||
|                                     /* data */ | ||||
|                                     NULL, | ||||
|                                     /* error */ | ||||
|                                     NULL); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       tower->textures[level] = cogl_texture_new_with_size (width, height, | ||||
|                                                            COGL_TEXTURE_NO_AUTO_MIPMAP, | ||||
|                                                            TEXTURE_FORMAT); | ||||
|     } | ||||
|  | ||||
|   tower->invalid[level].x1 = 0; | ||||
|   tower->invalid[level].y1 = 0; | ||||
|   tower->invalid[level].x2 = width; | ||||
|   tower->invalid[level].y2 = height; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| texture_tower_revalidate_fbo (MetaTextureTower *tower, | ||||
|                               int               level) | ||||
| { | ||||
|   CoglTexture *source_texture = tower->textures[level - 1]; | ||||
|   int source_texture_width = cogl_texture_get_width (source_texture); | ||||
|   int source_texture_height = cogl_texture_get_height (source_texture); | ||||
|   CoglTexture *dest_texture = tower->textures[level]; | ||||
|   int dest_texture_width = cogl_texture_get_width (dest_texture); | ||||
|   int dest_texture_height = cogl_texture_get_height (dest_texture); | ||||
|   Box *invalid = &tower->invalid[level]; | ||||
|   CoglMatrix modelview; | ||||
|  | ||||
|   if (tower->fbos[level] == NULL) | ||||
|     tower->fbos[level] = cogl_offscreen_new_to_texture (dest_texture); | ||||
|  | ||||
|   if (tower->fbos[level] == NULL) | ||||
|     return FALSE; | ||||
|  | ||||
|   cogl_push_framebuffer (COGL_FRAMEBUFFER (tower->fbos[level])); | ||||
|  | ||||
|   cogl_ortho (0, dest_texture_width, dest_texture_height, 0, -1., 1.); | ||||
|  | ||||
|   cogl_matrix_init_identity (&modelview); | ||||
|   cogl_set_modelview_matrix (&modelview); | ||||
|  | ||||
|   cogl_set_source_texture (tower->textures[level - 1]); | ||||
|   cogl_rectangle_with_texture_coords (invalid->x1, invalid->y1, | ||||
|                                       invalid->x2, invalid->y2, | ||||
|                                       (2. * invalid->x1) / source_texture_width, | ||||
|                                       (2. * invalid->y1) / source_texture_height, | ||||
|                                       (2. * invalid->x2) / source_texture_width, | ||||
|                                       (2. * invalid->y2) / source_texture_height); | ||||
|  | ||||
|   cogl_pop_framebuffer (); | ||||
|  | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| static void | ||||
| fill_copy (guchar       *buf, | ||||
|            const guchar *source, | ||||
|            int           width) | ||||
| { | ||||
|   memcpy (buf, source, width * 4); | ||||
| } | ||||
|  | ||||
| static void | ||||
| fill_scale_down (guchar       *buf, | ||||
|                  const guchar *source, | ||||
|                  int           width) | ||||
| { | ||||
|   while (width > 1) | ||||
|     { | ||||
|       buf[0] = (source[0] + source[4]) / 2; | ||||
|       buf[1] = (source[1] + source[5]) / 2; | ||||
|       buf[2] = (source[2] + source[6]) / 2; | ||||
|       buf[3] = (source[3] + source[7]) / 2; | ||||
|  | ||||
|       buf += 4; | ||||
|       source += 8; | ||||
|       width -= 2; | ||||
|     } | ||||
|  | ||||
|   if (width > 0) | ||||
|     { | ||||
|       buf[0] = source[0] / 2; | ||||
|       buf[1] = source[1] / 2; | ||||
|       buf[2] = source[2] / 2; | ||||
|       buf[3] = source[3] / 2; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void | ||||
| texture_tower_revalidate_client (MetaTextureTower *tower, | ||||
|                                  int               level) | ||||
| { | ||||
|   CoglTexture *source_texture = tower->textures[level - 1]; | ||||
|   int source_texture_width = cogl_texture_get_width (source_texture); | ||||
|   int source_texture_height = cogl_texture_get_height (source_texture); | ||||
|   guint source_rowstride; | ||||
|   guchar *source_data; | ||||
|   CoglTexture *dest_texture = tower->textures[level]; | ||||
|   int dest_texture_width = cogl_texture_get_width (dest_texture); | ||||
|   int dest_texture_height = cogl_texture_get_height (dest_texture); | ||||
|   int dest_x = tower->invalid[level].x1; | ||||
|   int dest_y = tower->invalid[level].y1; | ||||
|   int dest_width = tower->invalid[level].x2 - tower->invalid[level].x1; | ||||
|   int dest_height = tower->invalid[level].y2 - tower->invalid[level].y1; | ||||
|   guchar *dest_data; | ||||
|   guchar *source_tmp1 = NULL, *source_tmp2 = NULL; | ||||
|   int i, j; | ||||
|  | ||||
|   source_rowstride = source_texture_width * 4; | ||||
|  | ||||
|   source_data = g_malloc (source_texture_height * source_rowstride); | ||||
|   cogl_texture_get_data (source_texture, TEXTURE_FORMAT, source_rowstride, | ||||
|                          source_data); | ||||
|  | ||||
|   dest_data = g_malloc (dest_height * dest_width * 4); | ||||
|  | ||||
|   if (dest_texture_height < source_texture_height) | ||||
|     { | ||||
|       source_tmp1 = g_malloc (dest_width * 4); | ||||
|       source_tmp2 = g_malloc (dest_width * 4); | ||||
|     } | ||||
|  | ||||
|   for (i = 0; i < dest_height; i++) | ||||
|     { | ||||
|       guchar *dest_row = dest_data + i * dest_width * 4; | ||||
|       if (dest_texture_height < source_texture_height) | ||||
|         { | ||||
|           guchar *source1, *source2; | ||||
|           guchar *dest; | ||||
|  | ||||
|           if (dest_texture_width < source_texture_width) | ||||
|             { | ||||
|               fill_scale_down (source_tmp1, | ||||
|                                source_data + ((i + dest_y) * 2) * source_rowstride + dest_x * 2 * 4, | ||||
|                                dest_width * 2); | ||||
|               fill_scale_down (source_tmp2, | ||||
|                                source_data + ((i + dest_y) * 2 + 1) * source_rowstride + dest_x * 2 * 4, | ||||
|                                dest_width * 2); | ||||
|             } | ||||
|           else | ||||
|             { | ||||
|               fill_copy (source_tmp1, | ||||
|                          source_data + ((i + dest_y) * 2) * source_rowstride + dest_x * 4, | ||||
|                          dest_width); | ||||
|               fill_copy (source_tmp2, | ||||
|                          source_data + ((i + dest_y) * 2 + 1) * source_rowstride + dest_x * 4, | ||||
|                          dest_width); | ||||
|             } | ||||
|  | ||||
|           source1 = source_tmp1; | ||||
|           source2 = source_tmp2; | ||||
|  | ||||
|           dest = dest_row; | ||||
|           for (j = 0; j < dest_width * 4; j++) | ||||
|             *(dest++) = (*(source1++) + *(source2++)) / 2; | ||||
|         } | ||||
|       else | ||||
|         { | ||||
|           if (dest_texture_width < source_texture_width) | ||||
|             fill_scale_down (dest_row, | ||||
|                              source_data + (i + dest_y) * source_rowstride + dest_x * 2 * 4, | ||||
|                              dest_width * 2); | ||||
|           else | ||||
|             fill_copy (dest_row, | ||||
|                        source_data + (i + dest_y) * source_rowstride, | ||||
|                        dest_width); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   cogl_texture_set_region (dest_texture, | ||||
|                            0, 0, | ||||
|                            dest_x, dest_y, | ||||
|                            dest_width, dest_height, | ||||
|                            dest_width, dest_height, | ||||
|                            TEXTURE_FORMAT, | ||||
|                            4 * dest_width, | ||||
|                            dest_data); | ||||
|  | ||||
|   if (dest_texture_height < source_texture_height) | ||||
|     { | ||||
|       g_free (source_tmp1); | ||||
|       g_free (source_tmp2); | ||||
|     } | ||||
|  | ||||
|   g_free (source_data); | ||||
|   g_free (dest_data); | ||||
| } | ||||
|  | ||||
| static void | ||||
| texture_tower_revalidate (MetaTextureTower *tower, | ||||
|                           int               level) | ||||
| { | ||||
|   if (!texture_tower_revalidate_fbo (tower, level)) | ||||
|     texture_tower_revalidate_client (tower, level); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * meta_texture_tower_get_paint_texture: | ||||
|  * @tower: a #MetaTextureTower | ||||
|  * | ||||
|  * Gets the texture from the tower that best matches the current | ||||
|  * rendering scale. (On the assumption here the texture is going to | ||||
|  * be rendered with vertex coordinates that correspond to its | ||||
|  * size in pixels, so a 200x200 texture will be rendered on the | ||||
|  * rectangle (0, 0, 200, 200). | ||||
|  * | ||||
|  * Return value: the COGL texture handle to use for painting, or | ||||
|  *  %NULL if no base texture has yet been set. | ||||
|  */ | ||||
| CoglTexture * | ||||
| meta_texture_tower_get_paint_texture (MetaTextureTower *tower) | ||||
| { | ||||
|   int texture_width, texture_height; | ||||
|   int level; | ||||
|  | ||||
|   g_return_val_if_fail (tower != NULL, NULL); | ||||
|  | ||||
|   if (tower->textures[0] == NULL) | ||||
|     return NULL; | ||||
|  | ||||
|   texture_width = cogl_texture_get_width (tower->textures[0]); | ||||
|   texture_height = cogl_texture_get_height (tower->textures[0]); | ||||
|  | ||||
|   level = get_paint_level(texture_width, texture_height); | ||||
|   if (level < 0) /* singular paint matrix, scaled to nothing */ | ||||
|     return NULL; | ||||
|   level = MIN (level, tower->n_levels - 1); | ||||
|  | ||||
|   if (tower->textures[level] == NULL || | ||||
|       (tower->invalid[level].x2 != tower->invalid[level].x1 && | ||||
|        tower->invalid[level].y2 != tower->invalid[level].y1)) | ||||
|     { | ||||
|       int i; | ||||
|  | ||||
|       for (i = 1; i <= level; i++) | ||||
|        { | ||||
|          /* Use "floor" convention here to be consistent with the NPOT texture extension */ | ||||
|          texture_width = MAX (1, texture_width / 2); | ||||
|          texture_height = MAX (1, texture_height / 2); | ||||
|  | ||||
|          if (tower->textures[i] == NULL) | ||||
|            texture_tower_create_texture (tower, i, texture_width, texture_height); | ||||
|        } | ||||
|  | ||||
|       for (i = 1; i <= level; i++) | ||||
|        { | ||||
|          if (tower->invalid[level].x2 != tower->invalid[level].x1 && | ||||
|              tower->invalid[level].y2 != tower->invalid[level].y1) | ||||
|            texture_tower_revalidate (tower, i); | ||||
|        } | ||||
|    } | ||||
|  | ||||
|   return tower->textures[level]; | ||||
| } | ||||
| @@ -1,69 +0,0 @@ | ||||
| /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | ||||
| /* | ||||
|  * MetaTextureTower | ||||
|  * | ||||
|  * Mipmap emulation by creation of scaled down images | ||||
|  * | ||||
|  * Copyright (C) 2009 Red Hat, 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., 59 Temple Place - Suite 330, Boston, MA | ||||
|  * 02111-1307, USA. | ||||
|  */ | ||||
|  | ||||
| #ifndef __META_TEXTURE_TOWER_H__ | ||||
| #define __META_TEXTURE_TOWER_H__ | ||||
|  | ||||
| #include <clutter/clutter.h> | ||||
|  | ||||
| G_BEGIN_DECLS | ||||
|  | ||||
| /** | ||||
|  * SECTION:MetaTextureTower | ||||
|  * @short_description: mipmap emulation by creation of scaled down images | ||||
|  * | ||||
|  * A #MetaTextureTower is used to get good looking scaled down images when | ||||
|  * we can't use the GL drivers mipmap support. There are two separate reasons | ||||
|  * | ||||
|  *  - Some cards (including radeon cards <= r5xx) only support | ||||
|  *    TEXTURE_RECTANGLE_ARB and not NPOT textures. Rectangular textures | ||||
|  *    are defined not to support mipmapping. | ||||
|  *  - Even when NPOT textures are available, the combination of NPOT | ||||
|  *    textures, texture_from_pixmap, and mipmapping doesn't typically | ||||
|  *    work, since the X server doesn't allocate pixmaps in the right | ||||
|  *    layout for mipmapping. | ||||
|  * | ||||
|  * So, what we do is create the "mipmap" levels ourselves by successive | ||||
|  * power-of-two scaledowns, and when rendering pick the single texture | ||||
|  * that best matches the scale we are rendering at. (Since we aren't | ||||
|  * typically using perspective transforms, we'll frequently have a single | ||||
|  * scale for the entire texture.) | ||||
|  */ | ||||
|  | ||||
| typedef struct _MetaTextureTower MetaTextureTower; | ||||
|  | ||||
| MetaTextureTower *meta_texture_tower_new               (void); | ||||
| void              meta_texture_tower_free              (MetaTextureTower *tower); | ||||
| void              meta_texture_tower_set_base_texture  (MetaTextureTower *tower, | ||||
|                                                         CoglTexture      *texture); | ||||
| void              meta_texture_tower_update_area       (MetaTextureTower *tower, | ||||
|                                                         int               x, | ||||
|                                                         int               y, | ||||
|                                                         int               width, | ||||
|                                                         int               height); | ||||
| CoglTexture      *meta_texture_tower_get_paint_texture (MetaTextureTower *tower); | ||||
|  | ||||
| G_BEGIN_DECLS | ||||
|  | ||||
| #endif /* __META_TEXTURE_TOWER_H__ */ | ||||
| @@ -1782,10 +1782,6 @@ check_needs_pixmap (MetaWindowActor *self) | ||||
|           goto out; | ||||
|         } | ||||
|  | ||||
|       if (compositor->no_mipmaps) | ||||
|         meta_shaped_texture_set_create_mipmaps (META_SHAPED_TEXTURE (priv->actor), | ||||
|                                                 FALSE); | ||||
|  | ||||
|       meta_shaped_texture_set_pixmap (META_SHAPED_TEXTURE (priv->actor), | ||||
|                                       priv->back_pixmap); | ||||
|  | ||||
|   | ||||
| @@ -66,9 +66,6 @@ GType meta_shaped_texture_get_type (void) G_GNUC_CONST; | ||||
|  | ||||
| ClutterActor *meta_shaped_texture_new (void); | ||||
|  | ||||
| void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex, | ||||
| 					     gboolean           create_mipmaps); | ||||
|  | ||||
| void meta_shaped_texture_update_area (MetaShapedTexture *stex, | ||||
|                                       int                x, | ||||
|                                       int                y, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user