diff options
author | Yaniv Kamay <ykamay@redhat.com> | 2009-09-19 21:25:46 +0300 |
---|---|---|
committer | Yaniv Kamay <ykamay@redhat.com> | 2009-10-14 15:06:41 +0200 |
commit | c1b79eb035fa158fb2ac3bc8e559809611070016 (patch) | |
tree | 3348dd749a700dedf87c9b16fe8be77c62928df8 /client/x11/red_pixmap_gl.cpp | |
download | spice-c1b79eb035fa158fb2ac3bc8e559809611070016.tar.gz spice-c1b79eb035fa158fb2ac3bc8e559809611070016.tar.xz spice-c1b79eb035fa158fb2ac3bc8e559809611070016.zip |
fresh start
Diffstat (limited to 'client/x11/red_pixmap_gl.cpp')
-rw-r--r-- | client/x11/red_pixmap_gl.cpp | 317 |
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; +} + |