c5cfbea9b5c0e7e4757550afebe0cb2c9e09e01d
[blender-staging.git] / source / blender / gpu / intern / gpu_extensions.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  *
23  * The Original Code is Copyright (C) 2005 Blender Foundation.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): Brecht Van Lommel.
29  *
30  * ***** END GPL LICENSE BLOCK *****
31  */
32
33 /** \file blender/gpu/intern/gpu_extensions.c
34  *  \ingroup gpu
35  */
36
37
38 #include "GL/glew.h"
39
40 #include "DNA_image_types.h"
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BKE_global.h"
45
46
47 #include "BLI_blenlib.h"
48 #include "BLI_utildefines.h"
49
50 #include "GPU_draw.h"
51 #include "GPU_extensions.h"
52
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56
57 #include "BLI_winstuff.h"
58
59 /* Extensions support */
60
61 /* extensions used:
62         - texture border clamp: 1.3 core
63         - fragement shader: 2.0 core
64         - framebuffer object: ext specification
65         - multitexture 1.3 core
66         - arb non power of two: 2.0 core
67         - pixel buffer objects? 2.1 core
68         - arb draw buffers? 2.0 core
69 */
70
71 static struct GPUGlobal {
72         GLint maxtextures;
73         GLuint currentfb;
74         int glslsupport;
75         int extdisabled;
76         int colordepth;
77         int npotdisabled; /* ATI 3xx-5xx (and more) chipsets support NPoT partially (== not enough) */
78         GPUDeviceType device;
79         GPUOSType os;
80         GPUDriverType driver;
81 } GG = {1, 0, 0, 0, 0};
82
83 /* GPU Types */
84
85 int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
86 {
87         return (GG.device & device) && (GG.os & os) && (GG.driver & driver);
88 }
89
90 /* GPU Extensions */
91
92 void GPU_extensions_disable(void)
93 {
94         GG.extdisabled = 1;
95 }
96
97 void GPU_extensions_init(void)
98 {
99         GLint r, g, b;
100         const char *vendor, *renderer;
101
102         /* can't avoid calling this multiple times, see wm_window_add_ghostwindow */
103         static char init= 0;
104         if(init) return;
105         init= 1;
106
107         glewInit();
108
109         /* glewIsSupported("GL_VERSION_2_0") */
110
111         if (GLEW_ARB_multitexture)
112                 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &GG.maxtextures);
113
114         GG.glslsupport = 1;
115         if (!GLEW_ARB_multitexture) GG.glslsupport = 0;
116         if (!GLEW_ARB_vertex_shader) GG.glslsupport = 0;
117         if (!GLEW_ARB_fragment_shader) GG.glslsupport = 0;
118
119         glGetIntegerv(GL_RED_BITS, &r);
120         glGetIntegerv(GL_GREEN_BITS, &g);
121         glGetIntegerv(GL_BLUE_BITS, &b);
122     GG.colordepth = r+g+b; /* assumes same depth for RGB */
123     
124         vendor = (const char*)glGetString(GL_VENDOR);
125         renderer = (const char*)glGetString(GL_RENDERER);
126
127         if(strstr(vendor, "ATI")) {
128                 GG.device = GPU_DEVICE_ATI;
129                 GG.driver = GPU_DRIVER_OFFICIAL;
130
131                 /* ATI X1xxx cards (R500 chipset) lack full support for npot textures
132                  * although they report the GLEW_ARB_texture_non_power_of_two extension.
133                  */
134                 if(strstr(renderer, "X1"))
135                         GG.npotdisabled = 1;
136         }
137         else if(strstr(vendor, "NVIDIA")) {
138                 GG.device = GPU_DEVICE_NVIDIA;
139                 GG.driver = GPU_DRIVER_OFFICIAL;
140         }
141         else if(strstr(vendor, "Intel") ||
142                 /* src/mesa/drivers/dri/intel/intel_context.c */
143                 strstr(renderer, "Mesa DRI Intel") ||
144                 strstr(renderer, "Mesa DRI Mobile Intel")) {
145                 GG.device = GPU_DEVICE_INTEL;
146                 GG.driver = GPU_DRIVER_OFFICIAL;
147         }
148         else if(strstr(renderer, "Mesa DRI R") || (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI "))) {
149                 GG.device = GPU_DEVICE_ATI;
150                 GG.driver = GPU_DRIVER_OPENSOURCE;
151                 /* ATI 9500 to X2300 cards support NPoT textures poorly
152                  * Incomplete list http://dri.freedesktop.org/wiki/ATIRadeon
153                  * New IDs from MESA's src/gallium/drivers/r300/r300_screen.c
154                  */
155                 if(strstr(renderer, "R3") || strstr(renderer, "RV3") ||
156                    strstr(renderer, "R4") || strstr(renderer, "RV4") ||
157                    strstr(renderer, "RS4") || strstr(renderer, "RC4") ||
158                    strstr(renderer, "R5") || strstr(renderer, "RV5") ||
159                    strstr(renderer, "RS600") || strstr(renderer, "RS690") ||
160                    strstr(renderer, "RS740"))
161                         GG.npotdisabled = 1;
162         }
163         else if(strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) {
164                 GG.device = GPU_DEVICE_NVIDIA;
165                 GG.driver = GPU_DRIVER_OPENSOURCE;
166         }
167         else if(strstr(vendor, "Mesa")) {
168                 GG.device = GPU_DEVICE_SOFTWARE;
169                 GG.driver = GPU_DRIVER_SOFTWARE;
170         }
171         else if(strstr(vendor, "Microsoft")) {
172                 GG.device = GPU_DEVICE_SOFTWARE;
173                 GG.driver = GPU_DRIVER_SOFTWARE;
174         }
175         else if(strstr(renderer, "Apple Software Renderer")) {
176                 GG.device = GPU_DEVICE_SOFTWARE;
177                 GG.driver = GPU_DRIVER_SOFTWARE;
178         }
179         else {
180                 GG.device = GPU_DEVICE_ANY;
181                 GG.driver = GPU_DRIVER_ANY;
182         }
183
184         GG.os = GPU_OS_UNIX;
185 #ifdef _WIN32
186         GG.os = GPU_OS_WIN;
187 #endif
188 #ifdef __APPLE__
189         GG.os = GPU_OS_MAC;
190 #endif
191 }
192
193 int GPU_glsl_support(void)
194 {
195         return !GG.extdisabled && GG.glslsupport;
196 }
197
198 int GPU_non_power_of_two_support(void)
199 {
200         /* Exception for buggy ATI/Apple driver in Mac OS X 10.5/10.6,
201          * they claim to support this but can cause system freeze */
202         if(GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_MAC, GPU_DRIVER_OFFICIAL))
203                 return 0;
204
205         if(GG.npotdisabled)
206                 return 0;
207
208         return GLEW_ARB_texture_non_power_of_two;
209 }
210
211 int GPU_color_depth(void)
212 {
213     return GG.colordepth;
214 }
215
216 int GPU_print_error(const char *str)
217 {
218         GLenum errCode;
219
220         if (G.f & G_DEBUG) {
221                 if ((errCode = glGetError()) != GL_NO_ERROR) {
222                         fprintf(stderr, "%s opengl error: %s\n", str, gluErrorString(errCode));
223                         return 1;
224                 }
225         }
226
227         return 0;
228 }
229
230 static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
231 {
232         const char *err= "unknown";
233
234         switch(status) {
235                 case GL_FRAMEBUFFER_COMPLETE_EXT:
236                         break;
237                 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
238                         err= "Incomplete attachment";
239                         break;
240                 case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
241                         err= "Unsupported framebuffer format";
242                         break;
243                 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
244                         err= "Missing attachment";
245                         break;
246                 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
247                         err= "Attached images must have same dimensions";
248                         break;
249                 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
250                         err= "Attached images must have same format";
251                         break;
252                 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
253                         err= "Missing draw buffer";
254                         break;
255                 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
256                         err= "Missing read buffer";
257                         break;
258         }
259
260         if(err_out) {
261                 snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'",
262                         (int)status,
263                         err);
264         }
265         else {
266                 fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n",
267                         (int)status,
268                         err);
269         }
270
271 }
272
273 /* GPUTexture */
274
275 struct GPUTexture {
276         int w, h;                               /* width/height */
277         int number;                             /* number for multitexture binding */
278         int refcount;                   /* reference count */
279         GLenum target;                  /* GL_TEXTURE_* */
280         GLuint bindcode;                /* opengl identifier for texture */
281         int fromblender;                /* we got the texture from Blender */
282
283         GPUFrameBuffer *fb;             /* GPUFramebuffer this texture is attached to */
284         int depth;                              /* is a depth texture? */
285 };
286
287 static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels)
288 {
289         unsigned char *pixels, *p;
290         float *fp;
291         int a, len;
292
293         len = 4*length;
294         fp = fpixels;
295         p = pixels = MEM_callocN(sizeof(unsigned char)*len, "GPUTexturePixels");
296
297         for (a=0; a<len; a++, p++, fp++)
298                 *p = FTOCHAR((*fp));
299
300         return pixels;
301 }
302
303 static int is_pow2(int n)
304 {
305         return ((n)&(n-1))==0;
306 }
307
308 static int larger_pow2(int n)
309 {
310         if (is_pow2(n))
311                 return n;
312
313         while(!is_pow2(n))
314                 n= n&(n-1);
315
316         return n*2;
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                         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 = larger_pow2(tex->w);
365                 tex->h = larger_pow2(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)? 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 = larger_pow2(tex->w);
474                 tex->h = larger_pow2(tex->h);
475                 tex->depth = larger_pow2(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, 0);
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         if (tex)
521                 GPU_texture_unbind(tex);
522
523         return tex;
524 }
525
526 GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, double time, int mipmap)
527 {
528         GPUTexture *tex;
529         GLint w, h, border, lastbindcode, bindcode;
530
531         glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode);
532
533         GPU_update_image_time(ima, time);
534         bindcode = GPU_verify_image(ima, iuser, 0, 0, mipmap);
535
536         if(ima->gputexture) {
537                 ima->gputexture->bindcode = bindcode;
538                 glBindTexture(GL_TEXTURE_2D, lastbindcode);
539                 return ima->gputexture;
540         }
541
542         if(!bindcode) {
543                 glBindTexture(GL_TEXTURE_2D, lastbindcode);
544                 return NULL;
545         }
546
547         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
548         tex->bindcode = bindcode;
549         tex->number = -1;
550         tex->refcount = 1;
551         tex->target = GL_TEXTURE_2D;
552         tex->fromblender = 1;
553
554         ima->gputexture= tex;
555
556         if (!glIsTexture(tex->bindcode)) {
557                 GPU_print_error("Blender Texture");
558         }
559         else {
560                 glBindTexture(GL_TEXTURE_2D, tex->bindcode);
561                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
562                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
563                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border);
564
565                 tex->w = w - border;
566                 tex->h = h - border;
567         }
568
569         glBindTexture(GL_TEXTURE_2D, lastbindcode);
570
571         return tex;
572 }
573
574 GPUTexture *GPU_texture_create_1D(int w, float *fpixels, char err_out[256])
575 {
576         GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, err_out);
577
578         if (tex)
579                 GPU_texture_unbind(tex);
580         
581         return tex;
582 }
583
584 GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels, char err_out[256])
585 {
586         GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, err_out);
587
588         if (tex)
589                 GPU_texture_unbind(tex);
590         
591         return tex;
592 }
593
594 GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
595 {
596         GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, err_out);
597
598         if (tex)
599                 GPU_texture_unbind(tex);
600         
601         return tex;
602 }
603
604 void GPU_texture_bind(GPUTexture *tex, int number)
605 {
606         GLenum arbnumber;
607
608         if (number >= GG.maxtextures) {
609                 GPU_print_error("Not enough texture slots.");
610                 return;
611         }
612
613         if(number == -1)
614                 return;
615
616         GPU_print_error("Pre Texture Bind");
617
618         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + number);
619         if (number != 0) glActiveTextureARB(arbnumber);
620         glBindTexture(tex->target, tex->bindcode);
621         glEnable(tex->target);
622         if (number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
623
624         tex->number = number;
625
626         GPU_print_error("Post Texture Bind");
627 }
628
629 void GPU_texture_unbind(GPUTexture *tex)
630 {
631         GLenum arbnumber;
632
633         if (tex->number >= GG.maxtextures) {
634                 GPU_print_error("Not enough texture slots.");
635                 return;
636         }
637
638         if(tex->number == -1)
639                 return;
640         
641         GPU_print_error("Pre Texture Unbind");
642
643         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
644         if (tex->number != 0) glActiveTextureARB(arbnumber);
645         glBindTexture(tex->target, 0);
646         glDisable(tex->target);
647         if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
648
649         tex->number = -1;
650
651         GPU_print_error("Post Texture Unbind");
652 }
653
654 void GPU_texture_free(GPUTexture *tex)
655 {
656         tex->refcount--;
657
658         if (tex->refcount < 0)
659                 fprintf(stderr, "GPUTexture: negative refcount\n");
660         
661         if (tex->refcount == 0) {
662                 if (tex->fb)
663                         GPU_framebuffer_texture_detach(tex->fb, tex);
664                 if (tex->bindcode && !tex->fromblender)
665                         glDeleteTextures(1, &tex->bindcode);
666
667                 MEM_freeN(tex);
668         }
669 }
670
671 void GPU_texture_ref(GPUTexture *tex)
672 {
673         tex->refcount++;
674 }
675
676 int GPU_texture_target(GPUTexture *tex)
677 {
678         return tex->target;
679 }
680
681 int GPU_texture_opengl_width(GPUTexture *tex)
682 {
683         return tex->w;
684 }
685
686 int GPU_texture_opengl_height(GPUTexture *tex)
687 {
688         return tex->h;
689 }
690
691 GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex)
692 {
693         return tex->fb;
694 }
695
696 /* GPUFrameBuffer */
697
698 struct GPUFrameBuffer {
699         GLuint object;
700         GPUTexture *colortex;
701         GPUTexture *depthtex;
702 };
703
704 GPUFrameBuffer *GPU_framebuffer_create(void)
705 {
706         GPUFrameBuffer *fb;
707
708         if (!GLEW_EXT_framebuffer_object)
709                 return NULL;
710         
711         fb= MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
712         glGenFramebuffersEXT(1, &fb->object);
713
714         if (!fb->object) {
715                 fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
716                         (int)glGetError());
717                 GPU_framebuffer_free(fb);
718                 return NULL;
719         }
720
721         return fb;
722 }
723
724 int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, char err_out[256])
725 {
726         GLenum status;
727         GLenum attachment;
728
729         if(tex->depth)
730                 attachment = GL_DEPTH_ATTACHMENT_EXT;
731         else
732                 attachment = GL_COLOR_ATTACHMENT0_EXT;
733
734         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
735         GG.currentfb = fb->object;
736
737         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, 
738                 tex->target, tex->bindcode, 0);
739
740         if(tex->depth) {
741                 glDrawBuffer(GL_NONE);
742                 glReadBuffer(GL_NONE);
743         }
744         else {
745                 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
746                 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
747         }
748
749         status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
750
751         if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
752                 GPU_framebuffer_restore();
753                 GPU_print_framebuffer_error(status, err_out);
754                 return 0;
755         }
756
757         if(tex->depth)
758                 fb->depthtex = tex;
759         else
760                 fb->colortex = tex;
761
762         tex->fb= fb;
763
764         return 1;
765 }
766
767 void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
768 {
769         GLenum attachment;
770
771         if(!tex->fb)
772                 return;
773
774         if(GG.currentfb != tex->fb->object) {
775                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
776                 GG.currentfb = tex->fb->object;
777         }
778
779         if(tex->depth) {
780                 fb->depthtex = NULL;
781                 attachment = GL_DEPTH_ATTACHMENT_EXT;
782         }
783         else {
784                 fb->colortex = NULL;
785                 attachment = GL_COLOR_ATTACHMENT0_EXT;
786         }
787
788         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
789                 tex->target, 0, 0);
790
791         tex->fb = NULL;
792 }
793
794 void GPU_framebuffer_texture_bind(GPUFrameBuffer *UNUSED(fb), GPUTexture *tex)
795 {
796         /* push attributes */
797         glPushAttrib(GL_ENABLE_BIT);
798         glPushAttrib(GL_VIEWPORT_BIT);
799         glDisable(GL_SCISSOR_TEST);
800
801         /* bind framebuffer */
802         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
803
804         /* push matrices and set default viewport and matrix */
805         glViewport(0, 0, tex->w, tex->h);
806         GG.currentfb = tex->fb->object;
807
808         glMatrixMode(GL_PROJECTION);
809         glPushMatrix();
810         glLoadIdentity();
811         glMatrixMode(GL_MODELVIEW);
812         glPushMatrix();
813         glLoadIdentity();
814 }
815
816 void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
817 {
818         /* restore matrix */
819         glMatrixMode(GL_PROJECTION);
820         glPopMatrix();
821         glMatrixMode(GL_MODELVIEW);
822         glPopMatrix();
823
824         /* restore attributes */
825         glPopAttrib();
826         glPopAttrib();
827         glEnable(GL_SCISSOR_TEST);
828 }
829
830 void GPU_framebuffer_free(GPUFrameBuffer *fb)
831 {
832         if(fb->depthtex)
833                 GPU_framebuffer_texture_detach(fb, fb->depthtex);
834         if(fb->colortex)
835                 GPU_framebuffer_texture_detach(fb, fb->colortex);
836
837         if(fb->object) {
838                 glDeleteFramebuffersEXT(1, &fb->object);
839
840                 if (GG.currentfb == fb->object) {
841                         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
842                         GG.currentfb = 0;
843                 }
844         }
845
846         MEM_freeN(fb);
847 }
848
849 void GPU_framebuffer_restore(void)
850 {
851         if (GG.currentfb != 0) {
852                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
853                 GG.currentfb = 0;
854         }
855 }
856
857 /* GPUOffScreen */
858
859 struct GPUOffScreen {
860         GPUFrameBuffer *fb;
861         GPUTexture *color;
862         GPUTexture *depth;
863 };
864
865 GPUOffScreen *GPU_offscreen_create(int *width, int *height, char err_out[256])
866 {
867         GPUOffScreen *ofs;
868
869         ofs= MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
870
871         ofs->fb = GPU_framebuffer_create();
872         if(!ofs->fb) {
873                 GPU_offscreen_free(ofs);
874                 return NULL;
875         }
876
877         ofs->depth = GPU_texture_create_depth(*width, *height, err_out);
878         if(!ofs->depth) {
879                 GPU_offscreen_free(ofs);
880                 return NULL;
881         }
882
883         if(*width!=ofs->depth->w || *height!=ofs->depth->h) {
884                 *width= ofs->depth->w;
885                 *height= ofs->depth->h;
886                 printf("Offscreen size differs from given size!\n");
887         }
888         
889         if(!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, err_out)) {
890                 GPU_offscreen_free(ofs);
891                 return NULL;
892         }
893
894         ofs->color = GPU_texture_create_2D(*width, *height, NULL, err_out);
895         if(!ofs->color) {
896                 GPU_offscreen_free(ofs);
897                 return NULL;
898         }
899
900         if(!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, err_out)) {
901                 GPU_offscreen_free(ofs);
902                 return NULL;
903         }
904
905         GPU_framebuffer_restore();
906
907         return ofs;
908 }
909
910 void GPU_offscreen_free(GPUOffScreen *ofs)
911 {
912         if(ofs->fb)
913                 GPU_framebuffer_free(ofs->fb);
914         if(ofs->color)
915                 GPU_texture_free(ofs->color);
916         if(ofs->depth)
917                 GPU_texture_free(ofs->depth);
918         
919         MEM_freeN(ofs);
920 }
921
922 void GPU_offscreen_bind(GPUOffScreen *ofs)
923 {
924         glDisable(GL_SCISSOR_TEST);
925         GPU_framebuffer_texture_bind(ofs->fb, ofs->color);
926 }
927
928 void GPU_offscreen_unbind(GPUOffScreen *ofs)
929 {
930         GPU_framebuffer_texture_unbind(ofs->fb, ofs->color);
931         GPU_framebuffer_restore();
932         glEnable(GL_SCISSOR_TEST);
933 }
934
935 /* GPUShader */
936
937 struct GPUShader {
938         GLhandleARB object;             /* handle for full shader */
939         GLhandleARB vertex;             /* handle for vertex shader */
940         GLhandleARB fragment;   /* handle for fragment shader */
941         GLhandleARB lib;                /* handle for libment shader */
942         int totattrib;                  /* total number of attributes */
943 };
944
945 static void shader_print_errors(const char *task, char *log, const char *code)
946 {
947         const char *c, *pos, *end = code + strlen(code);
948         int line = 1;
949
950         fprintf(stderr, "GPUShader: %s error:\n", task);
951
952         if(G.f & G_DEBUG) {
953                 c = code;
954                 while ((c < end) && (pos = strchr(c, '\n'))) {
955                         fprintf(stderr, "%2d  ", line);
956                         fwrite(c, (pos+1)-c, 1, stderr);
957                         c = pos+1;
958                         line++;
959                 }
960
961                 fprintf(stderr, "%s", c);
962         }
963
964         fprintf(stderr, "%s\n", log);
965 }
966
967 GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPUShader *lib,*/ const char *libcode)
968 {
969         GLint status;
970         GLcharARB log[5000];
971         const char *fragsource[2];
972         GLsizei length = 0;
973         GLint count;
974         GPUShader *shader;
975
976         if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
977                 return NULL;
978
979         shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
980
981         if(vertexcode)
982                 shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
983         if(fragcode)
984                 shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
985         shader->object = glCreateProgramObjectARB();
986
987         if (!shader->object ||
988                 (vertexcode && !shader->vertex) ||
989                 (fragcode && !shader->fragment)) {
990                 fprintf(stderr, "GPUShader, object creation failed.\n");
991                 GPU_shader_free(shader);
992                 return NULL;
993         }
994
995         if(vertexcode) {
996                 glAttachObjectARB(shader->object, shader->vertex);
997                 glShaderSourceARB(shader->vertex, 1, (const char**)&vertexcode, NULL);
998
999                 glCompileShaderARB(shader->vertex);
1000                 glGetObjectParameterivARB(shader->vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status);
1001
1002                 if (!status) {
1003                         glGetInfoLogARB(shader->vertex, sizeof(log), &length, log);
1004                         shader_print_errors("compile", log, vertexcode);
1005
1006                         GPU_shader_free(shader);
1007                         return NULL;
1008                 }
1009         }
1010
1011         if(fragcode) {
1012                 count = 0;
1013                 if(libcode) fragsource[count++] = libcode;
1014                 if(fragcode) fragsource[count++] = fragcode;
1015
1016                 glAttachObjectARB(shader->object, shader->fragment);
1017                 glShaderSourceARB(shader->fragment, count, fragsource, NULL);
1018
1019                 glCompileShaderARB(shader->fragment);
1020                 glGetObjectParameterivARB(shader->fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status);
1021
1022                 if (!status) {
1023                         glGetInfoLogARB(shader->fragment, sizeof(log), &length, log);
1024                         shader_print_errors("compile", log, fragcode);
1025
1026                         GPU_shader_free(shader);
1027                         return NULL;
1028                 }
1029         }
1030
1031         /*if(lib && lib->lib)
1032                 glAttachObjectARB(shader->object, lib->lib);*/
1033
1034         glLinkProgramARB(shader->object);
1035         glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status);
1036         if (!status) {
1037                 glGetInfoLogARB(shader->object, sizeof(log), &length, log);
1038                 if (fragcode) shader_print_errors("linking", log, fragcode);
1039                 else if (vertexcode) shader_print_errors("linking", log, vertexcode);
1040                 else if (libcode) shader_print_errors("linking", log, libcode);
1041
1042                 GPU_shader_free(shader);
1043                 return NULL;
1044         }
1045
1046         return shader;
1047 }
1048
1049 #if 0
1050 GPUShader *GPU_shader_create_lib(const char *code)
1051 {
1052         GLint status;
1053         GLcharARB log[5000];
1054         GLsizei length = 0;
1055         GPUShader *shader;
1056
1057         if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
1058                 return NULL;
1059
1060         shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
1061
1062         shader->lib = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
1063
1064         if (!shader->lib) {
1065                 fprintf(stderr, "GPUShader, object creation failed.\n");
1066                 GPU_shader_free(shader);
1067                 return NULL;
1068         }
1069
1070         glShaderSourceARB(shader->lib, 1, (const char**)&code, NULL);
1071
1072         glCompileShaderARB(shader->lib);
1073         glGetObjectParameterivARB(shader->lib, GL_OBJECT_COMPILE_STATUS_ARB, &status);
1074
1075         if (!status) {
1076                 glGetInfoLogARB(shader->lib, sizeof(log), &length, log);
1077                 shader_print_errors("compile", log, code);
1078
1079                 GPU_shader_free(shader);
1080                 return NULL;
1081         }
1082
1083         return shader;
1084 }
1085 #endif
1086
1087 void GPU_shader_bind(GPUShader *shader)
1088 {
1089         GPU_print_error("Pre Shader Bind");
1090         glUseProgramObjectARB(shader->object);
1091         GPU_print_error("Post Shader Bind");
1092 }
1093
1094 void GPU_shader_unbind(GPUShader *UNUSED(shader))
1095 {
1096         GPU_print_error("Pre Shader Unbind");
1097         glUseProgramObjectARB(0);
1098         GPU_print_error("Post Shader Unbind");
1099 }
1100
1101 void GPU_shader_free(GPUShader *shader)
1102 {
1103         if (shader->lib)
1104                 glDeleteObjectARB(shader->lib);
1105         if (shader->vertex)
1106                 glDeleteObjectARB(shader->vertex);
1107         if (shader->fragment)
1108                 glDeleteObjectARB(shader->fragment);
1109         if (shader->object)
1110                 glDeleteObjectARB(shader->object);
1111         MEM_freeN(shader);
1112 }
1113
1114 int GPU_shader_get_uniform(GPUShader *shader, const char *name)
1115 {
1116         return glGetUniformLocationARB(shader->object, name);
1117 }
1118
1119 void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, float *value)
1120 {
1121         if(location == -1)
1122                 return;
1123
1124         GPU_print_error("Pre Uniform Vector");
1125
1126         if (length == 1) glUniform1fvARB(location, arraysize, value);
1127         else if (length == 2) glUniform2fvARB(location, arraysize, value);
1128         else if (length == 3) glUniform3fvARB(location, arraysize, value);
1129         else if (length == 4) glUniform4fvARB(location, arraysize, value);
1130         else if (length == 9) glUniformMatrix3fvARB(location, arraysize, 0, value);
1131         else if (length == 16) glUniformMatrix4fvARB(location, arraysize, 0, value);
1132
1133         GPU_print_error("Post Uniform Vector");
1134 }
1135
1136 void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
1137 {
1138         GLenum arbnumber;
1139
1140         if (tex->number >= GG.maxtextures) {
1141                 GPU_print_error("Not enough texture slots.");
1142                 return;
1143         }
1144                 
1145         if(tex->number == -1)
1146                 return;
1147
1148         if(location == -1)
1149                 return;
1150
1151         GPU_print_error("Pre Uniform Texture");
1152
1153         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
1154
1155         if (tex->number != 0) glActiveTextureARB(arbnumber);
1156         glBindTexture(tex->target, tex->bindcode);
1157         glUniform1iARB(location, tex->number);
1158         glEnable(tex->target);
1159         if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
1160
1161         GPU_print_error("Post Uniform Texture");
1162 }
1163
1164 int GPU_shader_get_attribute(GPUShader *shader, char *name)
1165 {
1166         int index;
1167         
1168         GPU_print_error("Pre Get Attribute");
1169
1170         index = glGetAttribLocationARB(shader->object, name);
1171
1172         GPU_print_error("Post Get Attribute");
1173
1174         return index;
1175 }
1176
1177 #if 0
1178 /* GPUPixelBuffer */
1179
1180 typedef struct GPUPixelBuffer {
1181         GLuint bindcode[2];
1182         GLuint current;
1183         int datasize;
1184         int numbuffers;
1185         int halffloat;
1186 } GPUPixelBuffer;
1187
1188 void GPU_pixelbuffer_free(GPUPixelBuffer *pb)
1189 {
1190         if (pb->bindcode[0])
1191                 glDeleteBuffersARB(pb->numbuffers, pb->bindcode);
1192         MEM_freeN(pb);
1193 }
1194
1195 GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffers)
1196 {
1197         GPUPixelBuffer *pb;
1198
1199         if (!GLEW_ARB_multitexture || !GLEW_EXT_pixel_buffer_object)
1200                 return NULL;
1201         
1202         pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO");
1203         pb->datasize = x*y*4*((halffloat)? 16: 8);
1204         pb->numbuffers = numbuffers;
1205         pb->halffloat = halffloat;
1206
1207            glGenBuffersARB(pb->numbuffers, pb->bindcode);
1208
1209         if (!pb->bindcode[0]) {
1210                 fprintf(stderr, "GPUPixelBuffer allocation failed\n");
1211                 GPU_pixelbuffer_free(pb);
1212                 return NULL;
1213         }
1214
1215         return pb;
1216 }
1217
1218 void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb)
1219 {
1220         void *pixels;
1221         int i;
1222
1223         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
1224  
1225          for (i = 0; i < pb->numbuffers; i++) {
1226                 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->bindcode[pb->current]);
1227                 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->datasize, NULL,
1228                         GL_STREAM_DRAW_ARB);
1229     
1230                 pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
1231                 /*memcpy(pixels, _oImage.data(), pb->datasize);*/
1232     
1233                 if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
1234                         fprintf(stderr, "Could not unmap opengl PBO\n");
1235                         break;
1236                 }
1237         }
1238
1239         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
1240 }
1241
1242 static int pixelbuffer_map_into_gpu(GLuint bindcode)
1243 {
1244         void *pixels;
1245
1246         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
1247         pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
1248
1249         /* do stuff in pixels */
1250
1251         if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
1252                 fprintf(stderr, "Could not unmap opengl PBO\n");
1253                 return 0;
1254         }
1255         
1256         return 1;
1257 }
1258
1259 static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLuint bindcode)
1260 {
1261         GLenum type = (pb->halffloat)? GL_HALF_FLOAT_NV: GL_UNSIGNED_BYTE;
1262         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
1263         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
1264
1265         glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h,
1266                                         GL_RGBA, type, NULL);
1267
1268         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
1269         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
1270 }
1271
1272 void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb)
1273 {
1274         int newbuffer;
1275
1276         if (pb->numbuffers == 1) {
1277                 pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[0]);
1278                 pixelbuffer_map_into_gpu(pb->bindcode[0]);
1279         }
1280         else {
1281                 pb->current = (pb->current+1)%pb->numbuffers;
1282                 newbuffer = (pb->current+1)%pb->numbuffers;
1283
1284                 pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]);
1285                 pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]);
1286         }
1287 }
1288 #endif
1289