1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /*
3  * Utilities for use with Cogl
4  *
5  * Copyright 2010 Red Hat, Inc.
6  * Copyright 2010 Intel Corporation
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA
21  * 02110-1335, USA.
22  */
23 
24 #if HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 #include <clutter/clutter.h>
28 #include "cogl-utils.h"
29 #include "meta-sync-ring.h"
30 #include <meta/errors.h>
31 
32 #include <gdk/gdk.h>
33 
34 /**
35  * meta_create_color_texture_4ub:
36  * @red:
37  * @green:
38  * @blue:
39  * @alpha:
40  * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE;
41  *   %COGL_TEXTURE_NO_SLICING is useful if the texture will be
42  *   repeated to create a constant color fill, since hardware
43  *   repeat can't be used for a sliced texture.
44  *
45  * Creates a texture that is a single pixel with the specified
46  * unpremultiplied color components.
47  *
48  * Return value: (transfer full): a newly created Cogl texture
49  */
50 CoglTexture *
meta_create_color_texture_4ub(guint8 red,guint8 green,guint8 blue,guint8 alpha,CoglTextureFlags flags)51 meta_create_color_texture_4ub (guint8           red,
52                                guint8           green,
53                                guint8           blue,
54                                guint8           alpha,
55                                CoglTextureFlags flags)
56 {
57   CoglColor color;
58   guint8 pixel[4];
59 
60   cogl_color_init_from_4ub (&color, red, green, blue, alpha);
61   cogl_color_premultiply (&color);
62 
63   pixel[0] = cogl_color_get_red_byte (&color);
64   pixel[1] = cogl_color_get_green_byte (&color);
65   pixel[2] = cogl_color_get_blue_byte (&color);
66   pixel[3] = cogl_color_get_alpha_byte (&color);
67 
68   return cogl_texture_new_from_data (1, 1,
69                                      flags,
70                                      COGL_PIXEL_FORMAT_RGBA_8888_PRE,
71                                      COGL_PIXEL_FORMAT_ANY,
72                                      4, pixel);
73 }
74 
75 CoglPipeline *
meta_create_texture_pipeline(CoglTexture * src_texture)76 meta_create_texture_pipeline (CoglTexture *src_texture)
77 {
78   static CoglPipeline *texture_pipeline_template = NULL;
79   CoglPipeline *pipeline;
80 
81   /* We use a pipeline that has a dummy texture as a base for all
82      texture pipelines. The idea is that only the Cogl texture object
83      would be different in the children so it is likely that Cogl will
84      be able to share GL programs between all the textures. */
85   if (G_UNLIKELY (texture_pipeline_template == NULL))
86     {
87       CoglTexture *dummy_texture;
88 
89       dummy_texture = meta_create_color_texture_4ub (0xff, 0xff, 0xff, 0xff,
90                                                      COGL_TEXTURE_NONE);
91 
92 
93       texture_pipeline_template = cogl_pipeline_new (meta_compositor_get_cogl_context ());
94       cogl_pipeline_set_layer_texture (texture_pipeline_template, 0, dummy_texture);
95       cogl_object_unref (dummy_texture);
96     }
97 
98   pipeline = cogl_pipeline_copy (texture_pipeline_template);
99 
100   if (src_texture != NULL)
101     cogl_pipeline_set_layer_texture (pipeline, 0, src_texture);
102 
103   return pipeline;
104 }
105 
106 /********************************************************************************************/
107 /********************************* CoglTexture2d wrapper ************************************/
108 
109 static gboolean supports_npot = FALSE;
110 static gboolean npot_sizes_checked = FALSE;
111 
112 static gint screen_width = 0;
113 static gint screen_height = 0;
114 
115 gboolean
meta_cogl_hardware_supports_npot_sizes(void)116 meta_cogl_hardware_supports_npot_sizes (void)
117 {
118   if (npot_sizes_checked)
119     return supports_npot;
120 
121   supports_npot = cogl_has_feature (meta_compositor_get_cogl_context (), COGL_FEATURE_ID_TEXTURE_NPOT);
122   npot_sizes_checked = TRUE;
123 
124   return supports_npot;
125 }
126 
127 inline static void
clamp_sizes(gint * width,gint * height)128 clamp_sizes (gint *width,
129              gint *height)
130 {
131     if (screen_width == 0)
132       {
133         GdkScreen *screen = gdk_screen_get_default ();
134 
135         screen_width = gdk_screen_get_width (screen);
136         screen_height = gdk_screen_get_height (screen);
137       }
138 
139     *width = MIN (*width, screen_width * 2);
140     *height = MIN (*height, screen_height * 2);
141 }
142 
143 /**
144  * meta_cogl_texture_new_from_data_wrapper: (skip)
145  *
146  * Decides whether to use the newer (apparently safer)
147  * cogl_texture_2d_new_from_data or the older cogl_texture_new_from_data
148  * depending on if the GPU supports it.
149  */
150 
151 CoglTexture *
meta_cogl_texture_new_from_data_wrapper(int width,int height,CoglTextureFlags flags,CoglPixelFormat format,CoglPixelFormat internal_format,int rowstride,const uint8_t * data)152 meta_cogl_texture_new_from_data_wrapper                (int  width,
153                                                         int  height,
154                                            CoglTextureFlags  flags,
155                                             CoglPixelFormat  format,
156                                             CoglPixelFormat  internal_format,
157                                                         int  rowstride,
158                                               const uint8_t *data)
159 {
160     CoglTexture *texture = NULL;
161 
162     clamp_sizes (&width, &height);
163 
164     if (supports_npot)
165       {
166         CoglError *error = NULL;
167 
168         texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (meta_compositor_get_cogl_context (), width, height,
169                                                                format,
170                                                                rowstride,
171                                                                data,
172                                                                &error));
173         if (error)
174           {
175             meta_verbose ("cogl_texture_2d_new_from_data failed: %s\n", error->message);
176             cogl_error_free (error);
177           }
178       }
179     else
180       {
181         texture = cogl_texture_new_from_data (width,
182                                               height,
183                                               flags,
184                                               format,
185                                               internal_format,
186                                               rowstride,
187                                               data);
188       }
189 
190     return texture;
191 }
192 
193 static CoglTexture *
meta_cogl_rectangle_new_compat(unsigned int width,unsigned int height,CoglPixelFormat format,unsigned int rowstride,const guint8 * data)194 meta_cogl_rectangle_new_compat (unsigned int width,
195                                 unsigned int height,
196                                 CoglPixelFormat format,
197                                 unsigned int rowstride,
198                                 const guint8 *data)
199 {
200   ClutterBackend *backend = clutter_get_default_backend ();
201   CoglContext *context = clutter_backend_get_cogl_context (backend);
202   CoglTextureRectangle *tex_rect;
203 
204   tex_rect = cogl_texture_rectangle_new_with_size (context, width, height);
205 
206   if (tex_rect == NULL)
207     return NULL;
208 
209   if (data)
210     cogl_texture_set_region (COGL_TEXTURE (tex_rect),
211                              0, 0, /* src_x/y */
212                              0, 0, /* dst_x/y */
213                              width, height, /* dst_width/height */
214                              width, height, /* width/height */
215                              format,
216                              rowstride,
217                              data);
218 
219   return COGL_TEXTURE (tex_rect);
220 }
221 
222 CoglTexture *
meta_cogl_rectangle_new(int width,int height,CoglPixelFormat format,int stride,const uint8_t * data)223 meta_cogl_rectangle_new (int width,
224                          int height,
225                          CoglPixelFormat format,
226                          int stride,
227                          const uint8_t *data)
228 {
229   if (!supports_npot)
230     return meta_cogl_rectangle_new_compat (width, height, format,  stride, data);
231 
232   CoglTexture *texture = COGL_TEXTURE (cogl_texture_rectangle_new_with_size (meta_compositor_get_cogl_context (), width, height));
233   cogl_texture_set_components (texture, COGL_TEXTURE_COMPONENTS_A);
234   cogl_texture_set_region (texture,
235                            0, 0, /* src_x/y */
236                            0, 0, /* dst_x/y */
237                            width, height, /* dst_width/height */
238                            width, height, /* width/height */
239                            format,
240                            stride, data);
241 
242   return texture;
243 }
244