spice/client/x11/red_pixmap_gl.cpp
Christophe Fergeau 78c1465ed3 add #include <config.h> to all source files
When using config.h, it must be the very first include in all source
files since it contains #define that may change the compilation process
(eg libc structure layout changes when it's used to enable large file
support on 32 bit x86 archs). This commit adds it at the beginning
of all .c and .cpp files
2011-05-03 14:44:10 +02:00

313 lines
9.8 KiB
C++

/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#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, RedDrawable::Format format,
bool top_bottom, RedWindow *win,
RenderType rendertype)
: RedPixmap(width, height, format, top_bottom)
{
GLuint fbo;
GLuint tex;
GLuint stencil_tex = 0;
Win xwin;
//GLint max_texture_size;
ASSERT(format == RedDrawable::ARGB32 || format == RedDrawable::RGB32 || format == RedDrawable::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 SpiceRect *bbox)
{
RenderType rendertype;
GLuint tex;
int height;
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;
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;
}