mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-27 07:29:32 +00:00
312 lines
9.8 KiB
C++
312 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;
|
|
}
|