Bug Summary

File:cdk/cdkgl.c
Warning:line 697, column 59
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cdkgl.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/cdk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Cdk" -D G_LOG_USE_STRUCTURED=1 -D CDK_COMPILATION -I .. -I ../cdk -I .. -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/cdk -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-171836-43636-1 -x c cdkgl.c
1/* CDK - The GIMP Drawing Kit
2 * Copyright (C) 2014 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19
20#include "cdkcairo.h"
21#include "cdkglcontextprivate.h"
22
23#include "cdkinternals.h"
24
25#ifdef CDK_WINDOWING_WIN32
26# include "win32/cdkwin32.h"
27#endif
28
29#include <epoxy/gl.h>
30#include <math.h>
31#include <string.h>
32
33static cairo_user_data_key_t direct_key;
34
35void
36cdk_cairo_surface_mark_as_direct (cairo_surface_t *surface,
37 CdkWindow *window)
38{
39 cairo_surface_set_user_data (surface, &direct_key,
40 g_object_ref (window)((__typeof__ (window)) (g_object_ref) (window)), g_object_unref);
41}
42
43static const char *
44get_vertex_type_name (int type)
45{
46 switch (type)
47 {
48 case GL_VERTEX_SHADER0x8B31:
49 return "vertex";
50 case GL_GEOMETRY_SHADER0x8DD9:
51 return "geometry";
52 case GL_FRAGMENT_SHADER0x8B30:
53 return "fragment";
54 }
55 return "unknown";
56}
57
58static guint
59create_shader (int type,
60 const char *code)
61{
62 guint shader;
63 int status;
64
65 shader = glCreateShaderepoxy_glCreateShader (type);
66 glShaderSourceepoxy_glShaderSource (shader, 1, &code, NULL((void*)0));
67 glCompileShaderepoxy_glCompileShader (shader);
68
69 glGetShaderivepoxy_glGetShaderiv (shader, GL_COMPILE_STATUS0x8B81, &status);
70 if (status == GL_FALSE0)
71 {
72 int log_len;
73 char *buffer;
74
75 glGetShaderivepoxy_glGetShaderiv (shader, GL_INFO_LOG_LENGTH0x8B84, &log_len);
76
77 buffer = g_malloc (log_len + 1);
78 glGetShaderInfoLogepoxy_glGetShaderInfoLog (shader, log_len, NULL((void*)0), buffer);
79
80 g_warning ("Compile failure in %s shader:\n%s", get_vertex_type_name (type), buffer);
81 g_free (buffer);
82
83 glDeleteShaderepoxy_glDeleteShader (shader);
84
85 return 0;
86 }
87
88 return shader;
89}
90
91static void
92make_program (CdkGLContextProgram *program,
93 const char *vertex_shader_path,
94 const char *fragment_shader_path)
95{
96 guint vertex_shader, fragment_shader;
97 GBytes *source;
98 int status;
99
100 source = g_resources_lookup_data (vertex_shader_path, 0, NULL((void*)0));
101 g_assert (source != NULL)do { if (source != ((void*)0)) ; else g_assertion_message_expr
("Cdk", "cdkgl.c", 101, ((const char*) (__func__)), "source != NULL"
); } while (0)
;
102 vertex_shader = create_shader (GL_VERTEX_SHADER0x8B31, g_bytes_get_data (source, NULL((void*)0)));
103 g_bytes_unref (source);
104 if (vertex_shader == 0)
105 return;
106
107 source = g_resources_lookup_data (fragment_shader_path, 0, NULL((void*)0));
108 g_assert (source != NULL)do { if (source != ((void*)0)) ; else g_assertion_message_expr
("Cdk", "cdkgl.c", 108, ((const char*) (__func__)), "source != NULL"
); } while (0)
;
109 fragment_shader = create_shader (GL_FRAGMENT_SHADER0x8B30, g_bytes_get_data (source, NULL((void*)0)));
110 g_bytes_unref (source);
111 if (fragment_shader == 0)
112 {
113 glDeleteShaderepoxy_glDeleteShader (vertex_shader);
114 return;
115 }
116
117 program->program = glCreateProgramepoxy_glCreateProgram ();
118 glAttachShaderepoxy_glAttachShader (program->program, vertex_shader);
119 glAttachShaderepoxy_glAttachShader (program->program, fragment_shader);
120
121 glLinkProgramepoxy_glLinkProgram (program->program);
122
123 glDeleteShaderepoxy_glDeleteShader (vertex_shader);
124 glDeleteShaderepoxy_glDeleteShader (fragment_shader);
125
126 glGetProgramivepoxy_glGetProgramiv (program->program, GL_LINK_STATUS0x8B82, &status);
127 if (status == GL_FALSE0)
128 {
129 int log_len;
130 char *buffer;
131
132 glGetProgramivepoxy_glGetProgramiv (program->program, GL_INFO_LOG_LENGTH0x8B84, &log_len);
133
134 buffer = g_malloc (log_len + 1);
135 glGetProgramInfoLogepoxy_glGetProgramInfoLog (program->program, log_len, NULL((void*)0), buffer);
136 g_warning ("Linker failure: %s\n", buffer);
137 g_free (buffer);
138
139 glDeleteProgramepoxy_glDeleteProgram (program->program);
140 }
141
142 program->position_location = glGetAttribLocationepoxy_glGetAttribLocation (program->program, "position");
143 program->uv_location = glGetAttribLocationepoxy_glGetAttribLocation (program->program, "uv");
144 program->map_location = glGetUniformLocationepoxy_glGetUniformLocation (program->program, "map");
145 program->flip_location = glGetUniformLocationepoxy_glGetUniformLocation (program->program, "flipColors");
146}
147
148static void
149bind_vao (CdkGLContextPaintData *paint_data)
150{
151 if (paint_data->vertex_array_object == 0)
152 {
153 glGenVertexArraysepoxy_glGenVertexArrays (1, &paint_data->vertex_array_object);
154 /* ATM we only use one VAO, so always bind it */
155 glBindVertexArrayepoxy_glBindVertexArray (paint_data->vertex_array_object);
156 }
157}
158
159static void
160use_texture_gles_program (CdkGLContextPaintData *paint_data)
161{
162 if (paint_data->texture_2d_quad_program.program == 0)
163 make_program (&paint_data->texture_2d_quad_program,
164 "/org/ctk/libcdk/glsl/gles2-texture.vs.glsl",
165 "/org/ctk/libcdk/glsl/gles2-texture.fs.glsl");
166
167 if (paint_data->current_program != &paint_data->texture_2d_quad_program)
168 {
169 paint_data->current_program = &paint_data->texture_2d_quad_program;
170 glUseProgramepoxy_glUseProgram (paint_data->current_program->program);
171 }
172}
173
174static void
175use_texture_2d_program (CdkGLContextPaintData *paint_data)
176{
177 const char *vertex_shader_path = paint_data->is_legacy
178 ? "/org/ctk/libcdk/glsl/gl2-texture-2d.vs.glsl"
179 : "/org/ctk/libcdk/glsl/gl3-texture-2d.vs.glsl";
180
181 const char *fragment_shader_path = paint_data->is_legacy
182 ? "/org/ctk/libcdk/glsl/gl2-texture-2d.fs.glsl"
183 : "/org/ctk/libcdk/glsl/gl3-texture-2d.fs.glsl";
184
185 if (paint_data->texture_2d_quad_program.program == 0)
186 make_program (&paint_data->texture_2d_quad_program, vertex_shader_path, fragment_shader_path);
187
188 if (paint_data->current_program != &paint_data->texture_2d_quad_program)
189 {
190 paint_data->current_program = &paint_data->texture_2d_quad_program;
191 glUseProgramepoxy_glUseProgram (paint_data->current_program->program);
192 }
193}
194
195static void
196use_texture_rect_program (CdkGLContextPaintData *paint_data)
197{
198 const char *vertex_shader_path = paint_data->is_legacy
199 ? "/org/ctk/libcdk/glsl/gl2-texture-rect.vs.glsl"
200 : "/org/ctk/libcdk/glsl/gl3-texture-rect.vs.glsl";
201
202 const char *fragment_shader_path = paint_data->is_legacy
203 ? "/org/ctk/libcdk/glsl/gl2-texture-rect.fs.glsl"
204 : "/org/ctk/libcdk/glsl/gl3-texture-rect.vs.glsl";
205
206 if (paint_data->texture_rect_quad_program.program == 0)
207 make_program (&paint_data->texture_rect_quad_program, vertex_shader_path, fragment_shader_path);
208
209 if (paint_data->current_program != &paint_data->texture_rect_quad_program)
210 {
211 paint_data->current_program = &paint_data->texture_rect_quad_program;
212 glUseProgramepoxy_glUseProgram (paint_data->current_program->program);
213 }
214}
215
216void
217cdk_gl_texture_quads (CdkGLContext *paint_context,
218 guint texture_target,
219 int n_quads,
220 CdkTexturedQuad *quads,
221 gboolean flip_colors)
222{
223 CdkGLContextPaintData *paint_data = cdk_gl_context_get_paint_data (paint_context);
224 CdkGLContextProgram *program;
225 CdkWindow *window = cdk_gl_context_get_window (paint_context);
226 int window_scale = cdk_window_get_scale_factor (window);
227 float w = cdk_window_get_width (window) * window_scale;
228 float h = cdk_window_get_height (window) * window_scale;
229 int i;
230 float *vertex_buffer_data;
231
232 bind_vao (paint_data);
233
234 if (paint_data->tmp_vertex_buffer == 0)
235 glGenBuffersepoxy_glGenBuffers(1, &paint_data->tmp_vertex_buffer);
236
237 if (paint_data->use_es)
238 use_texture_gles_program (paint_data);
239 else
240 {
241 if (texture_target == GL_TEXTURE_RECTANGLE_ARB0x84F5)
242 use_texture_rect_program (paint_data);
243 else
244 use_texture_2d_program (paint_data);
245 }
246
247 program = paint_data->current_program;
248
249 /* Use texture unit 0 */
250 glActiveTextureepoxy_glActiveTexture (GL_TEXTURE00x84C0);
251 glUniform1iepoxy_glUniform1i(program->map_location, 0);
252
253 /* Flip 'R' and 'B' colors on GLES, if necessary */
254 if (cdk_gl_context_get_use_es (paint_context))
255 glUniform1iepoxy_glUniform1i (program->flip_location, flip_colors ? 1 : 0);
256
257 glEnableVertexAttribArrayepoxy_glEnableVertexAttribArray (program->position_location);
258 glEnableVertexAttribArrayepoxy_glEnableVertexAttribArray (program->uv_location);
259 glBindBufferepoxy_glBindBuffer (GL_ARRAY_BUFFER0x8892, paint_data->tmp_vertex_buffer);
260
261 glVertexAttribPointerepoxy_glVertexAttribPointer (program->position_location, 2, GL_FLOAT0x1406, GL_FALSE0, sizeof(float) * 4, NULL((void*)0));
262 glVertexAttribPointerepoxy_glVertexAttribPointer (program->uv_location, 2, GL_FLOAT0x1406, GL_FALSE0, sizeof(float) * 4, (void *) (sizeof(float) * 2));
263
264#define VERTEX_SIZE4 4
265
266#define QUAD_N_VERTICES6 6
267
268#define QUAD_SIZE(4 * 6) (VERTEX_SIZE4 * QUAD_N_VERTICES6)
269
270 vertex_buffer_data = g_new (float, n_quads * QUAD_SIZE)((float *) g_malloc_n ((n_quads * (4 * 6)), sizeof (float)));
271
272 for (i = 0; i < n_quads; i++)
273 {
274 CdkTexturedQuad *quad = &quads[i];
275 float vertex_data[] = {
276 (quad->x1 * 2) / w - 1, (quad->y1 * 2) / h - 1, quad->u1, quad->v1,
277 (quad->x1 * 2) / w - 1, (quad->y2 * 2) / h - 1, quad->u1, quad->v2,
278 (quad->x2 * 2) / w - 1, (quad->y1 * 2) / h - 1, quad->u2, quad->v1,
279
280 (quad->x2 * 2) / w - 1, (quad->y2 * 2) / h - 1, quad->u2, quad->v2,
281 (quad->x1 * 2) / w - 1, (quad->y2 * 2) / h - 1, quad->u1, quad->v2,
282 (quad->x2 * 2) / w - 1, (quad->y1 * 2) / h - 1, quad->u2, quad->v1,
283 };
284
285 float *vertex = &vertex_buffer_data[i * QUAD_SIZE(4 * 6)];
286 memcpy (vertex, vertex_data, sizeof(vertex_data));
287 }
288
289 glBufferDataepoxy_glBufferData (GL_ARRAY_BUFFER0x8892, sizeof(float) * n_quads * QUAD_SIZE(4 * 6), vertex_buffer_data, GL_STREAM_DRAW0x88E0);
290 glDrawArraysepoxy_glDrawArrays (GL_TRIANGLES0x0004, 0, n_quads * QUAD_N_VERTICES6);
291
292 g_free (vertex_buffer_data);
293
294 glDisableVertexAttribArrayepoxy_glDisableVertexAttribArray (program->position_location);
295 glDisableVertexAttribArrayepoxy_glDisableVertexAttribArray (program->uv_location);
296}
297
298/* x,y,width,height describes a rectangle in the gl render buffer
299 coordinate space, and its top left corner is drawn at the current
300 position according to the cairo translation. */
301
302/**
303 * cdk_cairo_draw_from_gl:
304 * @cr: a cairo context
305 * @window: The window we're rendering for (not necessarily into)
306 * @source: The GL ID of the source buffer
307 * @source_type: The type of the @source
308 * @buffer_scale: The scale-factor that the @source buffer is allocated for
309 * @x: The source x position in @source to start copying from in GL coordinates
310 * @y: The source y position in @source to start copying from in GL coordinates
311 * @width: The width of the region to draw
312 * @height: The height of the region to draw
313 *
314 * This is the main way to draw GL content in CTK+. It takes a render buffer ID
315 * (@source_type == #GL_RENDERBUFFER) or a texture id (@source_type == #GL_TEXTURE)
316 * and draws it onto @cr with an OVER operation, respecting the current clip.
317 * The top left corner of the rectangle specified by @x, @y, @width and @height
318 * will be drawn at the current (0,0) position of the cairo_t.
319 *
320 * This will work for *all* cairo_t, as long as @window is realized, but the
321 * fallback implementation that reads back the pixels from the buffer may be
322 * used in the general case. In the case of direct drawing to a window with
323 * no special effects applied to @cr it will however use a more efficient
324 * approach.
325 *
326 * For #GL_RENDERBUFFER the code will always fall back to software for buffers
327 * with alpha components, so make sure you use #GL_TEXTURE if using alpha.
328 *
329 * Calling this may change the current GL context.
330 *
331 * Since: 3.16
332 */
333void
334cdk_cairo_draw_from_gl (cairo_t *cr,
335 CdkWindow *window,
336 int source,
337 int source_type,
338 int buffer_scale,
339 int x,
340 int y,
341 int width,
342 int height)
343{
344 CdkGLContext *paint_context;
345 cairo_surface_t *image;
346 cairo_matrix_t matrix;
347 int dx, dy, window_scale;
348 gboolean trivial_transform;
349 cairo_surface_t *group_target;
350 CdkWindow *direct_window, *impl_window;
351 guint framebuffer;
352 int alpha_size = 0;
353 cairo_region_t *clip_region;
354 CdkGLContextPaintData *paint_data;
355
356 impl_window = window->impl_window;
357
358 window_scale = cdk_window_get_scale_factor (impl_window);
359
360 paint_context = cdk_window_get_paint_gl_context (window, NULL((void*)0));
361 if (paint_context == NULL((void*)0))
362 {
363 g_warning ("cdk_cairo_draw_gl_render_buffer failed - no paint context");
364 return;
365 }
366
367 clip_region = cdk_cairo_region_from_clip (cr);
368
369 cdk_gl_context_make_current (paint_context);
370 paint_data = cdk_gl_context_get_paint_data (paint_context);
371
372 if (paint_data->tmp_framebuffer == 0)
373 glGenFramebuffersEXTepoxy_glGenFramebuffersEXT (1, &paint_data->tmp_framebuffer);
374
375 if (source_type == GL_RENDERBUFFER0x8D41)
376 {
377 glBindRenderbufferepoxy_glBindRenderbuffer (GL_RENDERBUFFER0x8D41, source);
378 glGetRenderbufferParameterivepoxy_glGetRenderbufferParameteriv (GL_RENDERBUFFER0x8D41, GL_RENDERBUFFER_ALPHA_SIZE0x8D53, &alpha_size);
379 }
380 else if (source_type == GL_TEXTURE0x1702)
381 {
382 glBindTextureepoxy_glBindTexture (GL_TEXTURE_2D0x0DE1, source);
383
384 if (cdk_gl_context_get_use_es (paint_context))
385 alpha_size = 1;
386 else
387 glGetTexLevelParameterivepoxy_glGetTexLevelParameteriv (GL_TEXTURE_2D0x0DE1, 0, GL_TEXTURE_ALPHA_SIZE0x805F, &alpha_size);
388 }
389 else
390 {
391 g_warning ("Unsupported gl source type %d\n", source_type);
392 return;
393 }
394
395 group_target = cairo_get_group_target (cr);
396 direct_window = cairo_surface_get_user_data (group_target, &direct_key);
397
398 cairo_get_matrix (cr, &matrix);
399
400 dx = matrix.x0;
401 dy = matrix.y0;
402
403 /* Trivial == integer-only translation */
404 trivial_transform =
405 (double)dx == matrix.x0 && (double)dy == matrix.y0 &&
406 matrix.xx == 1.0 && matrix.xy == 0.0 &&
407 matrix.yx == 0.0 && matrix.yy == 1.0;
408
409 /* For direct paint of non-alpha renderbuffer, we can
410 just do a bitblit */
411 if ((_cdk_gl_flags & CDK_GL_SOFTWARE_DRAW_GL) == 0 &&
412 source_type == GL_RENDERBUFFER0x8D41 &&
413 alpha_size == 0 &&
414 direct_window != NULL((void*)0) &&
415 direct_window->current_paint.use_gl &&
416 cdk_gl_context_has_framebuffer_blit (paint_context) &&
417 trivial_transform &&
418 clip_region != NULL((void*)0))
419 {
420 int unscaled_window_height;
421 int i;
422
423 /* Create a framebuffer with the source renderbuffer and
424 make it the current target for reads */
425 framebuffer = paint_data->tmp_framebuffer;
426 glBindFramebufferEXTepoxy_glBindFramebufferEXT (GL_FRAMEBUFFER_EXT0x8D40, framebuffer);
427 glFramebufferRenderbufferEXTepoxy_glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT0x8D40, GL_COLOR_ATTACHMENT0_EXT0x8CE0,
428 GL_RENDERBUFFER_EXT0x8D41, source);
429 glBindFramebufferEXTepoxy_glBindFramebufferEXT (GL_DRAW_FRAMEBUFFER_EXT0x8CA9, 0);
430
431 /* Translate to impl coords */
432 cairo_region_translate (clip_region, dx, dy);
433
434 glEnableepoxy_glEnable (GL_SCISSOR_TEST0x0C11);
435
436 cdk_window_get_unscaled_size (impl_window, NULL((void*)0), &unscaled_window_height);
437
438 /* We can use glDrawBuffer on OpenGL only; on GLES 2.0 we are already
439 * double buffered so we don't need it...
440 */
441 if (!cdk_gl_context_get_use_es (paint_context))
442 glDrawBufferepoxy_glDrawBuffer (GL_BACK0x0405);
443 else
444 {
445 int maj, min;
446
447 cdk_gl_context_get_version (paint_context, &maj, &min);
448
449 /* ... but on GLES 3.0 we can use the vectorized glDrawBuffers
450 * call.
451 */
452 if ((maj * 100 + min) >= 300)
453 {
454 static const GLenum buffers[] = { GL_BACK0x0405 };
455
456 glDrawBuffersepoxy_glDrawBuffers (G_N_ELEMENTS (buffers)(sizeof (buffers) / sizeof ((buffers)[0])), buffers);
457 }
458 }
459
460#define FLIP_Y(_y) (unscaled_window_height - (_y))
461
462 for (i = 0; i < cairo_region_num_rectangles (clip_region); i++)
463 {
464 cairo_rectangle_int_t clip_rect, dest;
465
466 cairo_region_get_rectangle (clip_region, i, &clip_rect);
467 clip_rect.x *= window_scale;
468 clip_rect.y *= window_scale;
469 clip_rect.width *= window_scale;
470 clip_rect.height *= window_scale;
471
472 glScissorepoxy_glScissor (clip_rect.x, FLIP_Y (clip_rect.y + clip_rect.height),
473 clip_rect.width, clip_rect.height);
474
475 dest.x = dx * window_scale;
476 dest.y = dy * window_scale;
477 dest.width = width * window_scale / buffer_scale;
478 dest.height = height * window_scale / buffer_scale;
479
480 if (cdk_rectangle_intersect (&clip_rect, &dest, &dest))
481 {
482 int clipped_src_x = x + (dest.x - dx * window_scale);
483 int clipped_src_y = y + (height - dest.height - (dest.y - dy * window_scale));
484 glBlitFramebufferEXTepoxy_glBlitFramebufferEXT(clipped_src_x, clipped_src_y,
485 (clipped_src_x + dest.width), (clipped_src_y + dest.height),
486 dest.x, FLIP_Y(dest.y + dest.height),
487 dest.x + dest.width, FLIP_Y(dest.y),
488 GL_COLOR_BUFFER_BIT0x00004000, GL_NEAREST0x2600);
489 if (impl_window->current_paint.flushed_region)
490 {
491 cairo_rectangle_int_t flushed_rect;
492
493 flushed_rect.x = dest.x / window_scale;
494 flushed_rect.y = dest.y / window_scale;
495 flushed_rect.width = (dest.x + dest.width + window_scale - 1) / window_scale - flushed_rect.x;
496 flushed_rect.height = (dest.y + dest.height + window_scale - 1) / window_scale - flushed_rect.y;
497
498 cairo_region_union_rectangle (impl_window->current_paint.flushed_region,
499 &flushed_rect);
500 cairo_region_subtract_rectangle (impl_window->current_paint.need_blend_region,
501 &flushed_rect);
502 }
503 }
504 }
505
506 glDisableepoxy_glDisable (GL_SCISSOR_TEST0x0C11);
507
508 glBindFramebufferEXTepoxy_glBindFramebufferEXT (GL_FRAMEBUFFER_EXT0x8D40, 0);
509
510#undef FLIP_Y
511
512 }
513 /* For direct paint of alpha or non-alpha textures we can use texturing */
514 else if ((_cdk_gl_flags & CDK_GL_SOFTWARE_DRAW_GL) == 0 &&
515 source_type == GL_TEXTURE0x1702 &&
516 direct_window != NULL((void*)0) &&
517 direct_window->current_paint.use_gl &&
518 trivial_transform &&
519 clip_region != NULL((void*)0))
520 {
521 int unscaled_window_height;
522 GLint texture_width;
523 GLint texture_height;
524 int i, n_rects, n_quads;
525 CdkTexturedQuad *quads;
526 cairo_rectangle_int_t clip_rect;
527
528 /* Translate to impl coords */
529 cairo_region_translate (clip_region, dx, dy);
530
531 if (alpha_size != 0)
532 {
533 cairo_region_t *opaque_region, *blend_region;
534
535 opaque_region = cairo_region_copy (clip_region);
536 cairo_region_subtract (opaque_region, impl_window->current_paint.flushed_region);
537 cairo_region_subtract (opaque_region, impl_window->current_paint.need_blend_region);
538
539 if (!cairo_region_is_empty (opaque_region))
540 cdk_gl_texture_from_surface (impl_window->current_paint.surface,
541 opaque_region);
542
543 blend_region = cairo_region_copy (clip_region);
544 cairo_region_intersect (blend_region, impl_window->current_paint.need_blend_region);
545
546 glEnableepoxy_glEnable (GL_BLEND0x0BE2);
547 if (!cairo_region_is_empty (blend_region))
548 cdk_gl_texture_from_surface (impl_window->current_paint.surface,
549 blend_region);
550
551 cairo_region_destroy (opaque_region);
552 cairo_region_destroy (blend_region);
553 }
554
555 glBindTextureepoxy_glBindTexture (GL_TEXTURE_2D0x0DE1, source);
556
557 if (cdk_gl_context_get_use_es (paint_context))
558 {
559 texture_width = width;
560 texture_height = height;
561 }
562 else
563 {
564 glGetTexLevelParameterivepoxy_glGetTexLevelParameteriv (GL_TEXTURE_2D0x0DE1, 0, GL_TEXTURE_WIDTH0x1000, &texture_width);
565 glGetTexLevelParameterivepoxy_glGetTexLevelParameteriv (GL_TEXTURE_2D0x0DE1, 0, GL_TEXTURE_HEIGHT0x1001, &texture_height);
566 }
567
568 glTexParameteriepoxy_glTexParameteri (GL_TEXTURE_2D0x0DE1, GL_TEXTURE_WRAP_S0x2802, GL_REPEAT0x2901);
569 glTexParameteriepoxy_glTexParameteri (GL_TEXTURE_2D0x0DE1, GL_TEXTURE_WRAP_T0x2803, GL_REPEAT0x2901);
570 glTexParameteriepoxy_glTexParameteri (GL_TEXTURE_2D0x0DE1, GL_TEXTURE_MIN_FILTER0x2801, GL_NEAREST0x2600);
571 glTexParameteriepoxy_glTexParameteri (GL_TEXTURE_2D0x0DE1, GL_TEXTURE_MAG_FILTER0x2800, GL_NEAREST0x2600);
572
573 glEnableepoxy_glEnable (GL_SCISSOR_TEST0x0C11);
574
575 cdk_window_get_unscaled_size (impl_window, NULL((void*)0), &unscaled_window_height);
576
577#define FLIP_Y(_y) (unscaled_window_height - (_y))
578
579 cairo_region_get_extents (clip_region, &clip_rect);
580
581 glScissorepoxy_glScissor (clip_rect.x * window_scale, FLIP_Y ((clip_rect.y + clip_rect.height) * window_scale),
582 clip_rect.width * window_scale, clip_rect.height * window_scale);
583
584 n_quads = 0;
585 n_rects = cairo_region_num_rectangles (clip_region);
586 quads = g_new (CdkTexturedQuad, n_rects)((CdkTexturedQuad *) g_malloc_n ((n_rects), sizeof (CdkTexturedQuad
)))
;
587 for (i = 0; i < n_rects; i++)
588 {
589 cairo_rectangle_int_t dest;
590
591 cairo_region_get_rectangle (clip_region, i, &clip_rect);
592
593 clip_rect.x *= window_scale;
594 clip_rect.y *= window_scale;
595 clip_rect.width *= window_scale;
596 clip_rect.height *= window_scale;
597
598 dest.x = dx * window_scale;
599 dest.y = dy * window_scale;
600 dest.width = width * window_scale / buffer_scale;
601 dest.height = height * window_scale / buffer_scale;
602
603 if (cdk_rectangle_intersect (&clip_rect, &dest, &dest))
604 {
605 int clipped_src_x = x + (dest.x - dx * window_scale);
606 int clipped_src_y = y + (height - dest.height - (dest.y - dy * window_scale));
607 CdkTexturedQuad quad = {
608 dest.x, FLIP_Y(dest.y),
609 dest.x + dest.width, FLIP_Y(dest.y + dest.height),
610 clipped_src_x / (float)texture_width, (clipped_src_y + dest.height) / (float)texture_height,
611 (clipped_src_x + dest.width) / (float)texture_width, clipped_src_y / (float)texture_height,
612 };
613
614 quads[n_quads++] = quad;
615
616 if (impl_window->current_paint.flushed_region)
617 {
618 cairo_rectangle_int_t flushed_rect;
619
620 flushed_rect.x = dest.x / window_scale;
621 flushed_rect.y = dest.y / window_scale;
622 flushed_rect.width = (dest.x + dest.width + window_scale - 1) / window_scale - flushed_rect.x;
623 flushed_rect.height = (dest.y + dest.height + window_scale - 1) / window_scale - flushed_rect.y;
624
625 cairo_region_union_rectangle (impl_window->current_paint.flushed_region,
626 &flushed_rect);
627 cairo_region_subtract_rectangle (impl_window->current_paint.need_blend_region,
628 &flushed_rect);
629 }
630 }
631 }
632
633 if (n_quads > 0)
634 cdk_gl_texture_quads (paint_context, GL_TEXTURE_2D0x0DE1, n_quads, quads, FALSE(0));
635
636 g_free (quads);
637
638 if (alpha_size != 0)
639 glDisableepoxy_glDisable (GL_BLEND0x0BE2);
640
641#undef FLIP_Y
642
643 }
644 else
645 {
646 /* Software fallback */
647 int major, minor, version;
648 gboolean es_read_bgra = FALSE(0);
649
650#ifdef CDK_WINDOWING_WIN32
651 /* on ANGLE GLES, we need to set the glReadPixel() format as GL_BGRA instead */
652 if (CDK_WIN32_IS_GL_CONTEXT(paint_context))
653 es_read_bgra = TRUE(!(0));
654#endif
655
656 cdk_gl_context_get_version (paint_context, &major, &minor);
657 version = major * 100 + minor;
658
659 /* TODO: Use glTexSubImage2D() and do a row-by-row copy to replace
660 * the GL_UNPACK_ROW_LENGTH support
661 */
662 if (cdk_gl_context_get_use_es (paint_context) &&
663 !(version >= 300 || cdk_gl_context_has_unpack_subimage (paint_context)))
664 goto out;
665
666 /* TODO: avoid reading back non-required data due to dest clip */
667 image = cairo_surface_create_similar_image (cairo_get_target (cr),
668 (alpha_size == 0) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32,
669 width, height);
670
671 cairo_surface_set_device_scale (image, buffer_scale, buffer_scale);
672
673 framebuffer = paint_data->tmp_framebuffer;
674 glBindFramebufferEXTepoxy_glBindFramebufferEXT (GL_FRAMEBUFFER_EXT0x8D40, framebuffer);
675
676 if (source_type == GL_RENDERBUFFER0x8D41)
677 {
678 /* Create a framebuffer with the source renderbuffer and
679 make it the current target for reads */
680 glFramebufferRenderbufferEXTepoxy_glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT0x8D40, GL_COLOR_ATTACHMENT0_EXT0x8CE0,
681 GL_RENDERBUFFER_EXT0x8D41, source);
682 }
683 else
684 {
685 glFramebufferTexture2DEXTepoxy_glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT0x8D40, GL_COLOR_ATTACHMENT0_EXT0x8CE0,
686 GL_TEXTURE_2D0x0DE1, source, 0);
687 }
688
689 glPixelStoreiepoxy_glPixelStorei (GL_PACK_ALIGNMENT0x0D05, 4);
690 glPixelStoreiepoxy_glPixelStorei (GL_PACK_ROW_LENGTH0x0D02, cairo_image_surface_get_stride (image) / 4);
691
692 /* The implicit format conversion is going to make this path slower */
693 if (!cdk_gl_context_get_use_es (paint_context))
694 glReadPixelsepoxy_glReadPixels (x, y, width, height, GL_BGRA0x80E1, GL_UNSIGNED_INT_8_8_8_8_REV0x8367,
695 cairo_image_surface_get_data (image));
696 else
697 glReadPixelsepoxy_glReadPixels (x, y, width, height, es_read_bgra ? GL_BGRA0x80E1 : GL_RGBA0x1908, GL_UNSIGNED_BYTE0x1401,
This statement is never executed
698 cairo_image_surface_get_data (image));
699
700 glPixelStoreiepoxy_glPixelStorei (GL_PACK_ROW_LENGTH0x0D02, 0);
701
702 glBindFramebufferEXTepoxy_glBindFramebufferEXT (GL_FRAMEBUFFER_EXT0x8D40, 0);
703
704 cairo_surface_mark_dirty (image);
705
706 /* Invert due to opengl having different origin */
707 cairo_scale (cr, 1, -1);
708 cairo_translate (cr, 0, -height / buffer_scale);
709
710 cairo_set_source_surface (cr, image, 0, 0);
711 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
712 cairo_paint (cr);
713
714 cairo_surface_destroy (image);
715 }
716
717out:
718 if (clip_region)
719 cairo_region_destroy (clip_region);
720
721}
722
723/* This is always called with the paint context current */
724void
725cdk_gl_texture_from_surface (cairo_surface_t *surface,
726 cairo_region_t *region)
727{
728 CdkGLContext *paint_context;
729 cairo_surface_t *image;
730 double device_x_offset, device_y_offset;
731 cairo_rectangle_int_t rect, e;
732 int n_rects, i;
733 CdkWindow *window;
734 int unscaled_window_height;
735 unsigned int texture_id;
736 int window_scale;
737 double sx, sy;
738 float umax, vmax;
739 gboolean use_texture_rectangle;
740 guint target;
741 paint_context = cdk_gl_context_get_current ();
742 if ((_cdk_gl_flags & CDK_GL_SOFTWARE_DRAW_SURFACE) == 0 &&
743 paint_context &&
744 CDK_GL_CONTEXT_GET_CLASS (paint_context)((((CdkGLContextClass*) (((GTypeInstance*) ((paint_context)))
->g_class))))
->texture_from_surface &&
745 CDK_GL_CONTEXT_GET_CLASS (paint_context)((((CdkGLContextClass*) (((GTypeInstance*) ((paint_context)))
->g_class))))
->texture_from_surface (paint_context, surface, region))
746 return;
747
748 /* Software fallback */
749 use_texture_rectangle = cdk_gl_context_use_texture_rectangle (paint_context);
750
751 window = cdk_gl_context_get_window (paint_context);
752 window_scale = cdk_window_get_scale_factor (window);
753 cdk_window_get_unscaled_size (window, NULL((void*)0), &unscaled_window_height);
754
755 sx = sy = 1;
756 cairo_surface_get_device_scale (window->current_paint.surface, &sx, &sy);
757
758 cairo_surface_get_device_offset (surface,
759 &device_x_offset, &device_y_offset);
760
761 glGenTexturesepoxy_glGenTextures (1, &texture_id);
762 if (use_texture_rectangle)
763 target = GL_TEXTURE_RECTANGLE_ARB0x84F5;
764 else
765 target = GL_TEXTURE_2D0x0DE1;
766
767 glBindTextureepoxy_glBindTexture (target, texture_id);
768 glEnableepoxy_glEnable (GL_SCISSOR_TEST0x0C11);
769
770 glTexParameteriepoxy_glTexParameteri (target, GL_TEXTURE_WRAP_S0x2802, GL_CLAMP_TO_EDGE0x812F);
771 glTexParameteriepoxy_glTexParameteri (target, GL_TEXTURE_WRAP_T0x2803, GL_CLAMP_TO_EDGE0x812F);
772 glTexParameteriepoxy_glTexParameteri (target, GL_TEXTURE_MIN_FILTER0x2801, GL_NEAREST0x2600);
773 glTexParameteriepoxy_glTexParameteri (target, GL_TEXTURE_MAG_FILTER0x2800, GL_NEAREST0x2600);
774
775 n_rects = cairo_region_num_rectangles (region);
776
777#define FLIP_Y(_y) (unscaled_window_height - (_y))
778
779 for (i = 0; i < n_rects; i++)
780 {
781 cairo_region_get_rectangle (region, i, &rect);
782
783 glScissorepoxy_glScissor (rect.x * window_scale, FLIP_Y ((rect.y + rect.height) * window_scale),
784 rect.width * window_scale, rect.height * window_scale);
785
786 e = rect;
787 e.x *= sx;
788 e.y *= sy;
789 e.x += (int)device_x_offset;
790 e.y += (int)device_y_offset;
791 e.width *= sx;
792 e.height *= sy;
793 image = cairo_surface_map_to_image (surface, &e);
794
795 cdk_gl_context_upload_texture (paint_context, image, e.width, e.height, target);
796
797 cairo_surface_unmap_image (surface, image);
798
799 if (use_texture_rectangle)
800 {
801 umax = rect.width * sx;
802 vmax = rect.height * sy;
803 }
804 else
805 {
806 umax = 1.0;
807 vmax = 1.0;
808 }
809
810 {
811 CdkTexturedQuad quad = {
812 rect.x * window_scale, FLIP_Y(rect.y * window_scale),
813 (rect.x + rect.width) * window_scale, FLIP_Y((rect.y + rect.height) * window_scale),
814 0, 0,
815 umax, vmax,
816 };
817
818 /* We don't want to combine the quads here, because they have different textures.
819 * And we don't want to upload the unused source areas to make it one texture. */
820 cdk_gl_texture_quads (paint_context, target, 1, &quad, TRUE(!(0)));
821 }
822 }
823
824#undef FLIP_Y
825
826 glDisableepoxy_glDisable (GL_SCISSOR_TEST0x0C11);
827 glDeleteTexturesepoxy_glDeleteTextures (1, &texture_id);
828}