/** * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * * 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. The Blender * Foundation also sells licenses for use in proprietary software under * the Blender License. See http://www.blender.org/BL/ for information * about this. * * 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, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2005 Blender Foundation. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): Brecht Van Lommel. * * ***** END GPL LICENSE BLOCK ***** */ #include "GL/glew.h" #include "DNA_listBase.h" #include "DNA_image_types.h" #include "DNA_userdef_types.h" #include "MEM_guardedalloc.h" #include "BKE_image.h" #include "BKE_global.h" #include "BKE_utildefines.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "BLI_blenlib.h" #include "GPU_draw.h" #include "GPU_extensions.h" #include #include #include /* Extensions support */ /* extensions used: - texture border clamp: 1.3 core - fragement shader: 2.0 core - framebuffer object: ext specification - multitexture 1.3 core - arb non power of two: 2.0 core - pixel buffer objects? 2.1 core - arb draw buffers? 2.0 core */ struct GPUGlobal { GLint maxtextures; GLuint currentfb; int minimumsupport; } GG = {1, 0, 0}; void GPU_extensions_init() { glewInit(); /* glewIsSupported("GL_VERSION_2_0") */ if (GLEW_ARB_multitexture) glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &GG.maxtextures); GG.minimumsupport = 1; if (!GLEW_ARB_multitexture) GG.minimumsupport = 0; if (!GLEW_ARB_vertex_shader) GG.minimumsupport = 0; if (!GLEW_ARB_fragment_shader) GG.minimumsupport = 0; } int GPU_extensions_minimum_support() { return GG.minimumsupport; } int GPU_print_error(char *str) { GLenum errCode; if (G.f & G_DEBUG) { if ((errCode = glGetError()) != GL_NO_ERROR) { fprintf(stderr, "%s opengl error: %s\n", str, gluErrorString(errCode)); return 1; } } return 0; } static void GPU_print_framebuffer_error(GLenum status) { fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d\n", (int)status); switch(status) { case GL_FRAMEBUFFER_COMPLETE_EXT: break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: fprintf(stderr, "Incomplete attachment.\n"); break; case GL_FRAMEBUFFER_UNSUPPORTED_EXT: fprintf(stderr, "Unsupported framebuffer format.\n"); break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: fprintf(stderr, "Missing attachment.\n"); break; case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: fprintf(stderr, "Attached images must have same dimensions.\n"); break; case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: fprintf(stderr, "Attached images must have same format.\n"); break; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: fprintf(stderr, "Missing draw buffer.\n"); break; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: fprintf(stderr, "Missing read buffer.\n"); break; default: fprintf(stderr, "Unknown.\n"); break; } } /* GPUTexture */ struct GPUTexture { int w, h; /* width/height */ int number; /* number for multitexture binding */ int refcount; /* reference count */ GLenum target; /* GL_TEXTURE_* */ GLuint bindcode; /* opengl identifier for texture */ int fromblender; /* we got the texture from Blender */ GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */ int depth; /* is a depth texture? */ }; static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels) { unsigned char *pixels, *p; float *fp; int a, len; len = 4*length; fp = fpixels; p = pixels = MEM_callocN(sizeof(unsigned char)*len, "GPUTexturePixels"); for (a=0; aw = w; tex->h = h; tex->number = -1; tex->refcount = 1; tex->target = (n == 1)? GL_TEXTURE_1D: GL_TEXTURE_2D; tex->depth = depth; glGenTextures(1, &tex->bindcode); if (!tex->bindcode) { fprintf(stderr, "GPUTexture: texture create failed: %d\n", (int)glGetError()); GPU_texture_free(tex); return NULL; } if (!GLEW_ARB_texture_non_power_of_two) { tex->w = larger_pow2(tex->w); tex->h = larger_pow2(tex->h); } tex->number = 0; glBindTexture(tex->target, tex->bindcode); if(depth) { type = GL_UNSIGNED_BYTE; format = GL_DEPTH_COMPONENT; internalformat = GL_DEPTH_COMPONENT; } else { type = GL_UNSIGNED_BYTE; format = GL_RGBA; internalformat = GL_RGBA8; if (fpixels) pixels = GPU_texture_convert_pixels(w*h, fpixels); } if (tex->target == GL_TEXTURE_1D) { glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, 0); if (fpixels) { glTexSubImage1D(tex->target, 0, 0, w, format, type, pixels? pixels: fpixels); if (tex->w > w) GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w-w, 1); } } else { glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, format, type, 0); if (fpixels) { glTexSubImage2D(tex->target, 0, 0, 0, w, h, format, type, pixels? pixels: fpixels); if (tex->w > w) GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w-w, tex->h); if (tex->h > h) GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h-h); } } if (pixels) MEM_freeN(pixels); if(depth) { glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE); glTexParameteri(tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); glTexParameteri(tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); } else { glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } if (tex->target != GL_TEXTURE_1D) { /* CLAMP_TO_BORDER is an OpenGL 1.3 core feature */ GLenum wrapmode = (depth)? GL_CLAMP_TO_EDGE: GL_CLAMP_TO_BORDER; glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, wrapmode); glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, wrapmode); #if 0 float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); #endif } else glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); return tex; } GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, double time) { GPUTexture *tex; GLint w, h, border, lastbindcode, bindcode; glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode); GPU_update_image_time(ima, time); bindcode = GPU_verify_image(ima, 0, 0, 0); if(ima->gputexture) { ima->gputexture->bindcode = bindcode; glBindTexture(GL_TEXTURE_2D, lastbindcode); return ima->gputexture; } if(!bindcode) { glBindTexture(GL_TEXTURE_2D, lastbindcode); return NULL; } tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->bindcode = bindcode; tex->number = -1; tex->refcount = 1; tex->target = GL_TEXTURE_2D; tex->fromblender = 1; ima->gputexture= tex; if (!glIsTexture(tex->bindcode)) { GPU_print_error("Blender Texture"); } else { glBindTexture(GL_TEXTURE_2D, tex->bindcode); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border); tex->w = w - border; tex->h = h - border; } glBindTexture(GL_TEXTURE_2D, lastbindcode); return tex; } GPUTexture *GPU_texture_create_1D(int w, float *fpixels) { GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0); if (tex) GPU_texture_unbind(tex); return tex; } GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels) { GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0); if (tex) GPU_texture_unbind(tex); return tex; } GPUTexture *GPU_texture_create_depth(int w, int h) { GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1); if (tex) GPU_texture_unbind(tex); return tex; } void GPU_texture_bind(GPUTexture *tex, int number) { GLenum arbnumber; if (number >= GG.maxtextures) { GPU_print_error("Not enough texture slots."); return; } if(number == -1) return; GPU_print_error("Pre Texture Bind"); arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + number); if (number != 0) glActiveTextureARB(arbnumber); glBindTexture(tex->target, tex->bindcode); glEnable(tex->target); if (number != 0) glActiveTextureARB(GL_TEXTURE0_ARB); tex->number = number; GPU_print_error("Post Texture Bind"); } void GPU_texture_unbind(GPUTexture *tex) { GLenum arbnumber; if (tex->number >= GG.maxtextures) { GPU_print_error("Not enough texture slots."); return; } if(tex->number == -1) return; GPU_print_error("Pre Texture Unbind"); arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number); if (tex->number != 0) glActiveTextureARB(arbnumber); glBindTexture(tex->target, 0); glDisable(tex->target); if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB); tex->number = -1; GPU_print_error("Post Texture Unbind"); } void GPU_texture_free(GPUTexture *tex) { tex->refcount--; if (tex->refcount < 0) fprintf(stderr, "GPUTexture: negative refcount\n"); if (tex->refcount == 0) { if (tex->fb) GPU_framebuffer_texture_detach(tex->fb, tex); if (tex->bindcode && !tex->fromblender) glDeleteTextures(1, &tex->bindcode); MEM_freeN(tex); } } void GPU_texture_ref(GPUTexture *tex) { tex->refcount++; } int GPU_texture_target(GPUTexture *tex) { return tex->target; } int GPU_texture_opengl_width(GPUTexture *tex) { return tex->w; } int GPU_texture_opengl_height(GPUTexture *tex) { return tex->h; } GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex) { return tex->fb; } /* GPUFrameBuffer */ struct GPUFrameBuffer { GLuint object; GPUTexture *colortex; GPUTexture *depthtex; }; GPUFrameBuffer *GPU_framebuffer_create() { GPUFrameBuffer *fb; if (!GLEW_EXT_framebuffer_object) return NULL; fb= MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); glGenFramebuffersEXT(1, &fb->object); if (!fb->object) { fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n", (int)glGetError()); GPU_framebuffer_free(fb); return NULL; } return fb; } int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex) { GLenum status; GLenum attachment; if(tex->depth) attachment = GL_DEPTH_ATTACHMENT_EXT; else attachment = GL_COLOR_ATTACHMENT0_EXT; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); GG.currentfb = fb->object; glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, tex->target, tex->bindcode, 0); if(tex->depth) { glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); } else { glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); glReadBuffer(GL_NONE); } status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { GPU_framebuffer_restore(); GPU_print_framebuffer_error(status); return 0; } if(tex->depth) fb->depthtex = tex; else fb->colortex = tex; tex->fb= fb; return 1; } void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex) { GLenum attachment; if(!tex->fb) return; if(GG.currentfb != tex->fb->object) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object); GG.currentfb = tex->fb->object; } if(tex->depth) { fb->depthtex = NULL; attachment = GL_DEPTH_ATTACHMENT_EXT; } else { fb->colortex = NULL; attachment = GL_COLOR_ATTACHMENT0_EXT; } glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, tex->target, 0, 0); tex->fb = NULL; } void GPU_framebuffer_texture_bind(GPUFrameBuffer *fb, GPUTexture *tex) { /* push attributes */ glPushAttrib(GL_ENABLE_BIT); glPushAttrib(GL_VIEWPORT_BIT); glDisable(GL_SCISSOR_TEST); /* bind framebuffer */ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object); /* push matrices and set default viewport and matrix */ glViewport(0, 0, tex->w, tex->h); GG.currentfb = tex->fb->object; glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); } void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *tex) { /* restore matrix */ glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); /* restore attributes */ glPopAttrib(); glPopAttrib(); glEnable(GL_SCISSOR_TEST); } void GPU_framebuffer_free(GPUFrameBuffer *fb) { if(fb->depthtex) GPU_framebuffer_texture_detach(fb, fb->depthtex); if(fb->colortex) GPU_framebuffer_texture_detach(fb, fb->colortex); if(fb->object) { glDeleteFramebuffersEXT(1, &fb->object); if (GG.currentfb == fb->object) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); GG.currentfb = 0; } } MEM_freeN(fb); } void GPU_framebuffer_restore() { if (GG.currentfb != 0) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); GG.currentfb = 0; } } /* GPUShader */ struct GPUShader { GLhandleARB object; /* handle for full shader */ GLhandleARB vertex; /* handle for vertex shader */ GLhandleARB fragment; /* handle for fragment shader */ GLhandleARB lib; /* handle for libment shader */ int totattrib; /* total number of attributes */ }; static void shader_print_errors(char *task, char *log, const char *code) { const char *c, *pos, *end = code + strlen(code); int line = 1; fprintf(stderr, "GPUShader: %s error:\n", task); if(G.f & G_DEBUG) { c = code; while ((c < end) && (pos = strchr(c, '\n'))) { fprintf(stderr, "%2d ", line); fwrite(c, (pos+1)-c, 1, stderr); c = pos+1; line++; } fprintf(stderr, "%s", c); } fprintf(stderr, "%s\n", log); } GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPUShader *lib,*/ const char *libcode) { GLint status; GLcharARB log[5000]; const char *fragsource[2]; GLsizei length = 0; GLint count; GPUShader *shader; if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader) return NULL; shader = MEM_callocN(sizeof(GPUShader), "GPUShader"); if(vertexcode) shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); if(fragcode) shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); shader->object = glCreateProgramObjectARB(); if (!shader->object || (vertexcode && !shader->vertex) || (fragcode && !shader->fragment)) { fprintf(stderr, "GPUShader, object creation failed.\n"); GPU_shader_free(shader); return NULL; } if(vertexcode) { glAttachObjectARB(shader->object, shader->vertex); glShaderSourceARB(shader->vertex, 1, (const char**)&vertexcode, NULL); glCompileShaderARB(shader->vertex); glGetObjectParameterivARB(shader->vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status); if (!status) { glGetInfoLogARB(shader->vertex, sizeof(log), &length, log); shader_print_errors("compile", log, vertexcode); GPU_shader_free(shader); return NULL; } } if(fragcode) { count = 0; if(libcode) fragsource[count++] = libcode; if(fragcode) fragsource[count++] = fragcode; glAttachObjectARB(shader->object, shader->fragment); glShaderSourceARB(shader->fragment, count, fragsource, NULL); glCompileShaderARB(shader->fragment); glGetObjectParameterivARB(shader->fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status); if (!status) { glGetInfoLogARB(shader->fragment, sizeof(log), &length, log); shader_print_errors("compile", log, fragcode); GPU_shader_free(shader); return NULL; } } /*if(lib && lib->lib) glAttachObjectARB(shader->object, lib->lib);*/ glLinkProgramARB(shader->object); glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status); if (!status) { glGetInfoLogARB(shader->object, sizeof(log), &length, log); shader_print_errors("linking", log, fragcode); GPU_shader_free(shader); return NULL; } return shader; } #if 0 GPUShader *GPU_shader_create_lib(const char *code) { GLint status; GLcharARB log[5000]; GLsizei length = 0; GPUShader *shader; if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader) return NULL; shader = MEM_callocN(sizeof(GPUShader), "GPUShader"); shader->lib = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); if (!shader->lib) { fprintf(stderr, "GPUShader, object creation failed.\n"); GPU_shader_free(shader); return NULL; } glShaderSourceARB(shader->lib, 1, (const char**)&code, NULL); glCompileShaderARB(shader->lib); glGetObjectParameterivARB(shader->lib, GL_OBJECT_COMPILE_STATUS_ARB, &status); if (!status) { glGetInfoLogARB(shader->lib, sizeof(log), &length, log); shader_print_errors("compile", log, code); GPU_shader_free(shader); return NULL; } return shader; } #endif void GPU_shader_bind(GPUShader *shader) { GPU_print_error("Pre Shader Bind"); glUseProgramObjectARB(shader->object); GPU_print_error("Post Shader Bind"); } void GPU_shader_unbind() { GPU_print_error("Pre Shader Unbind"); glUseProgramObjectARB(0); GPU_print_error("Post Shader Unbind"); } void GPU_shader_free(GPUShader *shader) { if (shader->lib) glDeleteObjectARB(shader->lib); if (shader->vertex) glDeleteObjectARB(shader->vertex); if (shader->fragment) glDeleteObjectARB(shader->fragment); if (shader->object) glDeleteObjectARB(shader->object); MEM_freeN(shader); } int GPU_shader_get_uniform(GPUShader *shader, char *name) { return glGetUniformLocationARB(shader->object, name); } void GPU_shader_uniform_vector(GPUShader *shader, int location, int length, int arraysize, float *value) { if(location == -1) return; GPU_print_error("Pre Uniform Vector"); if (length == 1) glUniform1fvARB(location, arraysize, value); else if (length == 2) glUniform2fvARB(location, arraysize, value); else if (length == 3) glUniform3fvARB(location, arraysize, value); else if (length == 4) glUniform4fvARB(location, arraysize, value); else if (length == 9) glUniformMatrix3fvARB(location, arraysize, 0, value); else if (length == 16) glUniformMatrix4fvARB(location, arraysize, 0, value); GPU_print_error("Post Uniform Vector"); } void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex) { GLenum arbnumber; if (tex->number >= GG.maxtextures) { GPU_print_error("Not enough texture slots."); return; } if(tex->number == -1) return; if(location == -1) return; GPU_print_error("Pre Uniform Texture"); arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number); if (tex->number != 0) glActiveTextureARB(arbnumber); glBindTexture(tex->target, tex->bindcode); glUniform1iARB(location, tex->number); glEnable(tex->target); if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB); GPU_print_error("Post Uniform Texture"); } int GPU_shader_get_attribute(GPUShader *shader, char *name) { int index; GPU_print_error("Pre Get Attribute"); index = glGetAttribLocationARB(shader->object, name); GPU_print_error("Post Get Attribute"); return index; } #if 0 /* GPUPixelBuffer */ typedef struct GPUPixelBuffer { GLuint bindcode[2]; GLuint current; int datasize; int numbuffers; int halffloat; } GPUPixelBuffer; void GPU_pixelbuffer_free(GPUPixelBuffer *pb) { if (pb->bindcode[0]) glDeleteBuffersARB(pb->numbuffers, pb->bindcode); MEM_freeN(pb); } GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffers) { GPUPixelBuffer *pb; if (!GLEW_ARB_multitexture || !GLEW_EXT_pixel_buffer_object) return NULL; pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO"); pb->datasize = x*y*4*((halffloat)? 16: 8); pb->numbuffers = numbuffers; pb->halffloat = halffloat; glGenBuffersARB(pb->numbuffers, pb->bindcode); if (!pb->bindcode[0]) { fprintf(stderr, "GPUPixelBuffer allocation failed\n"); GPU_pixelbuffer_free(pb); return NULL; } return pb; } void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb) { void *pixels; int i; glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode); for (i = 0; i < pb->numbuffers; i++) { glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->bindcode[pb->current]); glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->datasize, NULL, GL_STREAM_DRAW_ARB); pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY); /*memcpy(pixels, _oImage.data(), pb->datasize);*/ if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) { fprintf(stderr, "Could not unmap opengl PBO\n"); break; } } glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0); } static int pixelbuffer_map_into_gpu(GLuint bindcode) { void *pixels; glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode); pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY); /* do stuff in pixels */ if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) { fprintf(stderr, "Could not unmap opengl PBO\n"); return 0; } return 1; } static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLuint bindcode) { GLenum type = (pb->halffloat)? GL_HALF_FLOAT_NV: GL_UNSIGNED_BYTE; glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode); glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode); glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h, GL_RGBA, type, NULL); glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0); glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0); } void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb) { int newbuffer; if (pb->numbuffers == 1) { pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[0]); pixelbuffer_map_into_gpu(pb->bindcode[0]); } else { pb->current = (pb->current+1)%pb->numbuffers; newbuffer = (pb->current+1)%pb->numbuffers; pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]); pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]); } } #endif