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