uploaded original spice-server-0.12.4 and celt-0.5.1.3
[sdk/emulator/libs/spice-server.git] / client / x11 / red_pixmap_gl.cpp
1 /*
2    Copyright (C) 2009 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.1 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 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20
21 #include <GL/gl.h>
22 #include <GL/glu.h>
23 #include <GL/glext.h>
24 #include <X11/Xlib.h>
25 #include "common/gl_utils.h"
26
27 #include "common.h"
28 #include "red_pixmap_gl.h"
29 #include "debug.h"
30 #include "utils.h"
31 #include "pixels_source_p.h"
32 #include "x_platform.h"
33 #include "red_window_p.h"
34
35
36 RedPixmapGL::RedPixmapGL(int width, int height, RedDrawable::Format format,
37                          bool top_bottom, RedWindow *win,
38                          RenderType rendertype)
39     : RedPixmap(width, height, format, top_bottom)
40 {
41     GLuint fbo;
42     GLuint tex;
43     GLuint stencil_tex = 0;
44     Win xwin;
45     //GLint max_texture_size;
46
47     ASSERT(format == RedDrawable::ARGB32 || format == RedDrawable::RGB32 || format == RedDrawable::A1);
48     ASSERT(sizeof(RedDrawable_p) <= PIXELES_SOURCE_OPAQUE_SIZE);
49
50     ((PixelsSource_p*)get_opaque())->type = PIXELS_SOURCE_TYPE_GL_TEXTURE;
51
52     _glcont = win->create_context_gl();
53     if (!_glcont) {
54         THROW("glXCreateContext failed");
55     }
56
57     win->set_gl_context(_glcont);
58
59     xwin = ((RedWindow_p*)win)->get_window();
60
61     /*glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
62     if (width > max_texture_size || height > max_texture_size) {
63         throw Exception(fmt("%s: unsuported max %|| width %|| height %||")
64                              % __FUNCTION__
65                              % max_texture_size
66                              % width
67                              % height);
68     }*/
69
70     if (rendertype == RENDER_TYPE_FBO) {
71         glXMakeCurrent(XPlatform::get_display(), xwin, _glcont);
72         if (!gluCheckExtension((GLubyte *)"GL_EXT_framebuffer_object",
73                                glGetString(GL_EXTENSIONS))) {
74             glXMakeCurrent(XPlatform::get_display(), 0, 0);
75             glXDestroyContext(XPlatform::get_display(), _glcont);
76             THROW("no GL_EXT_framebuffer_object extension");
77         }
78         glEnable(GL_TEXTURE_2D);
79         glGenFramebuffersEXT(1, &fbo);
80         glGenTextures(1, &tex);
81         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
82
83         glBindTexture(GL_TEXTURE_2D, tex);
84
85         glTexImage2D(GL_TEXTURE_2D, 0, 4, gl_get_to_power_two(width),
86                      gl_get_to_power_two(height), 0, GL_BGRA, GL_UNSIGNED_BYTE,
87                      NULL);
88
89         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
90         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
91
92         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
93                                   GL_TEXTURE_2D, tex, 0);
94
95
96         glGenTextures(1, &stencil_tex);
97         glBindTexture(GL_TEXTURE_2D, stencil_tex);
98         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
99         glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_EXT,
100                      gl_get_to_power_two(width), gl_get_to_power_two(height), 0,
101                      GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
102         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
103                                   GL_DEPTH_ATTACHMENT_EXT,
104                                   GL_TEXTURE_2D, stencil_tex, 0);
105         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
106                                   GL_STENCIL_ATTACHMENT_EXT,
107                                   GL_TEXTURE_2D, stencil_tex, 0);
108         glBindTexture(GL_TEXTURE_2D, 0);
109
110         ((PixelsSource_p*)get_opaque())->gl.fbo = fbo;
111         win->set_render_fbo(fbo);
112     } else {
113         GLXPbuffer pbuff;
114
115         pbuff = win->create_pbuff(gl_get_to_power_two(width),
116                                   gl_get_to_power_two(height));
117         if (!pbuff) {
118             glXDestroyContext(XPlatform::get_display(), _glcont);
119             THROW("pbuff creation failed");
120         }
121         glXMakeCurrent(XPlatform::get_display(), pbuff, _glcont);
122         glEnable(GL_TEXTURE_2D);
123         glGenTextures(1, &tex);
124         glBindTexture(GL_TEXTURE_2D, tex);
125
126         glTexImage2D(GL_TEXTURE_2D, 0, 4, gl_get_to_power_two(width),
127                      gl_get_to_power_two(height), 0, GL_BGRA, GL_UNSIGNED_BYTE,
128                      NULL);
129
130         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
131         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
132
133         glBindTexture(GL_TEXTURE_2D, 0);
134         ((PixelsSource_p*)get_opaque())->gl.pbuff = pbuff;
135         win->set_render_pbuff(pbuff);
136     }
137
138     ((PixelsSource_p*)get_opaque())->gl.stencil_tex = stencil_tex;
139     ((PixelsSource_p*)get_opaque())->gl.tex = tex;
140     ((PixelsSource_p*)get_opaque())->gl.width = width;
141     ((PixelsSource_p*)get_opaque())->gl.height = height;
142     ((PixelsSource_p*)get_opaque())->gl.width_powed = gl_get_to_power_two(width);
143     ((PixelsSource_p*)get_opaque())->gl.height_powed = gl_get_to_power_two(height);
144     ((PixelsSource_p*)get_opaque())->gl.win = xwin;
145     ((PixelsSource_p*)get_opaque())->gl.rendertype = rendertype;
146     ((PixelsSource_p*)get_opaque())->gl.context = _glcont;
147
148     _textures_lost = false;
149
150     GLC_ERROR_TEST_FINISH;
151 }
152
153 void RedPixmapGL::textures_lost()
154 {
155     _textures_lost = true;
156 }
157
158 void RedPixmapGL::touch_context()
159 {
160     Win win;
161     GLXPbuffer pbuff;
162     RenderType rendertype;
163
164     rendertype = ((PixelsSource_p*)get_opaque())->gl.rendertype;
165     if (rendertype == RENDER_TYPE_FBO) {
166         win = ((PixelsSource_p*)get_opaque())->gl.win;
167         if (_glcont) {
168             glXMakeCurrent(XPlatform::get_display(), win, _glcont);
169         }
170     } else {
171         pbuff = ((PixelsSource_p*)get_opaque())->gl.pbuff;
172         glXMakeCurrent(XPlatform::get_display(), pbuff, _glcont);
173     }
174     GLC_ERROR_TEST_FLUSH;
175 }
176
177 void RedPixmapGL::update_texture(const SpiceRect *bbox)
178 {
179     RenderType rendertype;
180     GLuint tex;
181     int height;
182
183     rendertype = ((PixelsSource_p*)get_opaque())->gl.rendertype;
184
185     if (rendertype == RENDER_TYPE_PBUFF) {
186         int tex_x, tex_y;
187         int vertex_x1, vertex_x2;
188         int vertex_y1, vertex_y2;
189         int is_enabled;
190         GLint prev_tex;
191
192         height = ((PixelsSource_p*)get_opaque())->gl.height;
193
194         tex = ((PixelsSource_p*)get_opaque())->gl.tex;
195
196         tex_x = bbox->left;
197         tex_y = height - bbox->bottom;
198         vertex_x1 = bbox->left;
199         vertex_y1 = height - bbox->bottom;
200         vertex_x2 = vertex_x1 + (bbox->right - bbox->left);
201         vertex_y2 = vertex_y1 + (bbox->bottom - bbox->top);
202
203         is_enabled = glIsEnabled(GL_TEXTURE_2D);
204         if (!is_enabled) {
205             glEnable(GL_TEXTURE_2D);
206         } else {
207             glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev_tex);
208         }
209         glBindTexture(GL_TEXTURE_2D, tex);
210         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, tex_x, tex_y, vertex_x1,
211                             vertex_y1, vertex_x2 - vertex_x1,
212                             vertex_y2 - vertex_y1);
213         if (!is_enabled) {
214             glBindTexture(GL_TEXTURE_2D, 0);
215             glDisable(GL_TEXTURE_2D);
216         } else {
217             glBindTexture(GL_TEXTURE_2D, prev_tex);
218         }
219     }
220     GLC_ERROR_TEST_FLUSH;
221 }
222
223 void RedPixmapGL::pre_copy()
224 {
225     glFlush();
226
227     glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT |
228                  GL_TRANSFORM_BIT);
229
230     glMatrixMode(GL_TEXTURE);
231     glPushMatrix();
232     glLoadIdentity();
233
234     glMatrixMode(GL_PROJECTION);
235     glPushMatrix();
236     glLoadIdentity();
237     gluOrtho2D(0, ((PixelsSource_p*)get_opaque())->gl.width, 0,
238                ((PixelsSource_p*)get_opaque())->gl.height);
239
240     glMatrixMode(GL_MODELVIEW);
241     glPushMatrix();
242     glLoadIdentity();
243     glViewport(0, 0, ((PixelsSource_p*)get_opaque())->gl.width,
244                ((PixelsSource_p*)get_opaque())->gl.height);
245
246
247     glDisable(GL_TEXTURE_GEN_S);
248     glDisable(GL_TEXTURE_GEN_T);
249     glDisable(GL_BLEND);
250     glDisable(GL_ALPHA_TEST);
251     glDisable(GL_COLOR_LOGIC_OP);
252
253     glColor3f(1, 1, 1);
254 }
255
256 void RedPixmapGL::past_copy()
257 {
258     glMatrixMode(GL_MODELVIEW);
259     glPopMatrix();
260     glMatrixMode(GL_PROJECTION);
261     glPopMatrix();
262     glMatrixMode(GL_TEXTURE);
263     glPopMatrix();
264
265     glPopAttrib();
266     glFlush();
267 }
268
269 RedPixmapGL::~RedPixmapGL()
270 {
271     GLXPbuffer pbuff;
272     GLuint fbo;
273     RenderType rendertype;
274     GLuint tex;
275     GLuint stencil_tex;
276
277     /*
278      * GL textures might be destroyed by res change.
279      */
280     if (!_textures_lost) {
281         tex = ((PixelsSource_p*)get_opaque())->gl.tex;
282         stencil_tex = ((PixelsSource_p*)get_opaque())->gl.stencil_tex;
283         if (tex) {
284             glDeleteTextures(1, &tex);
285         }
286         if (stencil_tex) {
287             glDeleteTextures(1, &stencil_tex);
288         }
289         if (_glcont) {
290             glXDestroyContext(XPlatform::get_display(), _glcont);
291         }
292     }
293
294     rendertype = ((PixelsSource_p*)get_opaque())->gl.rendertype;
295     if (rendertype == RENDER_TYPE_FBO) {
296         fbo = ((PixelsSource_p*)get_opaque())->gl.fbo;
297         if (fbo) {
298             glDeleteFramebuffersEXT(1, &fbo);
299         }
300     } else {
301         pbuff = ((PixelsSource_p*)get_opaque())->gl.pbuff;
302         glXDestroyPbuffer(XPlatform::get_display(), pbuff);
303     }
304
305     /*
306      * Both tex and stenctil_tex are textures and therefore they are destroyed
307      * when the context is gone, so we dont free them here as they might have
308      * already been destroyed.
309      */
310     GLC_ERROR_TEST_FINISH;
311 }