Blender V2.61 - r43446

gpu_extensions.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2005 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): Brecht Van Lommel.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include "GL/glew.h"
00034 
00035 #include "DNA_image_types.h"
00036 
00037 #include "MEM_guardedalloc.h"
00038 
00039 #include "BKE_global.h"
00040 
00041 
00042 #include "BLI_blenlib.h"
00043 #include "BLI_utildefines.h"
00044 #include "BLI_math_base.h"
00045 
00046 #include "GPU_draw.h"
00047 #include "GPU_extensions.h"
00048 #include "gpu_codegen.h"
00049 
00050 #include <stdlib.h>
00051 #include <stdio.h>
00052 #include <string.h>
00053 
00054 #include "BLI_winstuff.h"
00055 
00056 /* Extensions support */
00057 
00058 /* extensions used:
00059     - texture border clamp: 1.3 core
00060     - fragement shader: 2.0 core
00061     - framebuffer object: ext specification
00062     - multitexture 1.3 core
00063     - arb non power of two: 2.0 core
00064     - pixel buffer objects? 2.1 core
00065     - arb draw buffers? 2.0 core
00066 */
00067 
00068 static struct GPUGlobal {
00069     GLint maxtextures;
00070     GLuint currentfb;
00071     int glslsupport;
00072     int extdisabled;
00073     int colordepth;
00074     int npotdisabled; /* ATI 3xx-5xx (and more) chipsets support NPoT partially (== not enough) */
00075     GPUDeviceType device;
00076     GPUOSType os;
00077     GPUDriverType driver;
00078 } GG = {1, 0, 0, 0, 0};
00079 
00080 /* GPU Types */
00081 
00082 int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
00083 {
00084     return (GG.device & device) && (GG.os & os) && (GG.driver & driver);
00085 }
00086 
00087 /* GPU Extensions */
00088 
00089 static int gpu_extensions_init = 0;
00090 
00091 void GPU_extensions_disable(void)
00092 {
00093     GG.extdisabled = 1;
00094 }
00095 
00096 void GPU_extensions_init(void)
00097 {
00098     GLint r, g, b;
00099     const char *vendor, *renderer;
00100 
00101     /* can't avoid calling this multiple times, see wm_window_add_ghostwindow */
00102     if(gpu_extensions_init) return;
00103     gpu_extensions_init= 1;
00104 
00105     glewInit();
00106     GPU_codegen_init();
00107 
00108     /* glewIsSupported("GL_VERSION_2_0") */
00109 
00110     if (GLEW_ARB_multitexture)
00111         glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &GG.maxtextures);
00112 
00113     GG.glslsupport = 1;
00114     if (!GLEW_ARB_multitexture) GG.glslsupport = 0;
00115     if (!GLEW_ARB_vertex_shader) GG.glslsupport = 0;
00116     if (!GLEW_ARB_fragment_shader) GG.glslsupport = 0;
00117 
00118     glGetIntegerv(GL_RED_BITS, &r);
00119     glGetIntegerv(GL_GREEN_BITS, &g);
00120     glGetIntegerv(GL_BLUE_BITS, &b);
00121     GG.colordepth = r+g+b; /* assumes same depth for RGB */
00122 
00123     vendor = (const char*)glGetString(GL_VENDOR);
00124     renderer = (const char*)glGetString(GL_RENDERER);
00125 
00126     if(strstr(vendor, "ATI")) {
00127         GG.device = GPU_DEVICE_ATI;
00128         GG.driver = GPU_DRIVER_OFFICIAL;
00129 
00130         /* ATI X1xxx cards (R500 chipset) lack full support for npot textures
00131          * although they report the GLEW_ARB_texture_non_power_of_two extension.
00132          */
00133         if(strstr(renderer, "X1"))
00134             GG.npotdisabled = 1;
00135     }
00136     else if(strstr(vendor, "NVIDIA")) {
00137         GG.device = GPU_DEVICE_NVIDIA;
00138         GG.driver = GPU_DRIVER_OFFICIAL;
00139     }
00140     else if(strstr(vendor, "Intel") ||
00141             /* src/mesa/drivers/dri/intel/intel_context.c */
00142             strstr(renderer, "Mesa DRI Intel") ||
00143         strstr(renderer, "Mesa DRI Mobile Intel")) {
00144         GG.device = GPU_DEVICE_INTEL;
00145         GG.driver = GPU_DRIVER_OFFICIAL;
00146     }
00147     else if(strstr(renderer, "Mesa DRI R") || (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI "))) {
00148         GG.device = GPU_DEVICE_ATI;
00149         GG.driver = GPU_DRIVER_OPENSOURCE;
00150         /* ATI 9500 to X2300 cards support NPoT textures poorly
00151          * Incomplete list http://dri.freedesktop.org/wiki/ATIRadeon
00152          * New IDs from MESA's src/gallium/drivers/r300/r300_screen.c
00153          */
00154         if(strstr(renderer, "R3") || strstr(renderer, "RV3") ||
00155            strstr(renderer, "R4") || strstr(renderer, "RV4") ||
00156            strstr(renderer, "RS4") || strstr(renderer, "RC4") ||
00157            strstr(renderer, "R5") || strstr(renderer, "RV5") ||
00158            strstr(renderer, "RS600") || strstr(renderer, "RS690") ||
00159            strstr(renderer, "RS740"))
00160             GG.npotdisabled = 1;
00161     }
00162     else if(strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) {
00163         GG.device = GPU_DEVICE_NVIDIA;
00164         GG.driver = GPU_DRIVER_OPENSOURCE;
00165     }
00166     else if(strstr(vendor, "Mesa")) {
00167         GG.device = GPU_DEVICE_SOFTWARE;
00168         GG.driver = GPU_DRIVER_SOFTWARE;
00169     }
00170     else if(strstr(vendor, "Microsoft")) {
00171         GG.device = GPU_DEVICE_SOFTWARE;
00172         GG.driver = GPU_DRIVER_SOFTWARE;
00173     }
00174     else if(strstr(renderer, "Apple Software Renderer")) {
00175         GG.device = GPU_DEVICE_SOFTWARE;
00176         GG.driver = GPU_DRIVER_SOFTWARE;
00177     }
00178     else {
00179         GG.device = GPU_DEVICE_ANY;
00180         GG.driver = GPU_DRIVER_ANY;
00181     }
00182 
00183     GG.os = GPU_OS_UNIX;
00184 #ifdef _WIN32
00185     GG.os = GPU_OS_WIN;
00186 #endif
00187 #ifdef __APPLE__
00188     GG.os = GPU_OS_MAC;
00189 #endif
00190 }
00191 
00192 void GPU_extensions_exit(void)
00193 {
00194     gpu_extensions_init = 0;
00195     GPU_codegen_exit();
00196 }
00197 
00198 int GPU_glsl_support(void)
00199 {
00200     return !GG.extdisabled && GG.glslsupport;
00201 }
00202 
00203 int GPU_non_power_of_two_support(void)
00204 {
00205     /* Exception for buggy ATI/Apple driver in Mac OS X 10.5/10.6,
00206      * they claim to support this but can cause system freeze */
00207     if(GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_MAC, GPU_DRIVER_OFFICIAL))
00208         return 0;
00209 
00210     if(GG.npotdisabled)
00211         return 0;
00212 
00213     return GLEW_ARB_texture_non_power_of_two;
00214 }
00215 
00216 int GPU_color_depth(void)
00217 {
00218     return GG.colordepth;
00219 }
00220 
00221 int GPU_print_error(const char *str)
00222 {
00223     GLenum errCode;
00224 
00225     if (G.f & G_DEBUG) {
00226         if ((errCode = glGetError()) != GL_NO_ERROR) {
00227             fprintf(stderr, "%s opengl error: %s\n", str, gluErrorString(errCode));
00228             return 1;
00229         }
00230     }
00231 
00232     return 0;
00233 }
00234 
00235 static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
00236 {
00237     const char *err= "unknown";
00238 
00239     switch(status) {
00240         case GL_FRAMEBUFFER_COMPLETE_EXT:
00241             break;
00242         case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
00243             err= "Incomplete attachment";
00244             break;
00245         case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
00246             err= "Unsupported framebuffer format";
00247             break;
00248         case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
00249             err= "Missing attachment";
00250             break;
00251         case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
00252             err= "Attached images must have same dimensions";
00253             break;
00254         case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
00255             err= "Attached images must have same format";
00256             break;
00257         case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
00258             err= "Missing draw buffer";
00259             break;
00260         case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
00261             err= "Missing read buffer";
00262             break;
00263     }
00264 
00265     if(err_out) {
00266         BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'",
00267             (int)status, err);
00268     }
00269     else {
00270         fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n",
00271             (int)status, err);
00272     }
00273 }
00274 
00275 /* GPUTexture */
00276 
00277 struct GPUTexture {
00278     int w, h;               /* width/height */
00279     int number;             /* number for multitexture binding */
00280     int refcount;           /* reference count */
00281     GLenum target;          /* GL_TEXTURE_* */
00282     GLuint bindcode;        /* opengl identifier for texture */
00283     int fromblender;        /* we got the texture from Blender */
00284 
00285     GPUFrameBuffer *fb;     /* GPUFramebuffer this texture is attached to */
00286     int depth;              /* is a depth texture? */
00287 };
00288 
00289 static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels)
00290 {
00291     unsigned char *pixels, *p;
00292     float *fp;
00293     int a, len;
00294 
00295     len = 4*length;
00296     fp = fpixels;
00297     p = pixels = MEM_callocN(sizeof(unsigned char)*len, "GPUTexturePixels");
00298 
00299     for (a=0; a<len; a++, p++, fp++)
00300         *p = FTOCHAR((*fp));
00301 
00302     return pixels;
00303 }
00304 
00305 static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
00306 {
00307     void *pixels = MEM_callocN(sizeof(char)*4*w*h, "GPUTextureEmptyPixels");
00308 
00309     if (target == GL_TEXTURE_1D)
00310         glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels);
00311     else
00312         glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
00313     
00314     MEM_freeN(pixels);
00315 }
00316 
00317 static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, int depth, char err_out[256])
00318 {
00319     GPUTexture *tex;
00320     GLenum type, format, internalformat;
00321     void *pixels = NULL;
00322 
00323     if(depth && !GLEW_ARB_depth_texture)
00324         return NULL;
00325 
00326     tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
00327     tex->w = w;
00328     tex->h = h;
00329     tex->number = -1;
00330     tex->refcount = 1;
00331     tex->target = (n == 1)? GL_TEXTURE_1D: GL_TEXTURE_2D;
00332     tex->depth = depth;
00333 
00334     glGenTextures(1, &tex->bindcode);
00335 
00336     if (!tex->bindcode) {
00337         if(err_out) {
00338             BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d",
00339                 (int)glGetError());
00340         }
00341         else {
00342             fprintf(stderr, "GPUTexture: texture create failed: %d\n",
00343                 (int)glGetError());
00344         }
00345         GPU_texture_free(tex);
00346         return NULL;
00347     }
00348 
00349     if (!GPU_non_power_of_two_support()) {
00350         tex->w = power_of_2_max_i(tex->w);
00351         tex->h = power_of_2_max_i(tex->h);
00352     }
00353 
00354     tex->number = 0;
00355     glBindTexture(tex->target, tex->bindcode);
00356 
00357     if(depth) {
00358         type = GL_UNSIGNED_BYTE;
00359         format = GL_DEPTH_COMPONENT;
00360         internalformat = GL_DEPTH_COMPONENT;
00361     }
00362     else {
00363         type = GL_UNSIGNED_BYTE;
00364         format = GL_RGBA;
00365         internalformat = GL_RGBA8;
00366 
00367         if (fpixels)
00368             pixels = GPU_texture_convert_pixels(w*h, fpixels);
00369     }
00370 
00371     if (tex->target == GL_TEXTURE_1D) {
00372         glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL);
00373 
00374         if (fpixels) {
00375             glTexSubImage1D(tex->target, 0, 0, w, format, type,
00376                 pixels? pixels: fpixels);
00377 
00378             if (tex->w > w)
00379                 GPU_glTexSubImageEmpty(tex->target, format, w, 0,
00380                     tex->w-w, 1);
00381         }
00382     }
00383     else {
00384         glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0,
00385             format, type, NULL);
00386 
00387         if (fpixels) {
00388             glTexSubImage2D(tex->target, 0, 0, 0, w, h,
00389                 format, type, pixels? pixels: fpixels);
00390 
00391             if (tex->w > w)
00392                 GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w-w, tex->h);
00393             if (tex->h > h)
00394                 GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h-h);
00395         }
00396     }
00397 
00398     if (pixels)
00399         MEM_freeN(pixels);
00400 
00401     if(depth) {
00402         glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00403         glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00404         glTexParameteri(tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
00405         glTexParameteri(tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
00406         glTexParameteri(tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);  
00407     }
00408     else {
00409         glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00410         glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00411     }
00412 
00413     if (tex->target != GL_TEXTURE_1D) {
00414         /* CLAMP_TO_BORDER is an OpenGL 1.3 core feature */
00415         GLenum wrapmode = (depth || tex->h == 1)? GL_CLAMP_TO_EDGE: GL_CLAMP_TO_BORDER;
00416         glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, wrapmode);
00417         glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, wrapmode);
00418 
00419 #if 0
00420         float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
00421         glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); 
00422 #endif
00423     }
00424     else
00425         glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00426 
00427     return tex;
00428 }
00429 
00430 
00431 GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels)
00432 {
00433     GPUTexture *tex;
00434     GLenum type, format, internalformat;
00435     void *pixels = NULL;
00436     float vfBorderColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
00437 
00438     if(!GLEW_VERSION_1_2)
00439         return NULL;
00440 
00441     tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
00442     tex->w = w;
00443     tex->h = h;
00444     tex->depth = depth;
00445     tex->number = -1;
00446     tex->refcount = 1;
00447     tex->target = GL_TEXTURE_3D;
00448 
00449     glGenTextures(1, &tex->bindcode);
00450 
00451     if (!tex->bindcode) {
00452         fprintf(stderr, "GPUTexture: texture create failed: %d\n",
00453             (int)glGetError());
00454         GPU_texture_free(tex);
00455         return NULL;
00456     }
00457 
00458     if (!GPU_non_power_of_two_support()) {
00459         tex->w = power_of_2_max_i(tex->w);
00460         tex->h = power_of_2_max_i(tex->h);
00461         tex->depth = power_of_2_max_i(tex->depth);
00462     }
00463 
00464     tex->number = 0;
00465     glBindTexture(tex->target, tex->bindcode);
00466 
00467     GPU_print_error("3D glBindTexture");
00468 
00469     type = GL_FLOAT; // GL_UNSIGNED_BYTE
00470     format = GL_RED;
00471     internalformat = GL_INTENSITY;
00472 
00473     //if (fpixels)
00474     //  pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
00475 
00476     glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
00477 
00478     GPU_print_error("3D glTexImage3D");
00479 
00480     if (fpixels) {
00481         if(!GPU_non_power_of_two_support() && (w != tex->w || h != tex->h || depth != tex->depth)) {
00482             /* clear first to avoid unitialized pixels */
00483             float *zero= MEM_callocN(sizeof(float)*tex->w*tex->h*tex->depth, "zero");
00484             glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->depth, format, type, zero);
00485             MEM_freeN(zero);
00486         }
00487 
00488         glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels);
00489         GPU_print_error("3D glTexSubImage3D");
00490     }
00491 
00492 
00493     glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, vfBorderColor);
00494     GPU_print_error("3D GL_TEXTURE_BORDER_COLOR");
00495     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00496     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00497     GPU_print_error("3D GL_LINEAR");
00498     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00499     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00500     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
00501     GPU_print_error("3D GL_CLAMP_TO_BORDER");
00502 
00503     if (pixels)
00504         MEM_freeN(pixels);
00505 
00506     GPU_texture_unbind(tex);
00507 
00508     return tex;
00509 }
00510 
00511 GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, double time, int mipmap)
00512 {
00513     GPUTexture *tex;
00514     GLint w, h, border, lastbindcode, bindcode;
00515 
00516     glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode);
00517 
00518     GPU_update_image_time(ima, time);
00519     bindcode = GPU_verify_image(ima, iuser, 0, 0, mipmap);
00520 
00521     if(ima->gputexture) {
00522         ima->gputexture->bindcode = bindcode;
00523         glBindTexture(GL_TEXTURE_2D, lastbindcode);
00524         return ima->gputexture;
00525     }
00526 
00527     if(!bindcode) {
00528         glBindTexture(GL_TEXTURE_2D, lastbindcode);
00529         return NULL;
00530     }
00531 
00532     tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
00533     tex->bindcode = bindcode;
00534     tex->number = -1;
00535     tex->refcount = 1;
00536     tex->target = GL_TEXTURE_2D;
00537     tex->fromblender = 1;
00538 
00539     ima->gputexture= tex;
00540 
00541     if (!glIsTexture(tex->bindcode)) {
00542         GPU_print_error("Blender Texture");
00543     }
00544     else {
00545         glBindTexture(GL_TEXTURE_2D, tex->bindcode);
00546         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
00547         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
00548         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border);
00549 
00550         tex->w = w - border;
00551         tex->h = h - border;
00552     }
00553 
00554     glBindTexture(GL_TEXTURE_2D, lastbindcode);
00555 
00556     return tex;
00557 }
00558 
00559 GPUTexture *GPU_texture_create_1D(int w, float *fpixels, char err_out[256])
00560 {
00561     GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, err_out);
00562 
00563     if (tex)
00564         GPU_texture_unbind(tex);
00565     
00566     return tex;
00567 }
00568 
00569 GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels, char err_out[256])
00570 {
00571     GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, err_out);
00572 
00573     if (tex)
00574         GPU_texture_unbind(tex);
00575     
00576     return tex;
00577 }
00578 
00579 GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
00580 {
00581     GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, err_out);
00582 
00583     if (tex)
00584         GPU_texture_unbind(tex);
00585     
00586     return tex;
00587 }
00588 
00589 void GPU_texture_bind(GPUTexture *tex, int number)
00590 {
00591     GLenum arbnumber;
00592 
00593     if (number >= GG.maxtextures) {
00594         GPU_print_error("Not enough texture slots.");
00595         return;
00596     }
00597 
00598     if(number == -1)
00599         return;
00600 
00601     GPU_print_error("Pre Texture Bind");
00602 
00603     arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + number);
00604     if (number != 0) glActiveTextureARB(arbnumber);
00605     glBindTexture(tex->target, tex->bindcode);
00606     glEnable(tex->target);
00607     if (number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
00608 
00609     tex->number = number;
00610 
00611     GPU_print_error("Post Texture Bind");
00612 }
00613 
00614 void GPU_texture_unbind(GPUTexture *tex)
00615 {
00616     GLenum arbnumber;
00617 
00618     if (tex->number >= GG.maxtextures) {
00619         GPU_print_error("Not enough texture slots.");
00620         return;
00621     }
00622 
00623     if(tex->number == -1)
00624         return;
00625     
00626     GPU_print_error("Pre Texture Unbind");
00627 
00628     arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
00629     if (tex->number != 0) glActiveTextureARB(arbnumber);
00630     glBindTexture(tex->target, 0);
00631     glDisable(tex->target);
00632     if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
00633 
00634     tex->number = -1;
00635 
00636     GPU_print_error("Post Texture Unbind");
00637 }
00638 
00639 void GPU_texture_free(GPUTexture *tex)
00640 {
00641     tex->refcount--;
00642 
00643     if (tex->refcount < 0)
00644         fprintf(stderr, "GPUTexture: negative refcount\n");
00645     
00646     if (tex->refcount == 0) {
00647         if (tex->fb)
00648             GPU_framebuffer_texture_detach(tex->fb, tex);
00649         if (tex->bindcode && !tex->fromblender)
00650             glDeleteTextures(1, &tex->bindcode);
00651 
00652         MEM_freeN(tex);
00653     }
00654 }
00655 
00656 void GPU_texture_ref(GPUTexture *tex)
00657 {
00658     tex->refcount++;
00659 }
00660 
00661 int GPU_texture_target(GPUTexture *tex)
00662 {
00663     return tex->target;
00664 }
00665 
00666 int GPU_texture_opengl_width(GPUTexture *tex)
00667 {
00668     return tex->w;
00669 }
00670 
00671 int GPU_texture_opengl_height(GPUTexture *tex)
00672 {
00673     return tex->h;
00674 }
00675 
00676 int GPU_texture_opengl_bindcode(GPUTexture *tex)
00677 {
00678     return tex->bindcode;
00679 }
00680 
00681 GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex)
00682 {
00683     return tex->fb;
00684 }
00685 
00686 /* GPUFrameBuffer */
00687 
00688 struct GPUFrameBuffer {
00689     GLuint object;
00690     GPUTexture *colortex;
00691     GPUTexture *depthtex;
00692 };
00693 
00694 GPUFrameBuffer *GPU_framebuffer_create(void)
00695 {
00696     GPUFrameBuffer *fb;
00697 
00698     if (!GLEW_EXT_framebuffer_object)
00699         return NULL;
00700     
00701     fb= MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
00702     glGenFramebuffersEXT(1, &fb->object);
00703 
00704     if (!fb->object) {
00705         fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
00706             (int)glGetError());
00707         GPU_framebuffer_free(fb);
00708         return NULL;
00709     }
00710 
00711     return fb;
00712 }
00713 
00714 int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, char err_out[256])
00715 {
00716     GLenum status;
00717     GLenum attachment;
00718 
00719     if(tex->depth)
00720         attachment = GL_DEPTH_ATTACHMENT_EXT;
00721     else
00722         attachment = GL_COLOR_ATTACHMENT0_EXT;
00723 
00724     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
00725     GG.currentfb = fb->object;
00726 
00727     glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, 
00728         tex->target, tex->bindcode, 0);
00729 
00730     if(tex->depth) {
00731         glDrawBuffer(GL_NONE);
00732         glReadBuffer(GL_NONE);
00733     }
00734     else {
00735         glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
00736         glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
00737     }
00738 
00739     status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
00740 
00741     if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
00742         GPU_framebuffer_restore();
00743         GPU_print_framebuffer_error(status, err_out);
00744         return 0;
00745     }
00746 
00747     if(tex->depth)
00748         fb->depthtex = tex;
00749     else
00750         fb->colortex = tex;
00751 
00752     tex->fb= fb;
00753 
00754     return 1;
00755 }
00756 
00757 void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
00758 {
00759     GLenum attachment;
00760 
00761     if(!tex->fb)
00762         return;
00763 
00764     if(GG.currentfb != tex->fb->object) {
00765         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
00766         GG.currentfb = tex->fb->object;
00767     }
00768 
00769     if(tex->depth) {
00770         fb->depthtex = NULL;
00771         attachment = GL_DEPTH_ATTACHMENT_EXT;
00772     }
00773     else {
00774         fb->colortex = NULL;
00775         attachment = GL_COLOR_ATTACHMENT0_EXT;
00776     }
00777 
00778     glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
00779         tex->target, 0, 0);
00780 
00781     tex->fb = NULL;
00782 }
00783 
00784 void GPU_framebuffer_texture_bind(GPUFrameBuffer *UNUSED(fb), GPUTexture *tex, int w, int h)
00785 {
00786     /* push attributes */
00787     glPushAttrib(GL_ENABLE_BIT);
00788     glPushAttrib(GL_VIEWPORT_BIT);
00789     glDisable(GL_SCISSOR_TEST);
00790 
00791     /* bind framebuffer */
00792     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
00793 
00794     /* push matrices and set default viewport and matrix */
00795     glViewport(0, 0, w, h);
00796     GG.currentfb = tex->fb->object;
00797 
00798     glMatrixMode(GL_PROJECTION);
00799     glPushMatrix();
00800     glLoadIdentity();
00801     glMatrixMode(GL_MODELVIEW);
00802     glPushMatrix();
00803     glLoadIdentity();
00804 }
00805 
00806 void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
00807 {
00808     /* restore matrix */
00809     glMatrixMode(GL_PROJECTION);
00810     glPopMatrix();
00811     glMatrixMode(GL_MODELVIEW);
00812     glPopMatrix();
00813 
00814     /* restore attributes */
00815     glPopAttrib();
00816     glPopAttrib();
00817     glEnable(GL_SCISSOR_TEST);
00818 }
00819 
00820 void GPU_framebuffer_free(GPUFrameBuffer *fb)
00821 {
00822     if(fb->depthtex)
00823         GPU_framebuffer_texture_detach(fb, fb->depthtex);
00824     if(fb->colortex)
00825         GPU_framebuffer_texture_detach(fb, fb->colortex);
00826 
00827     if(fb->object) {
00828         glDeleteFramebuffersEXT(1, &fb->object);
00829 
00830         if (GG.currentfb == fb->object) {
00831             glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
00832             GG.currentfb = 0;
00833         }
00834     }
00835 
00836     MEM_freeN(fb);
00837 }
00838 
00839 void GPU_framebuffer_restore(void)
00840 {
00841     if (GG.currentfb != 0) {
00842         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
00843         GG.currentfb = 0;
00844     }
00845 }
00846 
00847 /* GPUOffScreen */
00848 
00849 struct GPUOffScreen {
00850     GPUFrameBuffer *fb;
00851     GPUTexture *color;
00852     GPUTexture *depth;
00853 
00854     /* requested width/height, may be smaller than actual texture size due
00855        to missing non-power of two support, so we compensate for that */
00856     int w, h;
00857 };
00858 
00859 GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256])
00860 {
00861     GPUOffScreen *ofs;
00862 
00863     ofs= MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
00864     ofs->w= width;
00865     ofs->h= height;
00866 
00867     ofs->fb = GPU_framebuffer_create();
00868     if(!ofs->fb) {
00869         GPU_offscreen_free(ofs);
00870         return NULL;
00871     }
00872 
00873     ofs->depth = GPU_texture_create_depth(width, height, err_out);
00874     if(!ofs->depth) {
00875         GPU_offscreen_free(ofs);
00876         return NULL;
00877     }
00878 
00879     if(!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, err_out)) {
00880         GPU_offscreen_free(ofs);
00881         return NULL;
00882     }
00883 
00884     ofs->color = GPU_texture_create_2D(width, height, NULL, err_out);
00885     if(!ofs->color) {
00886         GPU_offscreen_free(ofs);
00887         return NULL;
00888     }
00889 
00890     if(!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, err_out)) {
00891         GPU_offscreen_free(ofs);
00892         return NULL;
00893     }
00894 
00895     GPU_framebuffer_restore();
00896 
00897     return ofs;
00898 }
00899 
00900 void GPU_offscreen_free(GPUOffScreen *ofs)
00901 {
00902     if(ofs->fb)
00903         GPU_framebuffer_free(ofs->fb);
00904     if(ofs->color)
00905         GPU_texture_free(ofs->color);
00906     if(ofs->depth)
00907         GPU_texture_free(ofs->depth);
00908     
00909     MEM_freeN(ofs);
00910 }
00911 
00912 void GPU_offscreen_bind(GPUOffScreen *ofs)
00913 {
00914     glDisable(GL_SCISSOR_TEST);
00915     GPU_framebuffer_texture_bind(ofs->fb, ofs->color, ofs->w, ofs->h);
00916 }
00917 
00918 void GPU_offscreen_unbind(GPUOffScreen *ofs)
00919 {
00920     GPU_framebuffer_texture_unbind(ofs->fb, ofs->color);
00921     GPU_framebuffer_restore();
00922     glEnable(GL_SCISSOR_TEST);
00923 }
00924 
00925 void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
00926 {
00927     glReadPixels(0, 0, ofs->w, ofs->h, GL_RGBA, type, pixels);
00928 }
00929 
00930 /* GPUShader */
00931 
00932 struct GPUShader {
00933     GLhandleARB object;     /* handle for full shader */
00934     GLhandleARB vertex;     /* handle for vertex shader */
00935     GLhandleARB fragment;   /* handle for fragment shader */
00936     GLhandleARB lib;        /* handle for libment shader */
00937     int totattrib;          /* total number of attributes */
00938 };
00939 
00940 static void shader_print_errors(const char *task, char *log, const char *code)
00941 {
00942     const char *c, *pos, *end = code + strlen(code);
00943     int line = 1;
00944 
00945     fprintf(stderr, "GPUShader: %s error:\n", task);
00946 
00947     if(G.f & G_DEBUG) {
00948         c = code;
00949         while ((c < end) && (pos = strchr(c, '\n'))) {
00950             fprintf(stderr, "%2d  ", line);
00951             fwrite(c, (pos+1)-c, 1, stderr);
00952             c = pos+1;
00953             line++;
00954         }
00955 
00956         fprintf(stderr, "%s", c);
00957     }
00958 
00959     fprintf(stderr, "%s\n", log);
00960 }
00961 
00962 GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPUShader *lib,*/ const char *libcode)
00963 {
00964     GLint status;
00965     GLcharARB log[5000];
00966     const char *fragsource[2];
00967     GLsizei length = 0;
00968     GLint count;
00969     GPUShader *shader;
00970 
00971     if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
00972         return NULL;
00973 
00974     shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
00975 
00976     if(vertexcode)
00977         shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
00978     if(fragcode)
00979         shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
00980     shader->object = glCreateProgramObjectARB();
00981 
00982     if (!shader->object ||
00983         (vertexcode && !shader->vertex) ||
00984         (fragcode && !shader->fragment)) {
00985         fprintf(stderr, "GPUShader, object creation failed.\n");
00986         GPU_shader_free(shader);
00987         return NULL;
00988     }
00989 
00990     if(vertexcode) {
00991         glAttachObjectARB(shader->object, shader->vertex);
00992         glShaderSourceARB(shader->vertex, 1, (const char**)&vertexcode, NULL);
00993 
00994         glCompileShaderARB(shader->vertex);
00995         glGetObjectParameterivARB(shader->vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status);
00996 
00997         if (!status) {
00998             glGetInfoLogARB(shader->vertex, sizeof(log), &length, log);
00999             shader_print_errors("compile", log, vertexcode);
01000 
01001             GPU_shader_free(shader);
01002             return NULL;
01003         }
01004     }
01005 
01006     if(fragcode) {
01007         count = 0;
01008         if(libcode) fragsource[count++] = libcode;
01009         if(fragcode) fragsource[count++] = fragcode;
01010 
01011         glAttachObjectARB(shader->object, shader->fragment);
01012         glShaderSourceARB(shader->fragment, count, fragsource, NULL);
01013 
01014         glCompileShaderARB(shader->fragment);
01015         glGetObjectParameterivARB(shader->fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status);
01016 
01017         if (!status) {
01018             glGetInfoLogARB(shader->fragment, sizeof(log), &length, log);
01019             shader_print_errors("compile", log, fragcode);
01020 
01021             GPU_shader_free(shader);
01022             return NULL;
01023         }
01024     }
01025 
01026     /*if(lib && lib->lib)
01027         glAttachObjectARB(shader->object, lib->lib);*/
01028 
01029     glLinkProgramARB(shader->object);
01030     glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status);
01031     if (!status) {
01032         glGetInfoLogARB(shader->object, sizeof(log), &length, log);
01033         if (fragcode) shader_print_errors("linking", log, fragcode);
01034         else if (vertexcode) shader_print_errors("linking", log, vertexcode);
01035         else if (libcode) shader_print_errors("linking", log, libcode);
01036 
01037         GPU_shader_free(shader);
01038         return NULL;
01039     }
01040 
01041     return shader;
01042 }
01043 
01044 #if 0
01045 GPUShader *GPU_shader_create_lib(const char *code)
01046 {
01047     GLint status;
01048     GLcharARB log[5000];
01049     GLsizei length = 0;
01050     GPUShader *shader;
01051 
01052     if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
01053         return NULL;
01054 
01055     shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
01056 
01057     shader->lib = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
01058 
01059     if (!shader->lib) {
01060         fprintf(stderr, "GPUShader, object creation failed.\n");
01061         GPU_shader_free(shader);
01062         return NULL;
01063     }
01064 
01065     glShaderSourceARB(shader->lib, 1, (const char**)&code, NULL);
01066 
01067     glCompileShaderARB(shader->lib);
01068     glGetObjectParameterivARB(shader->lib, GL_OBJECT_COMPILE_STATUS_ARB, &status);
01069 
01070     if (!status) {
01071         glGetInfoLogARB(shader->lib, sizeof(log), &length, log);
01072         shader_print_errors("compile", log, code);
01073 
01074         GPU_shader_free(shader);
01075         return NULL;
01076     }
01077 
01078     return shader;
01079 }
01080 #endif
01081 
01082 void GPU_shader_bind(GPUShader *shader)
01083 {
01084     GPU_print_error("Pre Shader Bind");
01085     glUseProgramObjectARB(shader->object);
01086     GPU_print_error("Post Shader Bind");
01087 }
01088 
01089 void GPU_shader_unbind(GPUShader *UNUSED(shader))
01090 {
01091     GPU_print_error("Pre Shader Unbind");
01092     glUseProgramObjectARB(0);
01093     GPU_print_error("Post Shader Unbind");
01094 }
01095 
01096 void GPU_shader_free(GPUShader *shader)
01097 {
01098     if (shader->lib)
01099         glDeleteObjectARB(shader->lib);
01100     if (shader->vertex)
01101         glDeleteObjectARB(shader->vertex);
01102     if (shader->fragment)
01103         glDeleteObjectARB(shader->fragment);
01104     if (shader->object)
01105         glDeleteObjectARB(shader->object);
01106     MEM_freeN(shader);
01107 }
01108 
01109 int GPU_shader_get_uniform(GPUShader *shader, const char *name)
01110 {
01111     return glGetUniformLocationARB(shader->object, name);
01112 }
01113 
01114 void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, float *value)
01115 {
01116     if(location == -1)
01117         return;
01118 
01119     GPU_print_error("Pre Uniform Vector");
01120 
01121     if (length == 1) glUniform1fvARB(location, arraysize, value);
01122     else if (length == 2) glUniform2fvARB(location, arraysize, value);
01123     else if (length == 3) glUniform3fvARB(location, arraysize, value);
01124     else if (length == 4) glUniform4fvARB(location, arraysize, value);
01125     else if (length == 9) glUniformMatrix3fvARB(location, arraysize, 0, value);
01126     else if (length == 16) glUniformMatrix4fvARB(location, arraysize, 0, value);
01127 
01128     GPU_print_error("Post Uniform Vector");
01129 }
01130 
01131 void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
01132 {
01133     GLenum arbnumber;
01134 
01135     if (tex->number >= GG.maxtextures) {
01136         GPU_print_error("Not enough texture slots.");
01137         return;
01138     }
01139         
01140     if(tex->number == -1)
01141         return;
01142 
01143     if(location == -1)
01144         return;
01145 
01146     GPU_print_error("Pre Uniform Texture");
01147 
01148     arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
01149 
01150     if (tex->number != 0) glActiveTextureARB(arbnumber);
01151     glBindTexture(tex->target, tex->bindcode);
01152     glUniform1iARB(location, tex->number);
01153     glEnable(tex->target);
01154     if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
01155 
01156     GPU_print_error("Post Uniform Texture");
01157 }
01158 
01159 int GPU_shader_get_attribute(GPUShader *shader, const char *name)
01160 {
01161     int index;
01162     
01163     GPU_print_error("Pre Get Attribute");
01164 
01165     index = glGetAttribLocationARB(shader->object, name);
01166 
01167     GPU_print_error("Post Get Attribute");
01168 
01169     return index;
01170 }
01171 
01172 #if 0
01173 /* GPUPixelBuffer */
01174 
01175 typedef struct GPUPixelBuffer {
01176     GLuint bindcode[2];
01177     GLuint current;
01178     int datasize;
01179     int numbuffers;
01180     int halffloat;
01181 } GPUPixelBuffer;
01182 
01183 void GPU_pixelbuffer_free(GPUPixelBuffer *pb)
01184 {
01185     if (pb->bindcode[0])
01186         glDeleteBuffersARB(pb->numbuffers, pb->bindcode);
01187     MEM_freeN(pb);
01188 }
01189 
01190 GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffers)
01191 {
01192     GPUPixelBuffer *pb;
01193 
01194     if (!GLEW_ARB_multitexture || !GLEW_EXT_pixel_buffer_object)
01195         return NULL;
01196     
01197     pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO");
01198     pb->datasize = x*y*4*((halffloat)? 16: 8);
01199     pb->numbuffers = numbuffers;
01200     pb->halffloat = halffloat;
01201 
01202     glGenBuffersARB(pb->numbuffers, pb->bindcode);
01203 
01204     if (!pb->bindcode[0]) {
01205         fprintf(stderr, "GPUPixelBuffer allocation failed\n");
01206         GPU_pixelbuffer_free(pb);
01207         return NULL;
01208     }
01209 
01210     return pb;
01211 }
01212 
01213 void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb)
01214 {
01215     void *pixels;
01216     int i;
01217 
01218     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
01219 
01220     for (i = 0; i < pb->numbuffers; i++) {
01221         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->bindcode[pb->current]);
01222         glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->datasize, NULL,
01223         GL_STREAM_DRAW_ARB);
01224 
01225         pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
01226         /*memcpy(pixels, _oImage.data(), pb->datasize);*/
01227 
01228         if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
01229             fprintf(stderr, "Could not unmap opengl PBO\n");
01230             break;
01231         }
01232     }
01233 
01234     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
01235 }
01236 
01237 static int pixelbuffer_map_into_gpu(GLuint bindcode)
01238 {
01239     void *pixels;
01240 
01241     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
01242     pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
01243 
01244     /* do stuff in pixels */
01245 
01246     if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
01247         fprintf(stderr, "Could not unmap opengl PBO\n");
01248         return 0;
01249     }
01250     
01251     return 1;
01252 }
01253 
01254 static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLuint bindcode)
01255 {
01256     GLenum type = (pb->halffloat)? GL_HALF_FLOAT_NV: GL_UNSIGNED_BYTE;
01257     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
01258     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
01259 
01260     glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h,
01261                     GL_RGBA, type, NULL);
01262 
01263     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
01264     glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
01265 }
01266 
01267 void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb)
01268 {
01269     int newbuffer;
01270 
01271     if (pb->numbuffers == 1) {
01272         pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[0]);
01273         pixelbuffer_map_into_gpu(pb->bindcode[0]);
01274     }
01275     else {
01276         pb->current = (pb->current+1)%pb->numbuffers;
01277         newbuffer = (pb->current+1)%pb->numbuffers;
01278 
01279         pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]);
01280         pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]);
01281     }
01282 }
01283 #endif
01284