summaryrefslogtreecommitdiffstats
path: root/client/x11/red_pixmap_gl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'client/x11/red_pixmap_gl.cpp')
-rw-r--r--client/x11/red_pixmap_gl.cpp317
1 files changed, 317 insertions, 0 deletions
diff --git a/client/x11/red_pixmap_gl.cpp b/client/x11/red_pixmap_gl.cpp
new file mode 100644
index 00000000..886bb0b3
--- /dev/null
+++ b/client/x11/red_pixmap_gl.cpp
@@ -0,0 +1,317 @@
+/*
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glext.h>
+#include <X11/Xlib.h>
+
+#include "common.h"
+#include "red_pixmap_gl.h"
+#include "debug.h"
+#include "utils.h"
+#include "gl_utils.h"
+#include "pixels_source_p.h"
+#include "x_platform.h"
+#include "red_window_p.h"
+
+
+RedPixmapGL::RedPixmapGL(int width, int height, RedPixmap::Format format,
+ bool top_bottom, rgb32_t* pallet, RedWindow *win,
+ RenderType rendertype)
+ : RedPixmap(width, height, format, top_bottom, pallet)
+{
+ GLuint fbo;
+ GLuint tex;
+ GLuint stencil_tex = 0;
+ Win xwin;
+ //GLint max_texture_size;
+
+ ASSERT(format == RedPixmap::ARGB32 || format == RedPixmap::RGB32 || format == RedPixmap::A1);
+ ASSERT(sizeof(RedDrawable_p) <= PIXELES_SOURCE_OPAQUE_SIZE);
+
+ ((PixelsSource_p*)get_opaque())->type = PIXELS_SOURCE_TYPE_GL_TEXTURE;
+
+ _glcont = win->create_context_gl();
+ if (!_glcont) {
+ THROW("glXCreateContext failed");
+ }
+
+ win->set_gl_context(_glcont);
+
+ xwin = ((RedWindow_p*)win)->get_window();
+
+ /*glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
+ if (width > max_texture_size || height > max_texture_size) {
+ throw Exception(fmt("%s: unsuported max %|| width %|| height %||")
+ % __FUNCTION__
+ % max_texture_size
+ % width
+ % height);
+ }*/
+
+ if (rendertype == RENDER_TYPE_FBO) {
+ glXMakeCurrent(XPlatform::get_display(), xwin, _glcont);
+ if (!gluCheckExtension((GLubyte *)"GL_EXT_framebuffer_object",
+ glGetString(GL_EXTENSIONS))) {
+ glXMakeCurrent(XPlatform::get_display(), 0, 0);
+ glXDestroyContext(XPlatform::get_display(), _glcont);
+ THROW("no GL_EXT_framebuffer_object extension");
+ }
+ glEnable(GL_TEXTURE_2D);
+ glGenFramebuffersEXT(1, &fbo);
+ glGenTextures(1, &tex);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
+
+ glBindTexture(GL_TEXTURE_2D, tex);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, gl_get_to_power_two(width),
+ gl_get_to_power_two(height), 0, GL_BGRA, GL_UNSIGNED_BYTE,
+ NULL);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, tex, 0);
+
+
+ glGenTextures(1, &stencil_tex);
+ glBindTexture(GL_TEXTURE_2D, stencil_tex);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_EXT,
+ gl_get_to_power_two(width), gl_get_to_power_two(height), 0,
+ GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
+ GL_DEPTH_ATTACHMENT_EXT,
+ GL_TEXTURE_2D, stencil_tex, 0);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
+ GL_STENCIL_ATTACHMENT_EXT,
+ GL_TEXTURE_2D, stencil_tex, 0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ ((PixelsSource_p*)get_opaque())->gl.fbo = fbo;
+ win->set_render_fbo(fbo);
+ } else {
+ GLXPbuffer pbuff;
+
+ pbuff = win->create_pbuff(gl_get_to_power_two(width),
+ gl_get_to_power_two(height));
+ if (!pbuff) {
+ glXDestroyContext(XPlatform::get_display(), _glcont);
+ THROW("pbuff creation failed");
+ }
+ glXMakeCurrent(XPlatform::get_display(), pbuff, _glcont);
+ glEnable(GL_TEXTURE_2D);
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, gl_get_to_power_two(width),
+ gl_get_to_power_two(height), 0, GL_BGRA, GL_UNSIGNED_BYTE,
+ NULL);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ ((PixelsSource_p*)get_opaque())->gl.pbuff = pbuff;
+ win->set_render_pbuff(pbuff);
+ }
+
+ ((PixelsSource_p*)get_opaque())->gl.stencil_tex = stencil_tex;
+ ((PixelsSource_p*)get_opaque())->gl.tex = tex;
+ ((PixelsSource_p*)get_opaque())->gl.width = width;
+ ((PixelsSource_p*)get_opaque())->gl.height = height;
+ ((PixelsSource_p*)get_opaque())->gl.width_powed = gl_get_to_power_two(width);
+ ((PixelsSource_p*)get_opaque())->gl.height_powed = gl_get_to_power_two(height);
+ ((PixelsSource_p*)get_opaque())->gl.win = xwin;
+ ((PixelsSource_p*)get_opaque())->gl.rendertype = rendertype;
+ ((PixelsSource_p*)get_opaque())->gl.context = _glcont;
+
+ _textures_lost = false;
+
+ GLC_ERROR_TEST_FINISH;
+}
+
+void RedPixmapGL::textures_lost()
+{
+ _textures_lost = true;
+}
+
+void RedPixmapGL::touch_context()
+{
+ Win win;
+ GLXPbuffer pbuff;
+ RenderType rendertype;
+
+ rendertype = ((PixelsSource_p*)get_opaque())->gl.rendertype;
+ if (rendertype == RENDER_TYPE_FBO) {
+ win = ((PixelsSource_p*)get_opaque())->gl.win;
+ if (_glcont) {
+ glXMakeCurrent(XPlatform::get_display(), win, _glcont);
+ }
+ } else {
+ pbuff = ((PixelsSource_p*)get_opaque())->gl.pbuff;
+ glXMakeCurrent(XPlatform::get_display(), pbuff, _glcont);
+ }
+ GLC_ERROR_TEST_FLUSH;
+}
+
+void RedPixmapGL::update_texture(const Rect *bbox)
+{
+ RenderType rendertype;
+ GLuint tex;
+ int width_powed;
+ int height_powed;
+ int height;
+ int width;
+
+ rendertype = ((PixelsSource_p*)get_opaque())->gl.rendertype;
+
+ if (rendertype == RENDER_TYPE_PBUFF) {
+ int tex_x, tex_y;
+ int vertex_x1, vertex_x2;
+ int vertex_y1, vertex_y2;
+ int is_enabled;
+ GLint prev_tex;
+
+ width_powed = ((PixelsSource_p*)get_opaque())->gl.width_powed;
+ height_powed = ((PixelsSource_p*)get_opaque())->gl.height_powed;
+ width = ((PixelsSource_p*)get_opaque())->gl.width;
+ height = ((PixelsSource_p*)get_opaque())->gl.height;
+
+ tex = ((PixelsSource_p*)get_opaque())->gl.tex;
+
+ tex_x = bbox->left;
+ tex_y = height - bbox->bottom;
+ vertex_x1 = bbox->left;
+ vertex_y1 = height - bbox->bottom;
+ vertex_x2 = vertex_x1 + (bbox->right - bbox->left);
+ vertex_y2 = vertex_y1 + (bbox->bottom - bbox->top);
+
+ is_enabled = glIsEnabled(GL_TEXTURE_2D);
+ if (!is_enabled) {
+ glEnable(GL_TEXTURE_2D);
+ } else {
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev_tex);
+ }
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, tex_x, tex_y, vertex_x1,
+ vertex_y1, vertex_x2 - vertex_x1,
+ vertex_y2 - vertex_y1);
+ if (!is_enabled) {
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, prev_tex);
+ }
+ }
+ GLC_ERROR_TEST_FLUSH;
+}
+
+void RedPixmapGL::pre_copy()
+{
+ glFlush();
+
+ glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT |
+ GL_TRANSFORM_BIT);
+
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ gluOrtho2D(0, ((PixelsSource_p*)get_opaque())->gl.width, 0,
+ ((PixelsSource_p*)get_opaque())->gl.height);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glViewport(0, 0, ((PixelsSource_p*)get_opaque())->gl.width,
+ ((PixelsSource_p*)get_opaque())->gl.height);
+
+
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glDisable(GL_BLEND);
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ glColor3f(1, 1, 1);
+}
+
+void RedPixmapGL::past_copy()
+{
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_TEXTURE);
+ glPopMatrix();
+
+ glPopAttrib();
+ glFlush();
+}
+
+RedPixmapGL::~RedPixmapGL()
+{
+ GLXPbuffer pbuff;
+ GLuint fbo;
+ RenderType rendertype;
+ GLuint tex;
+ GLuint stencil_tex;
+
+ /*
+ * GL textures might be destroyed by res change.
+ */
+ if (!_textures_lost) {
+ tex = ((PixelsSource_p*)get_opaque())->gl.tex;
+ stencil_tex = ((PixelsSource_p*)get_opaque())->gl.stencil_tex;
+ if (tex) {
+ glDeleteTextures(1, &tex);
+ }
+ if (stencil_tex) {
+ glDeleteTextures(1, &stencil_tex);
+ }
+ if (_glcont) {
+ glXDestroyContext(XPlatform::get_display(), _glcont);
+ }
+ }
+
+ rendertype = ((PixelsSource_p*)get_opaque())->gl.rendertype;
+ if (rendertype == RENDER_TYPE_FBO) {
+ fbo = ((PixelsSource_p*)get_opaque())->gl.fbo;
+ if (fbo) {
+ glDeleteFramebuffersEXT(1, &fbo);
+ }
+ } else {
+ pbuff = ((PixelsSource_p*)get_opaque())->gl.pbuff;
+ glXDestroyPbuffer(XPlatform::get_display(), pbuff);
+ }
+
+ /*
+ * Both tex and stenctil_tex are textures and therefore they are destroyed
+ * when the context is gone, so we dont free them here as they might have
+ * already been destroyed.
+ */
+ GLC_ERROR_TEST_FINISH;
+}
+