c15366c4976ca346ce3acc1cd3bd0b5e1d46a831
[blender.git] / source / blender / gpu / intern / gpu_extensions.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Brecht Van Lommel.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/gpu/intern/gpu_extensions.c
29  *  \ingroup gpu
30  */
31
32
33 #include "GL/glew.h"
34
35 #include "DNA_image_types.h"
36
37 #include "MEM_guardedalloc.h"
38
39 #include "BKE_global.h"
40
41
42 #include "BLI_blenlib.h"
43 #include "BLI_utildefines.h"
44 #include "BLI_math_base.h"
45
46 #include "GPU_draw.h"
47 #include "GPU_extensions.h"
48 #include "gpu_codegen.h"
49
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <string.h>
53
54 #ifdef WIN32
55 #  include "BLI_winstuff.h"
56 #endif
57
58 /* Extensions support */
59
60 /* extensions used:
61  * - texture border clamp: 1.3 core
62  * - fragment shader: 2.0 core
63  * - framebuffer object: ext specification
64  * - multitexture 1.3 core
65  * - arb non power of two: 2.0 core
66  * - pixel buffer objects? 2.1 core
67  * - arb draw buffers? 2.0 core
68  */
69
70 /* Non-generated shaders */
71 extern char datatoc_gpu_shader_vsm_store_vert_glsl[];
72 extern char datatoc_gpu_shader_vsm_store_frag_glsl[];
73 extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[];
74 extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[];
75
76 typedef struct GPUShaders {
77         GPUShader *vsm_store;
78         GPUShader *sep_gaussian_blur;
79 } GPUShaders;
80
81 static struct GPUGlobal {
82         GLint maxtextures;
83         GLuint currentfb;
84         int glslsupport;
85         int extdisabled;
86         int colordepth;
87         int npotdisabled; /* ATI 3xx-5xx (and more) chipsets support NPoT partially (== not enough) */
88         GPUDeviceType device;
89         GPUOSType os;
90         GPUDriverType driver;
91         GPUShaders shaders;
92 } GG = {1, 0};
93
94 /* GPU Types */
95
96 int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
97 {
98         return (GG.device & device) && (GG.os & os) && (GG.driver & driver);
99 }
100
101 /* GPU Extensions */
102
103 static int gpu_extensions_init = 0;
104
105 void GPU_extensions_disable(void)
106 {
107         GG.extdisabled = 1;
108 }
109
110 void GPU_extensions_init(void)
111 {
112         GLint r, g, b;
113         const char *vendor, *renderer;
114
115         /* can't avoid calling this multiple times, see wm_window_add_ghostwindow */
116         if (gpu_extensions_init) return;
117         gpu_extensions_init= 1;
118
119         glewInit();
120         GPU_codegen_init();
121
122         /* glewIsSupported("GL_VERSION_2_0") */
123
124         if (GLEW_ARB_multitexture)
125                 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &GG.maxtextures);
126
127         GG.glslsupport = 1;
128         if (!GLEW_ARB_multitexture) GG.glslsupport = 0;
129         if (!GLEW_ARB_vertex_shader) GG.glslsupport = 0;
130         if (!GLEW_ARB_fragment_shader) GG.glslsupport = 0;
131
132         glGetIntegerv(GL_RED_BITS, &r);
133         glGetIntegerv(GL_GREEN_BITS, &g);
134         glGetIntegerv(GL_BLUE_BITS, &b);
135         GG.colordepth = r+g+b; /* assumes same depth for RGB */
136
137         vendor = (const char*)glGetString(GL_VENDOR);
138         renderer = (const char*)glGetString(GL_RENDERER);
139
140         if (strstr(vendor, "ATI")) {
141                 GG.device = GPU_DEVICE_ATI;
142                 GG.driver = GPU_DRIVER_OFFICIAL;
143         }
144         else if (strstr(vendor, "NVIDIA")) {
145                 GG.device = GPU_DEVICE_NVIDIA;
146                 GG.driver = GPU_DRIVER_OFFICIAL;
147         }
148         else if (strstr(vendor, "Intel") ||
149                 /* src/mesa/drivers/dri/intel/intel_context.c */
150                 strstr(renderer, "Mesa DRI Intel") ||
151                 strstr(renderer, "Mesa DRI Mobile Intel")) {
152                 GG.device = GPU_DEVICE_INTEL;
153                 GG.driver = GPU_DRIVER_OFFICIAL;
154         }
155         else if (strstr(renderer, "Mesa DRI R") || (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI "))) {
156                 GG.device = GPU_DEVICE_ATI;
157                 GG.driver = GPU_DRIVER_OPENSOURCE;
158         }
159         else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) {
160                 GG.device = GPU_DEVICE_NVIDIA;
161                 GG.driver = GPU_DRIVER_OPENSOURCE;
162         }
163         else if (strstr(vendor, "Mesa")) {
164                 GG.device = GPU_DEVICE_SOFTWARE;
165                 GG.driver = GPU_DRIVER_SOFTWARE;
166         }
167         else if (strstr(vendor, "Microsoft")) {
168                 GG.device = GPU_DEVICE_SOFTWARE;
169                 GG.driver = GPU_DRIVER_SOFTWARE;
170         }
171         else if (strstr(renderer, "Apple Software Renderer")) {
172                 GG.device = GPU_DEVICE_SOFTWARE;
173                 GG.driver = GPU_DRIVER_SOFTWARE;
174         }
175         else {
176                 GG.device = GPU_DEVICE_ANY;
177                 GG.driver = GPU_DRIVER_ANY;
178         }
179
180         if (GG.device == GPU_DEVICE_ATI) {
181                 /* ATI 9500 to X2300 cards support NPoT textures poorly
182                  * Incomplete list http://dri.freedesktop.org/wiki/ATIRadeon
183                  * New IDs from MESA's src/gallium/drivers/r300/r300_screen.c
184                  */
185                 if (strstr(renderer, "R3") || strstr(renderer, "RV3") ||
186                     strstr(renderer, "R4") || strstr(renderer, "RV4") ||
187                     strstr(renderer, "RS4") || strstr(renderer, "RC4") ||
188                     strstr(renderer, "R5") || strstr(renderer, "RV5") ||
189                     strstr(renderer, "RS600") || strstr(renderer, "RS690") ||
190                     strstr(renderer, "RS740") || strstr(renderer, "X1") ||
191                     strstr(renderer, "X2") || strstr(renderer, "Radeon 9") ||
192                     strstr(renderer, "RADEON 9"))
193                 {
194                         GG.npotdisabled = 1;
195                 }
196         }
197
198         /* make sure double side isn't used by default and only getting enabled in places where it's
199          * really needed to prevent different unexpected behaviors like with intel gme965 card (sergey) */
200         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
201
202 #ifdef _WIN32
203         GG.os = GPU_OS_WIN;
204 #elif defined(__APPLE__)
205         GG.os = GPU_OS_MAC;
206 #else
207         GG.os = GPU_OS_UNIX;
208 #endif
209 }
210
211 void GPU_extensions_exit(void)
212 {
213         gpu_extensions_init = 0;
214         GPU_codegen_exit();
215 }
216
217 int GPU_glsl_support(void)
218 {
219         return !GG.extdisabled && GG.glslsupport;
220 }
221
222 int GPU_non_power_of_two_support(void)
223 {
224         if (GG.npotdisabled)
225                 return 0;
226
227         return GLEW_ARB_texture_non_power_of_two;
228 }
229
230 int GPU_color_depth(void)
231 {
232         return GG.colordepth;
233 }
234
235 int GPU_print_error(const char *str)
236 {
237         GLenum errCode;
238
239         if (G.debug & G_DEBUG) {
240                 if ((errCode = glGetError()) != GL_NO_ERROR) {
241                         fprintf(stderr, "%s opengl error: %s\n", str, gluErrorString(errCode));
242                         return 1;
243                 }
244         }
245
246         return 0;
247 }
248
249 static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
250 {
251         const char *err= "unknown";
252
253         switch (status) {
254                 case GL_FRAMEBUFFER_COMPLETE_EXT:
255                         break;
256                 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
257                         err= "Incomplete attachment";
258                         break;
259                 case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
260                         err= "Unsupported framebuffer format";
261                         break;
262                 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
263                         err= "Missing attachment";
264                         break;
265                 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
266                         err= "Attached images must have same dimensions";
267                         break;
268                 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
269                         err= "Attached images must have same format";
270                         break;
271                 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
272                         err= "Missing draw buffer";
273                         break;
274                 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
275                         err= "Missing read buffer";
276                         break;
277         }
278
279         if (err_out) {
280                 BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'",
281                         (int)status, err);
282         }
283         else {
284                 fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n",
285                         (int)status, err);
286         }
287 }
288
289 /* GPUTexture */
290
291 struct GPUTexture {
292         int w, h;                               /* width/height */
293         int number;                             /* number for multitexture binding */
294         int refcount;                   /* reference count */
295         GLenum target;                  /* GL_TEXTURE_* */
296         GLuint bindcode;                /* opengl identifier for texture */
297         int fromblender;                /* we got the texture from Blender */
298
299         GPUFrameBuffer *fb;             /* GPUFramebuffer this texture is attached to */
300         int depth;                              /* is a depth texture? */
301 };
302
303 static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels)
304 {
305         unsigned char *pixels, *p;
306         float *fp;
307         int a, len;
308
309         len = 4*length;
310         fp = fpixels;
311         p = pixels = MEM_callocN(sizeof(unsigned char)*len, "GPUTexturePixels");
312
313         for (a=0; a<len; a++, p++, fp++)
314                 *p = FTOCHAR((*fp));
315
316         return pixels;
317 }
318
319 static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
320 {
321         void *pixels = MEM_callocN(sizeof(char)*4*w*h, "GPUTextureEmptyPixels");
322
323         if (target == GL_TEXTURE_1D)
324                 glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels);
325         else
326                 glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
327         
328         MEM_freeN(pixels);
329 }
330
331 static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, int depth, char err_out[256])
332 {
333         GPUTexture *tex;
334         GLenum type, format, internalformat;
335         void *pixels = NULL;
336
337         if (depth && !GLEW_ARB_depth_texture)
338                 return NULL;
339
340         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
341         tex->w = w;
342         tex->h = h;
343         tex->number = -1;
344         tex->refcount = 1;
345         tex->target = (n == 1)? GL_TEXTURE_1D: GL_TEXTURE_2D;
346         tex->depth = depth;
347
348         glGenTextures(1, &tex->bindcode);
349
350         if (!tex->bindcode) {
351                 if (err_out) {
352                         BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d",
353                                 (int)glGetError());
354                 }
355                 else {
356                         fprintf(stderr, "GPUTexture: texture create failed: %d\n",
357                                 (int)glGetError());
358                 }
359                 GPU_texture_free(tex);
360                 return NULL;
361         }
362
363         if (!GPU_non_power_of_two_support()) {
364                 tex->w = power_of_2_max_i(tex->w);
365                 tex->h = power_of_2_max_i(tex->h);
366         }
367
368         tex->number = 0;
369         glBindTexture(tex->target, tex->bindcode);
370
371         if (depth) {
372                 type = GL_UNSIGNED_BYTE;
373                 format = GL_DEPTH_COMPONENT;
374                 internalformat = GL_DEPTH_COMPONENT;
375         }
376         else {
377                 type = GL_UNSIGNED_BYTE;
378                 format = GL_RGBA;
379                 internalformat = GL_RGBA8;
380
381                 if (fpixels)
382                         pixels = GPU_texture_convert_pixels(w*h, fpixels);
383         }
384
385         if (tex->target == GL_TEXTURE_1D) {
386                 glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL);
387
388                 if (fpixels) {
389                         glTexSubImage1D(tex->target, 0, 0, w, format, type,
390                                 pixels? pixels: fpixels);
391
392                         if (tex->w > w)
393                                 GPU_glTexSubImageEmpty(tex->target, format, w, 0,
394                                         tex->w-w, 1);
395                 }
396         }
397         else {
398                 glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0,
399                         format, type, NULL);
400
401                 if (fpixels) {
402                         glTexSubImage2D(tex->target, 0, 0, 0, w, h,
403                                 format, type, pixels? pixels: fpixels);
404
405                         if (tex->w > w)
406                                 GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w-w, tex->h);
407                         if (tex->h > h)
408                                 GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h-h);
409                 }
410         }
411
412         if (pixels)
413                 MEM_freeN(pixels);
414
415         if (depth) {
416                 glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
417                 glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
418                 glTexParameteri(tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
419                 glTexParameteri(tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
420                 glTexParameteri(tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);  
421         }
422         else {
423                 glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
424                 glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
425         }
426
427         if (tex->target != GL_TEXTURE_1D) {
428                 /* CLAMP_TO_BORDER is an OpenGL 1.3 core feature */
429                 GLenum wrapmode = (depth || tex->h == 1)? GL_CLAMP_TO_EDGE: GL_CLAMP_TO_BORDER;
430                 glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, wrapmode);
431                 glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, wrapmode);
432
433 #if 0
434                 float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
435                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); 
436 #endif
437         }
438         else
439                 glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
440
441         return tex;
442 }
443
444
445 GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels)
446 {
447         GPUTexture *tex;
448         GLenum type, format, internalformat;
449         void *pixels = NULL;
450         float vfBorderColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
451
452         if (!GLEW_VERSION_1_2)
453                 return NULL;
454
455         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
456         tex->w = w;
457         tex->h = h;
458         tex->depth = depth;
459         tex->number = -1;
460         tex->refcount = 1;
461         tex->target = GL_TEXTURE_3D;
462
463         glGenTextures(1, &tex->bindcode);
464
465         if (!tex->bindcode) {
466                 fprintf(stderr, "GPUTexture: texture create failed: %d\n",
467                         (int)glGetError());
468                 GPU_texture_free(tex);
469                 return NULL;
470         }
471
472         if (!GPU_non_power_of_two_support()) {
473                 tex->w = power_of_2_max_i(tex->w);
474                 tex->h = power_of_2_max_i(tex->h);
475                 tex->depth = power_of_2_max_i(tex->depth);
476         }
477
478         tex->number = 0;
479         glBindTexture(tex->target, tex->bindcode);
480
481         GPU_print_error("3D glBindTexture");
482
483         type = GL_FLOAT; // GL_UNSIGNED_BYTE
484         format = GL_RED;
485         internalformat = GL_INTENSITY;
486
487         //if (fpixels)
488         //      pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
489
490         glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
491
492         GPU_print_error("3D glTexImage3D");
493
494         if (fpixels) {
495                 if (!GPU_non_power_of_two_support() && (w != tex->w || h != tex->h || depth != tex->depth)) {
496                         /* clear first to avoid unitialized pixels */
497                         float *zero= MEM_callocN(sizeof(float)*tex->w*tex->h*tex->depth, "zero");
498                         glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->depth, format, type, zero);
499                         MEM_freeN(zero);
500                 }
501
502                 glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels);
503                 GPU_print_error("3D glTexSubImage3D");
504         }
505
506
507         glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, vfBorderColor);
508         GPU_print_error("3D GL_TEXTURE_BORDER_COLOR");
509         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
510         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
511         GPU_print_error("3D GL_LINEAR");
512         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
513         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
514         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
515         GPU_print_error("3D GL_CLAMP_TO_BORDER");
516
517         if (pixels)
518                 MEM_freeN(pixels);
519
520         GPU_texture_unbind(tex);
521
522         return tex;
523 }
524
525 GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, double time, int mipmap)
526 {
527         GPUTexture *tex;
528         GLint w, h, border, lastbindcode, bindcode;
529
530         glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode);
531
532         GPU_update_image_time(ima, time);
533         bindcode = GPU_verify_image(ima, iuser, 0, 0, mipmap);
534
535         if (ima->gputexture) {
536                 ima->gputexture->bindcode = bindcode;
537                 glBindTexture(GL_TEXTURE_2D, lastbindcode);
538                 return ima->gputexture;
539         }
540
541         if (!bindcode) {
542                 glBindTexture(GL_TEXTURE_2D, lastbindcode);
543                 return NULL;
544         }
545
546         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
547         tex->bindcode = bindcode;
548         tex->number = -1;
549         tex->refcount = 1;
550         tex->target = GL_TEXTURE_2D;
551         tex->fromblender = 1;
552
553         ima->gputexture= tex;
554
555         if (!glIsTexture(tex->bindcode)) {
556                 GPU_print_error("Blender Texture");
557         }
558         else {
559                 glBindTexture(GL_TEXTURE_2D, tex->bindcode);
560                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
561                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
562                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border);
563
564                 tex->w = w - border;
565                 tex->h = h - border;
566         }
567
568         glBindTexture(GL_TEXTURE_2D, lastbindcode);
569
570         return tex;
571 }
572
573 GPUTexture *GPU_texture_create_1D(int w, float *fpixels, char err_out[256])
574 {
575         GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, err_out);
576
577         if (tex)
578                 GPU_texture_unbind(tex);
579         
580         return tex;
581 }
582
583 GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels, char err_out[256])
584 {
585         GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, err_out);
586
587         if (tex)
588                 GPU_texture_unbind(tex);
589         
590         return tex;
591 }
592
593 GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
594 {
595         GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, err_out);
596
597         if (tex)
598                 GPU_texture_unbind(tex);
599         
600         return tex;
601 }
602
603 /**
604  * A shadow map for VSM needs two components (depth and depth^2)
605  */
606 GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256])
607 {
608         GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, err_out);
609
610         if (tex) {
611                 /* Now we tweak some of the settings */
612                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
613                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
614                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, size, size, 0, GL_RG, GL_FLOAT, 0);
615
616                 GPU_texture_unbind(tex);
617         }
618
619         return tex;
620 }
621
622 void GPU_texture_bind(GPUTexture *tex, int number)
623 {
624         GLenum arbnumber;
625
626         if (number >= GG.maxtextures) {
627                 GPU_print_error("Not enough texture slots.");
628                 return;
629         }
630
631         if (number == -1)
632                 return;
633
634         GPU_print_error("Pre Texture Bind");
635
636         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + number);
637         if (number != 0) glActiveTextureARB(arbnumber);
638         glBindTexture(tex->target, tex->bindcode);
639         glEnable(tex->target);
640         if (number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
641
642         tex->number = number;
643
644         GPU_print_error("Post Texture Bind");
645 }
646
647 void GPU_texture_unbind(GPUTexture *tex)
648 {
649         GLenum arbnumber;
650
651         if (tex->number >= GG.maxtextures) {
652                 GPU_print_error("Not enough texture slots.");
653                 return;
654         }
655
656         if (tex->number == -1)
657                 return;
658         
659         GPU_print_error("Pre Texture Unbind");
660
661         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
662         if (tex->number != 0) glActiveTextureARB(arbnumber);
663         glBindTexture(tex->target, 0);
664         glDisable(tex->target);
665         if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
666
667         tex->number = -1;
668
669         GPU_print_error("Post Texture Unbind");
670 }
671
672 void GPU_texture_free(GPUTexture *tex)
673 {
674         tex->refcount--;
675
676         if (tex->refcount < 0)
677                 fprintf(stderr, "GPUTexture: negative refcount\n");
678         
679         if (tex->refcount == 0) {
680                 if (tex->fb)
681                         GPU_framebuffer_texture_detach(tex->fb, tex);
682                 if (tex->bindcode && !tex->fromblender)
683                         glDeleteTextures(1, &tex->bindcode);
684
685                 MEM_freeN(tex);
686         }
687 }
688
689 void GPU_texture_ref(GPUTexture *tex)
690 {
691         tex->refcount++;
692 }
693
694 int GPU_texture_target(GPUTexture *tex)
695 {
696         return tex->target;
697 }
698
699 int GPU_texture_opengl_width(GPUTexture *tex)
700 {
701         return tex->w;
702 }
703
704 int GPU_texture_opengl_height(GPUTexture *tex)
705 {
706         return tex->h;
707 }
708
709 int GPU_texture_opengl_bindcode(GPUTexture *tex)
710 {
711         return tex->bindcode;
712 }
713
714 GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex)
715 {
716         return tex->fb;
717 }
718
719 /* GPUFrameBuffer */
720
721 struct GPUFrameBuffer {
722         GLuint object;
723         GPUTexture *colortex;
724         GPUTexture *depthtex;
725 };
726
727 GPUFrameBuffer *GPU_framebuffer_create(void)
728 {
729         GPUFrameBuffer *fb;
730
731         if (!GLEW_EXT_framebuffer_object)
732                 return NULL;
733         
734         fb= MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
735         glGenFramebuffersEXT(1, &fb->object);
736
737         if (!fb->object) {
738                 fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
739                         (int)glGetError());
740                 GPU_framebuffer_free(fb);
741                 return NULL;
742         }
743
744         return fb;
745 }
746
747 int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, char err_out[256])
748 {
749         GLenum status;
750         GLenum attachment;
751
752         if (tex->depth)
753                 attachment = GL_DEPTH_ATTACHMENT_EXT;
754         else
755                 attachment = GL_COLOR_ATTACHMENT0_EXT;
756
757         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
758         GG.currentfb = fb->object;
759
760         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, 
761                 tex->target, tex->bindcode, 0);
762
763         if (tex->depth) {
764                 glDrawBuffer(GL_NONE);
765                 glReadBuffer(GL_NONE);
766         }
767         else {
768                 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
769                 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
770         }
771
772         status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
773
774         if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
775                 GPU_framebuffer_restore();
776                 GPU_print_framebuffer_error(status, err_out);
777                 return 0;
778         }
779
780         if (tex->depth)
781                 fb->depthtex = tex;
782         else
783                 fb->colortex = tex;
784
785         tex->fb= fb;
786
787         return 1;
788 }
789
790 void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
791 {
792         GLenum attachment;
793
794         if (!tex->fb)
795                 return;
796
797         if (GG.currentfb != tex->fb->object) {
798                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
799                 GG.currentfb = tex->fb->object;
800         }
801
802         if (tex->depth) {
803                 fb->depthtex = NULL;
804                 attachment = GL_DEPTH_ATTACHMENT_EXT;
805         }
806         else {
807                 fb->colortex = NULL;
808                 attachment = GL_COLOR_ATTACHMENT0_EXT;
809         }
810
811         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
812                 tex->target, 0, 0);
813
814         tex->fb = NULL;
815 }
816
817 void GPU_framebuffer_texture_bind(GPUFrameBuffer *UNUSED(fb), GPUTexture *tex, int w, int h)
818 {
819         /* push attributes */
820         glPushAttrib(GL_ENABLE_BIT);
821         glPushAttrib(GL_VIEWPORT_BIT);
822         glDisable(GL_SCISSOR_TEST);
823
824         /* bind framebuffer */
825         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
826
827         /* push matrices and set default viewport and matrix */
828         glViewport(0, 0, w, h);
829         GG.currentfb = tex->fb->object;
830
831         glMatrixMode(GL_PROJECTION);
832         glPushMatrix();
833         glLoadIdentity();
834         glMatrixMode(GL_MODELVIEW);
835         glPushMatrix();
836         glLoadIdentity();
837 }
838
839 void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
840 {
841         /* restore matrix */
842         glMatrixMode(GL_PROJECTION);
843         glPopMatrix();
844         glMatrixMode(GL_MODELVIEW);
845         glPopMatrix();
846
847         /* restore attributes */
848         glPopAttrib();
849         glPopAttrib();
850         glEnable(GL_SCISSOR_TEST);
851 }
852
853 void GPU_framebuffer_free(GPUFrameBuffer *fb)
854 {
855         if (fb->depthtex)
856                 GPU_framebuffer_texture_detach(fb, fb->depthtex);
857         if (fb->colortex)
858                 GPU_framebuffer_texture_detach(fb, fb->colortex);
859
860         if (fb->object) {
861                 glDeleteFramebuffersEXT(1, &fb->object);
862
863                 if (GG.currentfb == fb->object) {
864                         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
865                         GG.currentfb = 0;
866                 }
867         }
868
869         MEM_freeN(fb);
870 }
871
872 void GPU_framebuffer_restore(void)
873 {
874         if (GG.currentfb != 0) {
875                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
876                 GG.currentfb = 0;
877         }
878 }
879
880 void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex)
881 {
882         float scaleh[2] = {1.0f/GPU_texture_opengl_width(blurtex), 0.0f};
883         float scalev[2] = {0.0f, 1.0f/GPU_texture_opengl_height(tex)};
884
885         GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR);
886         int scale_uniform, texture_source_uniform;
887
888         if (!blur_shader)
889                 return;
890
891         scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU");
892         texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource");
893                 
894         /* Blurring horizontally */
895
896         /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid
897            pushing unnecessary matrices onto the OpenGL stack. */
898         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object);
899
900         GPU_shader_bind(blur_shader);
901         GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float*)scaleh);
902         GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex);
903         glViewport(0, 0, GPU_texture_opengl_width(blurtex), GPU_texture_opengl_height(blurtex));
904
905         /* Peparing to draw quad */
906         glMatrixMode(GL_MODELVIEW);
907         glLoadIdentity();
908         glMatrixMode(GL_TEXTURE);
909         glLoadIdentity();
910         glMatrixMode(GL_PROJECTION);
911         glLoadIdentity();
912
913         GPU_texture_bind(tex, 0);
914
915         /* Drawing quad */
916         glBegin(GL_QUADS);
917                 glTexCoord2d(0,0);glVertex2f(1,1);
918                 glTexCoord2d(1,0);glVertex2f(-1,1);
919                 glTexCoord2d(1,1);glVertex2f(-1,-1);
920                 glTexCoord2d(0,1);glVertex2f(1,-1);
921         glEnd();
922                 
923         /* Blurring vertically */
924
925         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
926         glViewport(0, 0, GPU_texture_opengl_width(tex), GPU_texture_opengl_height(tex));
927         GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float*)scalev);
928         GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex);
929         GPU_texture_bind(blurtex, 0);
930         glBegin(GL_QUADS);
931                 glTexCoord2d(0,0);glVertex2f(1,1);
932                 glTexCoord2d(1,0);glVertex2f(-1,1);
933                 glTexCoord2d(1,1);glVertex2f(-1,-1);
934                 glTexCoord2d(0,1);glVertex2f(1,-1);
935         glEnd();
936         GPU_shader_unbind(blur_shader);
937 }
938
939 /* GPUOffScreen */
940
941 struct GPUOffScreen {
942         GPUFrameBuffer *fb;
943         GPUTexture *color;
944         GPUTexture *depth;
945
946         /* requested width/height, may be smaller than actual texture size due
947          * to missing non-power of two support, so we compensate for that */
948         int w, h;
949 };
950
951 GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256])
952 {
953         GPUOffScreen *ofs;
954
955         ofs= MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
956         ofs->w= width;
957         ofs->h= height;
958
959         ofs->fb = GPU_framebuffer_create();
960         if (!ofs->fb) {
961                 GPU_offscreen_free(ofs);
962                 return NULL;
963         }
964
965         ofs->depth = GPU_texture_create_depth(width, height, err_out);
966         if (!ofs->depth) {
967                 GPU_offscreen_free(ofs);
968                 return NULL;
969         }
970
971         if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, err_out)) {
972                 GPU_offscreen_free(ofs);
973                 return NULL;
974         }
975
976         ofs->color = GPU_texture_create_2D(width, height, NULL, err_out);
977         if (!ofs->color) {
978                 GPU_offscreen_free(ofs);
979                 return NULL;
980         }
981
982         if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, err_out)) {
983                 GPU_offscreen_free(ofs);
984                 return NULL;
985         }
986
987         GPU_framebuffer_restore();
988
989         return ofs;
990 }
991
992 void GPU_offscreen_free(GPUOffScreen *ofs)
993 {
994         if (ofs->fb)
995                 GPU_framebuffer_free(ofs->fb);
996         if (ofs->color)
997                 GPU_texture_free(ofs->color);
998         if (ofs->depth)
999                 GPU_texture_free(ofs->depth);
1000         
1001         MEM_freeN(ofs);
1002 }
1003
1004 void GPU_offscreen_bind(GPUOffScreen *ofs)
1005 {
1006         glDisable(GL_SCISSOR_TEST);
1007         GPU_framebuffer_texture_bind(ofs->fb, ofs->color, ofs->w, ofs->h);
1008 }
1009
1010 void GPU_offscreen_unbind(GPUOffScreen *ofs)
1011 {
1012         GPU_framebuffer_texture_unbind(ofs->fb, ofs->color);
1013         GPU_framebuffer_restore();
1014         glEnable(GL_SCISSOR_TEST);
1015 }
1016
1017 void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
1018 {
1019         glReadPixels(0, 0, ofs->w, ofs->h, GL_RGBA, type, pixels);
1020 }
1021
1022 /* GPUShader */
1023
1024 struct GPUShader {
1025         GLhandleARB object;             /* handle for full shader */
1026         GLhandleARB vertex;             /* handle for vertex shader */
1027         GLhandleARB fragment;   /* handle for fragment shader */
1028         GLhandleARB lib;                /* handle for libment shader */
1029         int totattrib;                  /* total number of attributes */
1030 };
1031
1032 static void shader_print_errors(const char *task, char *log, const char *code)
1033 {
1034         const char *c, *pos, *end = code + strlen(code);
1035         int line = 1;
1036
1037         fprintf(stderr, "GPUShader: %s error:\n", task);
1038
1039         if (G.debug & G_DEBUG) {
1040                 c = code;
1041                 while ((c < end) && (pos = strchr(c, '\n'))) {
1042                         fprintf(stderr, "%2d  ", line);
1043                         fwrite(c, (pos+1)-c, 1, stderr);
1044                         c = pos+1;
1045                         line++;
1046                 }
1047
1048                 fprintf(stderr, "%s", c);
1049         }
1050
1051         fprintf(stderr, "%s\n", log);
1052 }
1053
1054 GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPUShader *lib,*/ const char *libcode)
1055 {
1056         GLint status;
1057         GLcharARB log[5000];
1058         const char *fragsource[2];
1059         GLsizei length = 0;
1060         GLint count;
1061         GPUShader *shader;
1062
1063         if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
1064                 return NULL;
1065
1066         shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
1067
1068         if (vertexcode)
1069                 shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
1070         if (fragcode)
1071                 shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
1072         shader->object = glCreateProgramObjectARB();
1073
1074         if (!shader->object ||
1075                 (vertexcode && !shader->vertex) ||
1076                 (fragcode && !shader->fragment)) {
1077                 fprintf(stderr, "GPUShader, object creation failed.\n");
1078                 GPU_shader_free(shader);
1079                 return NULL;
1080         }
1081
1082         if (vertexcode) {
1083                 glAttachObjectARB(shader->object, shader->vertex);
1084                 glShaderSourceARB(shader->vertex, 1, (const char**)&vertexcode, NULL);
1085
1086                 glCompileShaderARB(shader->vertex);
1087                 glGetObjectParameterivARB(shader->vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status);
1088
1089                 if (!status) {
1090                         glGetInfoLogARB(shader->vertex, sizeof(log), &length, log);
1091                         shader_print_errors("compile", log, vertexcode);
1092
1093                         GPU_shader_free(shader);
1094                         return NULL;
1095                 }
1096         }
1097
1098         if (fragcode) {
1099                 count = 0;
1100                 if (libcode) fragsource[count++] = libcode;
1101                 if (fragcode) fragsource[count++] = fragcode;
1102
1103                 glAttachObjectARB(shader->object, shader->fragment);
1104                 glShaderSourceARB(shader->fragment, count, fragsource, NULL);
1105
1106                 glCompileShaderARB(shader->fragment);
1107                 glGetObjectParameterivARB(shader->fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status);
1108
1109                 if (!status) {
1110                         glGetInfoLogARB(shader->fragment, sizeof(log), &length, log);
1111                         shader_print_errors("compile", log, fragcode);
1112
1113                         GPU_shader_free(shader);
1114                         return NULL;
1115                 }
1116         }
1117
1118 #if 0
1119         if (lib && lib->lib)
1120                 glAttachObjectARB(shader->object, lib->lib);
1121 #endif
1122
1123         glLinkProgramARB(shader->object);
1124         glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status);
1125         if (!status) {
1126                 glGetInfoLogARB(shader->object, sizeof(log), &length, log);
1127                 if (fragcode) shader_print_errors("linking", log, fragcode);
1128                 else if (vertexcode) shader_print_errors("linking", log, vertexcode);
1129                 else if (libcode) shader_print_errors("linking", log, libcode);
1130
1131                 GPU_shader_free(shader);
1132                 return NULL;
1133         }
1134
1135         return shader;
1136 }
1137
1138 #if 0
1139 GPUShader *GPU_shader_create_lib(const char *code)
1140 {
1141         GLint status;
1142         GLcharARB log[5000];
1143         GLsizei length = 0;
1144         GPUShader *shader;
1145
1146         if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
1147                 return NULL;
1148
1149         shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
1150
1151         shader->lib = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
1152
1153         if (!shader->lib) {
1154                 fprintf(stderr, "GPUShader, object creation failed.\n");
1155                 GPU_shader_free(shader);
1156                 return NULL;
1157         }
1158
1159         glShaderSourceARB(shader->lib, 1, (const char**)&code, NULL);
1160
1161         glCompileShaderARB(shader->lib);
1162         glGetObjectParameterivARB(shader->lib, GL_OBJECT_COMPILE_STATUS_ARB, &status);
1163
1164         if (!status) {
1165                 glGetInfoLogARB(shader->lib, sizeof(log), &length, log);
1166                 shader_print_errors("compile", log, code);
1167
1168                 GPU_shader_free(shader);
1169                 return NULL;
1170         }
1171
1172         return shader;
1173 }
1174 #endif
1175
1176 void GPU_shader_bind(GPUShader *shader)
1177 {
1178         GPU_print_error("Pre Shader Bind");
1179         glUseProgramObjectARB(shader->object);
1180         GPU_print_error("Post Shader Bind");
1181 }
1182
1183 void GPU_shader_unbind(GPUShader *UNUSED(shader))
1184 {
1185         GPU_print_error("Pre Shader Unbind");
1186         glUseProgramObjectARB(0);
1187         GPU_print_error("Post Shader Unbind");
1188 }
1189
1190 void GPU_shader_free(GPUShader *shader)
1191 {
1192         if (shader->lib)
1193                 glDeleteObjectARB(shader->lib);
1194         if (shader->vertex)
1195                 glDeleteObjectARB(shader->vertex);
1196         if (shader->fragment)
1197                 glDeleteObjectARB(shader->fragment);
1198         if (shader->object)
1199                 glDeleteObjectARB(shader->object);
1200         MEM_freeN(shader);
1201 }
1202
1203 int GPU_shader_get_uniform(GPUShader *shader, const char *name)
1204 {
1205         return glGetUniformLocationARB(shader->object, name);
1206 }
1207
1208 void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, float *value)
1209 {
1210         if (location == -1)
1211                 return;
1212
1213         GPU_print_error("Pre Uniform Vector");
1214
1215         if (length == 1) glUniform1fvARB(location, arraysize, value);
1216         else if (length == 2) glUniform2fvARB(location, arraysize, value);
1217         else if (length == 3) glUniform3fvARB(location, arraysize, value);
1218         else if (length == 4) glUniform4fvARB(location, arraysize, value);
1219         else if (length == 9) glUniformMatrix3fvARB(location, arraysize, 0, value);
1220         else if (length == 16) glUniformMatrix4fvARB(location, arraysize, 0, value);
1221
1222         GPU_print_error("Post Uniform Vector");
1223 }
1224
1225 void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
1226 {
1227         GLenum arbnumber;
1228
1229         if (tex->number >= GG.maxtextures) {
1230                 GPU_print_error("Not enough texture slots.");
1231                 return;
1232         }
1233                 
1234         if (tex->number == -1)
1235                 return;
1236
1237         if (location == -1)
1238                 return;
1239
1240         GPU_print_error("Pre Uniform Texture");
1241
1242         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
1243
1244         if (tex->number != 0) glActiveTextureARB(arbnumber);
1245         glBindTexture(tex->target, tex->bindcode);
1246         glUniform1iARB(location, tex->number);
1247         glEnable(tex->target);
1248         if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
1249
1250         GPU_print_error("Post Uniform Texture");
1251 }
1252
1253 int GPU_shader_get_attribute(GPUShader *shader, const char *name)
1254 {
1255         int index;
1256         
1257         GPU_print_error("Pre Get Attribute");
1258
1259         index = glGetAttribLocationARB(shader->object, name);
1260
1261         GPU_print_error("Post Get Attribute");
1262
1263         return index;
1264 }
1265
1266 GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
1267 {
1268         GPUShader *retval = NULL;
1269
1270         switch (shader)
1271         {
1272         case GPU_SHADER_VSM_STORE:
1273                 if (!GG.shaders.vsm_store)
1274                         GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL);
1275                 retval = GG.shaders.vsm_store;
1276                 break;
1277         case GPU_SHADER_SEP_GAUSSIAN_BLUR:
1278                 if (!GG.shaders.sep_gaussian_blur)
1279                         GG.shaders.sep_gaussian_blur = GPU_shader_create(datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, NULL);
1280                 retval = GG.shaders.sep_gaussian_blur;
1281                 break;
1282         }
1283
1284         if (retval == NULL)
1285                 printf("Unable to create a GPUShader for builtin shader: %d\n", shader);
1286
1287         return retval;
1288 }
1289
1290 void GPU_shader_free_builtin_shaders()
1291 {
1292         if (GG.shaders.vsm_store)
1293         {
1294                 MEM_freeN(GG.shaders.vsm_store);
1295                 GG.shaders.vsm_store = NULL;
1296         }
1297
1298         if (GG.shaders.sep_gaussian_blur)
1299         {
1300                 MEM_freeN(GG.shaders.sep_gaussian_blur);
1301                 GG.shaders.sep_gaussian_blur = NULL;
1302         }
1303 }
1304
1305 #if 0
1306 /* GPUPixelBuffer */
1307
1308 typedef struct GPUPixelBuffer {
1309         GLuint bindcode[2];
1310         GLuint current;
1311         int datasize;
1312         int numbuffers;
1313         int halffloat;
1314 } GPUPixelBuffer;
1315
1316 void GPU_pixelbuffer_free(GPUPixelBuffer *pb)
1317 {
1318         if (pb->bindcode[0])
1319                 glDeleteBuffersARB(pb->numbuffers, pb->bindcode);
1320         MEM_freeN(pb);
1321 }
1322
1323 GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffers)
1324 {
1325         GPUPixelBuffer *pb;
1326
1327         if (!GLEW_ARB_multitexture || !GLEW_EXT_pixel_buffer_object)
1328                 return NULL;
1329         
1330         pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO");
1331         pb->datasize = x*y*4*((halffloat)? 16: 8);
1332         pb->numbuffers = numbuffers;
1333         pb->halffloat = halffloat;
1334
1335         glGenBuffersARB(pb->numbuffers, pb->bindcode);
1336
1337         if (!pb->bindcode[0]) {
1338                 fprintf(stderr, "GPUPixelBuffer allocation failed\n");
1339                 GPU_pixelbuffer_free(pb);
1340                 return NULL;
1341         }
1342
1343         return pb;
1344 }
1345
1346 void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb)
1347 {
1348         void *pixels;
1349         int i;
1350
1351         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
1352
1353         for (i = 0; i < pb->numbuffers; i++) {
1354                 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->bindcode[pb->current]);
1355                 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->datasize, NULL,
1356                 GL_STREAM_DRAW_ARB);
1357
1358                 pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
1359                 /*memcpy(pixels, _oImage.data(), pb->datasize);*/
1360
1361                 if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
1362                         fprintf(stderr, "Could not unmap opengl PBO\n");
1363                         break;
1364                 }
1365         }
1366
1367         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
1368 }
1369
1370 static int pixelbuffer_map_into_gpu(GLuint bindcode)
1371 {
1372         void *pixels;
1373
1374         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
1375         pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
1376
1377         /* do stuff in pixels */
1378
1379         if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
1380                 fprintf(stderr, "Could not unmap opengl PBO\n");
1381                 return 0;
1382         }
1383         
1384         return 1;
1385 }
1386
1387 static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLuint bindcode)
1388 {
1389         GLenum type = (pb->halffloat)? GL_HALF_FLOAT_NV: GL_UNSIGNED_BYTE;
1390         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
1391         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
1392
1393         glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h,
1394                                         GL_RGBA, type, NULL);
1395
1396         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
1397         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
1398 }
1399
1400 void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb)
1401 {
1402         int newbuffer;
1403
1404         if (pb->numbuffers == 1) {
1405                 pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[0]);
1406                 pixelbuffer_map_into_gpu(pb->bindcode[0]);
1407         }
1408         else {
1409                 pb->current = (pb->current+1)%pb->numbuffers;
1410                 newbuffer = (pb->current+1)%pb->numbuffers;
1411
1412                 pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]);
1413                 pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]);
1414         }
1415 }
1416 #endif
1417