fix for warnings & detecting opensource nouveau drivers.
[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 #include "GL/glew.h"
34
35 #include "DNA_image_types.h"
36
37 #include "MEM_guardedalloc.h"
38
39 #include "BKE_global.h"
40 #include "BKE_utildefines.h"
41
42
43 #include "BLI_blenlib.h"
44
45 #include "GPU_draw.h"
46 #include "GPU_extensions.h"
47
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <string.h>
51
52 /* Extensions support */
53
54 /* extensions used:
55         - texture border clamp: 1.3 core
56         - fragement shader: 2.0 core
57         - framebuffer object: ext specification
58         - multitexture 1.3 core
59         - arb non power of two: 2.0 core
60         - pixel buffer objects? 2.1 core
61         - arb draw buffers? 2.0 core
62 */
63
64 static struct GPUGlobal {
65         GLint maxtextures;
66         GLuint currentfb;
67         int glslsupport;
68         int extdisabled;
69         int colordepth;
70         GPUDeviceType device;
71         GPUOSType os;
72         GPUDriverType driver;
73 } GG = {1, 0, 0, 0};
74
75 /* GPU Types */
76
77 int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
78 {
79         return (GG.device & device) && (GG.os & os) && (GG.driver & driver);
80 }
81
82 /* GPU Extensions */
83
84 void GPU_extensions_disable()
85 {
86         GG.extdisabled = 1;
87 }
88
89 void GPU_extensions_init()
90 {
91         GLint r, g, b;
92         const char *vendor, *renderer;
93
94         /* can't avoid calling this multiple times, see wm_window_add_ghostwindow */    
95         static char init= 0;
96         if(init) return;
97         init= 1;
98
99         glewInit();
100
101         /* glewIsSupported("GL_VERSION_2_0") */
102
103         if (GLEW_ARB_multitexture)
104                 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &GG.maxtextures);
105
106         GG.glslsupport = 1;
107         if (!GLEW_ARB_multitexture) GG.glslsupport = 0;
108         if (!GLEW_ARB_vertex_shader) GG.glslsupport = 0;
109         if (!GLEW_ARB_fragment_shader) GG.glslsupport = 0;
110
111         glGetIntegerv(GL_RED_BITS, &r);
112         glGetIntegerv(GL_GREEN_BITS, &g);
113         glGetIntegerv(GL_BLUE_BITS, &b);
114     GG.colordepth = r+g+b; /* assumes same depth for RGB */
115     
116         vendor = (const char*)glGetString(GL_VENDOR);
117         renderer = (const char*)glGetString(GL_RENDERER);
118
119         if(strstr(vendor, "ATI")) {
120                 GG.device = GPU_DEVICE_ATI;
121                 GG.driver = GPU_DRIVER_OFFICIAL;
122         }
123         else if(strstr(vendor, "NVIDIA")) {
124                 GG.device = GPU_DEVICE_NVIDIA;
125                 GG.driver = GPU_DRIVER_OFFICIAL;
126         }
127         else if(strstr(vendor, "Intel") ||
128                 /* src/mesa/drivers/dri/intel/intel_context.c */
129                 strstr(renderer, "Mesa DRI Intel") ||
130                 strstr(renderer, "Mesa DRI Mobile Intel")) {
131                 GG.device = GPU_DEVICE_INTEL;
132                 GG.driver = GPU_DRIVER_OFFICIAL;
133         }
134         else if(strstr(renderer, "Mesa DRI R")) {
135                 GG.device = GPU_DEVICE_ATI;
136                 GG.driver = GPU_DRIVER_OPENSOURCE;
137         }
138         else if(strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) {
139                 GG.device = GPU_DEVICE_NVIDIA;
140                 GG.driver = GPU_DRIVER_OPENSOURCE;
141         }
142         else if(strstr(vendor, "Mesa")) {
143                 GG.device = GPU_DEVICE_SOFTWARE;
144                 GG.driver = GPU_DRIVER_SOFTWARE;
145         }
146         else if(strstr(vendor, "Microsoft")) {
147                 GG.device = GPU_DEVICE_SOFTWARE;
148                 GG.driver = GPU_DRIVER_SOFTWARE;
149         }
150         else if(strstr(renderer, "Apple Software Renderer")) {
151                 GG.device = GPU_DEVICE_SOFTWARE;
152                 GG.driver = GPU_DRIVER_SOFTWARE;
153         }
154         else {
155                 GG.device = GPU_DEVICE_ANY;
156                 GG.driver = GPU_DRIVER_ANY;
157         }
158
159         GG.os = GPU_OS_UNIX;
160 #ifdef _WIN32
161         GG.os = GPU_OS_WIN;
162 #endif
163 #ifdef __APPLE__
164         GG.os = GPU_OS_MAC;
165 #endif
166 }
167
168 int GPU_glsl_support()
169 {
170         return !GG.extdisabled && GG.glslsupport;
171 }
172
173 int GPU_non_power_of_two_support()
174 {
175         /* Exception for buggy ATI/Apple driver in Mac OS X 10.5/10.6,
176          * they claim to support this but can cause system freeze */
177         if(GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_MAC, GPU_DRIVER_OFFICIAL))
178                 return 0;
179
180         return GLEW_ARB_texture_non_power_of_two;
181 }
182
183 int GPU_color_depth()
184 {
185     return GG.colordepth;
186 }
187
188 int GPU_print_error(char *str)
189 {
190         GLenum errCode;
191
192         if (G.f & G_DEBUG) {
193                 if ((errCode = glGetError()) != GL_NO_ERROR) {
194                         fprintf(stderr, "%s opengl error: %s\n", str, gluErrorString(errCode));
195                         return 1;
196                 }
197         }
198
199         return 0;
200 }
201
202 static void GPU_print_framebuffer_error(GLenum status)
203 {
204         fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d\n",
205                 (int)status);
206
207         switch(status) {
208                 case GL_FRAMEBUFFER_COMPLETE_EXT:
209                         break;
210                 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
211                         fprintf(stderr, "Incomplete attachment.\n");
212                         break;
213                 case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
214                         fprintf(stderr, "Unsupported framebuffer format.\n");
215                         break;
216                 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
217                         fprintf(stderr, "Missing attachment.\n");
218                         break;
219                 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
220                         fprintf(stderr, "Attached images must have same dimensions.\n");
221                         break;
222                 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
223                          fprintf(stderr, "Attached images must have same format.\n");
224                         break;
225                 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
226                         fprintf(stderr, "Missing draw buffer.\n");
227                         break;
228                 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
229                         fprintf(stderr, "Missing read buffer.\n");
230                         break;
231                 default:
232                         fprintf(stderr, "Unknown.\n");
233                         break;
234         }
235 }
236
237 /* GPUTexture */
238
239 struct GPUTexture {
240         int w, h;                               /* width/height */
241         int number;                             /* number for multitexture binding */
242         int refcount;                   /* reference count */
243         GLenum target;                  /* GL_TEXTURE_* */
244         GLuint bindcode;                /* opengl identifier for texture */
245         int fromblender;                /* we got the texture from Blender */
246
247         GPUFrameBuffer *fb;             /* GPUFramebuffer this texture is attached to */
248         int depth;                              /* is a depth texture? */
249 };
250
251 static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels)
252 {
253         unsigned char *pixels, *p;
254         float *fp;
255         int a, len;
256
257         len = 4*length;
258         fp = fpixels;
259         p = pixels = MEM_callocN(sizeof(unsigned char)*len, "GPUTexturePixels");
260
261         for (a=0; a<len; a++, p++, fp++)
262                 *p = FTOCHAR((*fp));
263
264         return pixels;
265 }
266
267 static int is_pow2(int n)
268 {
269         return ((n)&(n-1))==0;
270 }
271
272 static int larger_pow2(int n)
273 {
274         if (is_pow2(n))
275                 return n;
276
277         while(!is_pow2(n))
278                 n= n&(n-1);
279
280         return n*2;
281 }
282
283 static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
284 {
285         void *pixels = MEM_callocN(sizeof(char)*4*w*h, "GPUTextureEmptyPixels");
286
287         if (target == GL_TEXTURE_1D)
288                 glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels);
289         else
290                 glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
291         
292         MEM_freeN(pixels);
293 }
294
295 static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, int depth)
296 {
297         GPUTexture *tex;
298         GLenum type, format, internalformat;
299         void *pixels = NULL;
300
301         if(depth && !GLEW_ARB_depth_texture)
302                 return NULL;
303
304         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
305         tex->w = w;
306         tex->h = h;
307         tex->number = -1;
308         tex->refcount = 1;
309         tex->target = (n == 1)? GL_TEXTURE_1D: GL_TEXTURE_2D;
310         tex->depth = depth;
311
312         glGenTextures(1, &tex->bindcode);
313
314         if (!tex->bindcode) {
315                 fprintf(stderr, "GPUTexture: texture create failed: %d\n",
316                         (int)glGetError());
317                 GPU_texture_free(tex);
318                 return NULL;
319         }
320
321         if (!GPU_non_power_of_two_support()) {
322                 tex->w = larger_pow2(tex->w);
323                 tex->h = larger_pow2(tex->h);
324         }
325
326         tex->number = 0;
327         glBindTexture(tex->target, tex->bindcode);
328
329         if(depth) {
330                 type = GL_UNSIGNED_BYTE;
331                 format = GL_DEPTH_COMPONENT;
332                 internalformat = GL_DEPTH_COMPONENT;
333         }
334         else {
335                 type = GL_UNSIGNED_BYTE;
336                 format = GL_RGBA;
337                 internalformat = GL_RGBA8;
338
339                 if (fpixels)
340                         pixels = GPU_texture_convert_pixels(w*h, fpixels);
341         }
342
343         if (tex->target == GL_TEXTURE_1D) {
344                 glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, 0);
345
346                 if (fpixels) {
347                         glTexSubImage1D(tex->target, 0, 0, w, format, type,
348                                 pixels? pixels: fpixels);
349
350                         if (tex->w > w)
351                                 GPU_glTexSubImageEmpty(tex->target, format, w, 0,
352                                         tex->w-w, 1);
353                 }
354         }
355         else {
356                 glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0,
357                         format, type, 0);
358
359                 if (fpixels) {
360                         glTexSubImage2D(tex->target, 0, 0, 0, w, h,
361                                 format, type, pixels? pixels: fpixels);
362
363                         if (tex->w > w)
364                                 GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w-w, tex->h);
365                         if (tex->h > h)
366                                 GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h-h);
367                 }
368         }
369
370         if (pixels)
371                 MEM_freeN(pixels);
372
373         if(depth) {
374                 glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
375                 glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
376                 glTexParameteri(tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
377                 glTexParameteri(tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
378                 glTexParameteri(tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);  
379         }
380         else {
381                 glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
382                 glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
383         }
384
385         if (tex->target != GL_TEXTURE_1D) {
386                 /* CLAMP_TO_BORDER is an OpenGL 1.3 core feature */
387                 GLenum wrapmode = (depth)? GL_CLAMP_TO_EDGE: GL_CLAMP_TO_BORDER;
388                 glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, wrapmode);
389                 glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, wrapmode);
390
391 #if 0
392                 float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
393                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); 
394 #endif
395         }
396         else
397                 glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
398
399         return tex;
400 }
401
402
403 GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels)
404 {
405         GPUTexture *tex;
406         GLenum type, format, internalformat;
407         void *pixels = NULL;
408         float vfBorderColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
409
410         if(!GLEW_VERSION_1_2)
411                 return NULL;
412
413         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
414         tex->w = w;
415         tex->h = h;
416         tex->depth = depth;
417         tex->number = -1;
418         tex->refcount = 1;
419         tex->target = GL_TEXTURE_3D;
420
421         glGenTextures(1, &tex->bindcode);
422
423         if (!tex->bindcode) {
424                 fprintf(stderr, "GPUTexture: texture create failed: %d\n",
425                         (int)glGetError());
426                 GPU_texture_free(tex);
427                 return NULL;
428         }
429
430         if (!GPU_non_power_of_two_support()) {
431                 tex->w = larger_pow2(tex->w);
432                 tex->h = larger_pow2(tex->h);
433                 tex->depth = larger_pow2(tex->depth);
434         }
435
436         tex->number = 0;
437         glBindTexture(tex->target, tex->bindcode);
438
439         GPU_print_error("3D glBindTexture");
440
441         type = GL_FLOAT; // GL_UNSIGNED_BYTE
442         format = GL_RED;
443         internalformat = GL_INTENSITY;
444
445         //if (fpixels)
446         //      pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
447
448         glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, 0);
449
450         GPU_print_error("3D glTexImage3D");
451
452         if (fpixels) {
453                 if(!GPU_non_power_of_two_support() && (w != tex->w || h != tex->h || depth != tex->depth)) {
454                         /* clear first to avoid unitialized pixels */
455                         float *zero= MEM_callocN(sizeof(float)*tex->w*tex->h*tex->depth, "zero");
456                         glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->depth, format, type, zero);
457                         MEM_freeN(zero);
458                 }
459
460                 glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels);
461                 GPU_print_error("3D glTexSubImage3D");
462         }
463
464
465         glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, vfBorderColor);
466         GPU_print_error("3D GL_TEXTURE_BORDER_COLOR");
467         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
468         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
469         GPU_print_error("3D GL_LINEAR");
470         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
471         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
472         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
473         GPU_print_error("3D GL_CLAMP_TO_BORDER");
474
475         if (pixels)
476                 MEM_freeN(pixels);
477
478         if (tex)
479                 GPU_texture_unbind(tex);
480
481         return tex;
482 }
483
484 GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, double time, int mipmap)
485 {
486         GPUTexture *tex;
487         GLint w, h, border, lastbindcode, bindcode;
488
489         glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode);
490
491         GPU_update_image_time(ima, time);
492         bindcode = GPU_verify_image(ima, iuser, 0, 0, mipmap);
493
494         if(ima->gputexture) {
495                 ima->gputexture->bindcode = bindcode;
496                 glBindTexture(GL_TEXTURE_2D, lastbindcode);
497                 return ima->gputexture;
498         }
499
500         if(!bindcode) {
501                 glBindTexture(GL_TEXTURE_2D, lastbindcode);
502                 return NULL;
503         }
504
505         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
506         tex->bindcode = bindcode;
507         tex->number = -1;
508         tex->refcount = 1;
509         tex->target = GL_TEXTURE_2D;
510         tex->fromblender = 1;
511
512         ima->gputexture= tex;
513
514         if (!glIsTexture(tex->bindcode)) {
515                 GPU_print_error("Blender Texture");
516         }
517         else {
518                 glBindTexture(GL_TEXTURE_2D, tex->bindcode);
519                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
520                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
521                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border);
522
523                 tex->w = w - border;
524                 tex->h = h - border;
525         }
526
527         glBindTexture(GL_TEXTURE_2D, lastbindcode);
528
529         return tex;
530 }
531
532 GPUTexture *GPU_texture_create_1D(int w, float *fpixels)
533 {
534         GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0);
535
536         if (tex)
537                 GPU_texture_unbind(tex);
538         
539         return tex;
540 }
541
542 GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels)
543 {
544         GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0);
545
546         if (tex)
547                 GPU_texture_unbind(tex);
548         
549         return tex;
550 }
551
552 GPUTexture *GPU_texture_create_depth(int w, int h)
553 {
554         GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1);
555
556         if (tex)
557                 GPU_texture_unbind(tex);
558         
559         return tex;
560 }
561
562 void GPU_texture_bind(GPUTexture *tex, int number)
563 {
564         GLenum arbnumber;
565
566         if (number >= GG.maxtextures) {
567                 GPU_print_error("Not enough texture slots.");
568                 return;
569         }
570
571         if(number == -1)
572                 return;
573
574         GPU_print_error("Pre Texture Bind");
575
576         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + number);
577         if (number != 0) glActiveTextureARB(arbnumber);
578         glBindTexture(tex->target, tex->bindcode);
579         glEnable(tex->target);
580         if (number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
581
582         tex->number = number;
583
584         GPU_print_error("Post Texture Bind");
585 }
586
587 void GPU_texture_unbind(GPUTexture *tex)
588 {
589         GLenum arbnumber;
590
591         if (tex->number >= GG.maxtextures) {
592                 GPU_print_error("Not enough texture slots.");
593                 return;
594         }
595
596         if(tex->number == -1)
597                 return;
598         
599         GPU_print_error("Pre Texture Unbind");
600
601         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
602         if (tex->number != 0) glActiveTextureARB(arbnumber);
603         glBindTexture(tex->target, 0);
604         glDisable(tex->target);
605         if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
606
607         tex->number = -1;
608
609         GPU_print_error("Post Texture Unbind");
610 }
611
612 void GPU_texture_free(GPUTexture *tex)
613 {
614         tex->refcount--;
615
616         if (tex->refcount < 0)
617                 fprintf(stderr, "GPUTexture: negative refcount\n");
618         
619         if (tex->refcount == 0) {
620                 if (tex->fb)
621                         GPU_framebuffer_texture_detach(tex->fb, tex);
622                 if (tex->bindcode && !tex->fromblender)
623                         glDeleteTextures(1, &tex->bindcode);
624
625                 MEM_freeN(tex);
626         }
627 }
628
629 void GPU_texture_ref(GPUTexture *tex)
630 {
631         tex->refcount++;
632 }
633
634 int GPU_texture_target(GPUTexture *tex)
635 {
636         return tex->target;
637 }
638
639 int GPU_texture_opengl_width(GPUTexture *tex)
640 {
641         return tex->w;
642 }
643
644 int GPU_texture_opengl_height(GPUTexture *tex)
645 {
646         return tex->h;
647 }
648
649 GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex)
650 {
651         return tex->fb;
652 }
653
654 /* GPUFrameBuffer */
655
656 struct GPUFrameBuffer {
657         GLuint object;
658         GPUTexture *colortex;
659         GPUTexture *depthtex;
660 };
661
662 GPUFrameBuffer *GPU_framebuffer_create()
663 {
664         GPUFrameBuffer *fb;
665
666         if (!GLEW_EXT_framebuffer_object)
667                 return NULL;
668         
669         fb= MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
670         glGenFramebuffersEXT(1, &fb->object);
671
672         if (!fb->object) {
673                 fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
674                         (int)glGetError());
675                 GPU_framebuffer_free(fb);
676                 return NULL;
677         }
678
679         return fb;
680 }
681
682 int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex)
683 {
684         GLenum status;
685         GLenum attachment;
686
687         if(tex->depth)
688                 attachment = GL_DEPTH_ATTACHMENT_EXT;
689         else
690                 attachment = GL_COLOR_ATTACHMENT0_EXT;
691
692         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
693         GG.currentfb = fb->object;
694
695         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, 
696                 tex->target, tex->bindcode, 0);
697
698         if(tex->depth) {
699                 glDrawBuffer(GL_NONE);
700                 glReadBuffer(GL_NONE);
701         }
702         else {
703                 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
704                 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
705         }
706
707         status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
708
709         if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
710                 GPU_framebuffer_restore();
711                 GPU_print_framebuffer_error(status);
712                 return 0;
713         }
714
715         if(tex->depth)
716                 fb->depthtex = tex;
717         else
718                 fb->colortex = tex;
719
720         tex->fb= fb;
721
722         return 1;
723 }
724
725 void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
726 {
727         GLenum attachment;
728
729         if(!tex->fb)
730                 return;
731
732         if(GG.currentfb != tex->fb->object) {
733                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
734                 GG.currentfb = tex->fb->object;
735         }
736
737         if(tex->depth) {
738                 fb->depthtex = NULL;
739                 attachment = GL_DEPTH_ATTACHMENT_EXT;
740         }
741         else {
742                 fb->colortex = NULL;
743                 attachment = GL_COLOR_ATTACHMENT0_EXT;
744         }
745
746         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
747                 tex->target, 0, 0);
748
749         tex->fb = NULL;
750 }
751
752 void GPU_framebuffer_texture_bind(GPUFrameBuffer *UNUSED(fb), GPUTexture *tex)
753 {
754         /* push attributes */
755         glPushAttrib(GL_ENABLE_BIT);
756         glPushAttrib(GL_VIEWPORT_BIT);
757         glDisable(GL_SCISSOR_TEST);
758
759         /* bind framebuffer */
760         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
761
762         /* push matrices and set default viewport and matrix */
763         glViewport(0, 0, tex->w, tex->h);
764         GG.currentfb = tex->fb->object;
765
766         glMatrixMode(GL_PROJECTION);
767         glPushMatrix();
768         glLoadIdentity();
769         glMatrixMode(GL_MODELVIEW);
770         glPushMatrix();
771         glLoadIdentity();
772 }
773
774 void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
775 {
776         /* restore matrix */
777         glMatrixMode(GL_PROJECTION);
778         glPopMatrix();
779         glMatrixMode(GL_MODELVIEW);
780         glPopMatrix();
781
782         /* restore attributes */
783         glPopAttrib();
784         glPopAttrib();
785         glEnable(GL_SCISSOR_TEST);
786 }
787
788 void GPU_framebuffer_free(GPUFrameBuffer *fb)
789 {
790         if(fb->depthtex)
791                 GPU_framebuffer_texture_detach(fb, fb->depthtex);
792         if(fb->colortex)
793                 GPU_framebuffer_texture_detach(fb, fb->colortex);
794
795         if(fb->object) {
796                 glDeleteFramebuffersEXT(1, &fb->object);
797
798                 if (GG.currentfb == fb->object) {
799                         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
800                         GG.currentfb = 0;
801                 }
802         }
803
804         MEM_freeN(fb);
805 }
806
807 void GPU_framebuffer_restore()
808 {
809         if (GG.currentfb != 0) {
810                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
811                 GG.currentfb = 0;
812         }
813 }
814
815 /* GPUOffScreen */
816
817 struct GPUOffScreen {
818         GPUFrameBuffer *fb;
819         GPUTexture *color;
820         GPUTexture *depth;
821 };
822
823 GPUOffScreen *GPU_offscreen_create(int width, int height)
824 {
825         GPUOffScreen *ofs;
826
827         ofs= MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
828
829         ofs->fb = GPU_framebuffer_create();
830         if(!ofs->fb) {
831                 GPU_offscreen_free(ofs);
832                 return NULL;
833         }
834
835         ofs->depth = GPU_texture_create_depth(width, height);
836         if(!ofs->depth) {
837                 GPU_offscreen_free(ofs);
838                 return NULL;
839         }
840
841         if(!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth)) {
842                 GPU_offscreen_free(ofs);
843                 return NULL;
844         }
845
846         ofs->color = GPU_texture_create_2D(width, height, NULL);
847         if(!ofs->color) {
848                 GPU_offscreen_free(ofs);
849                 return NULL;
850         }
851
852         if(!GPU_framebuffer_texture_attach(ofs->fb, ofs->color)) {
853                 GPU_offscreen_free(ofs);
854                 return NULL;
855         }
856
857         GPU_framebuffer_restore();
858
859         return ofs;
860 }
861
862 void GPU_offscreen_free(GPUOffScreen *ofs)
863 {
864         if(ofs->fb)
865                 GPU_framebuffer_free(ofs->fb);
866         if(ofs->color)
867                 GPU_texture_free(ofs->color);
868         if(ofs->depth)
869                 GPU_texture_free(ofs->depth);
870         
871         MEM_freeN(ofs);
872 }
873
874 void GPU_offscreen_bind(GPUOffScreen *ofs)
875 {
876         glDisable(GL_SCISSOR_TEST);
877         GPU_framebuffer_texture_bind(ofs->fb, ofs->color);
878 }
879
880 void GPU_offscreen_unbind(GPUOffScreen *ofs)
881 {
882         GPU_framebuffer_texture_unbind(ofs->fb, ofs->color);
883         GPU_framebuffer_restore();
884         glEnable(GL_SCISSOR_TEST);
885 }
886
887 /* GPUShader */
888
889 struct GPUShader {
890         GLhandleARB object;             /* handle for full shader */
891         GLhandleARB vertex;             /* handle for vertex shader */
892         GLhandleARB fragment;   /* handle for fragment shader */
893         GLhandleARB lib;                /* handle for libment shader */
894         int totattrib;                  /* total number of attributes */
895 };
896
897 static void shader_print_errors(char *task, char *log, const char *code)
898 {
899         const char *c, *pos, *end = code + strlen(code);
900         int line = 1;
901
902         fprintf(stderr, "GPUShader: %s error:\n", task);
903
904         if(G.f & G_DEBUG) {
905                 c = code;
906                 while ((c < end) && (pos = strchr(c, '\n'))) {
907                         fprintf(stderr, "%2d  ", line);
908                         fwrite(c, (pos+1)-c, 1, stderr);
909                         c = pos+1;
910                         line++;
911                 }
912
913                 fprintf(stderr, "%s", c);
914         }
915
916         fprintf(stderr, "%s\n", log);
917 }
918
919 GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPUShader *lib,*/ const char *libcode)
920 {
921         GLint status;
922         GLcharARB log[5000];
923         const char *fragsource[2];
924         GLsizei length = 0;
925         GLint count;
926         GPUShader *shader;
927
928         if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
929                 return NULL;
930
931         shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
932
933         if(vertexcode)
934                 shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
935         if(fragcode)
936                 shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
937         shader->object = glCreateProgramObjectARB();
938
939         if (!shader->object ||
940                 (vertexcode && !shader->vertex) ||
941                 (fragcode && !shader->fragment)) {
942                 fprintf(stderr, "GPUShader, object creation failed.\n");
943                 GPU_shader_free(shader);
944                 return NULL;
945         }
946
947         if(vertexcode) {
948                 glAttachObjectARB(shader->object, shader->vertex);
949                 glShaderSourceARB(shader->vertex, 1, (const char**)&vertexcode, NULL);
950
951                 glCompileShaderARB(shader->vertex);
952                 glGetObjectParameterivARB(shader->vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status);
953
954                 if (!status) {
955                         glGetInfoLogARB(shader->vertex, sizeof(log), &length, log);
956                         shader_print_errors("compile", log, vertexcode);
957
958                         GPU_shader_free(shader);
959                         return NULL;
960                 }
961         }
962
963         if(fragcode) {
964                 count = 0;
965                 if(libcode) fragsource[count++] = libcode;
966                 if(fragcode) fragsource[count++] = fragcode;
967
968                 glAttachObjectARB(shader->object, shader->fragment);
969                 glShaderSourceARB(shader->fragment, count, fragsource, NULL);
970
971                 glCompileShaderARB(shader->fragment);
972                 glGetObjectParameterivARB(shader->fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status);
973
974                 if (!status) {
975                         glGetInfoLogARB(shader->fragment, sizeof(log), &length, log);
976                         shader_print_errors("compile", log, fragcode);
977
978                         GPU_shader_free(shader);
979                         return NULL;
980                 }
981         }
982
983         /*if(lib && lib->lib)
984                 glAttachObjectARB(shader->object, lib->lib);*/
985
986         glLinkProgramARB(shader->object);
987         glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status);
988         if (!status) {
989                 glGetInfoLogARB(shader->object, sizeof(log), &length, log);
990                 if (fragcode) shader_print_errors("linking", log, fragcode);
991                 else if (vertexcode) shader_print_errors("linking", log, vertexcode);
992                 else if (libcode) shader_print_errors("linking", log, libcode);
993
994                 GPU_shader_free(shader);
995                 return NULL;
996         }
997
998         return shader;
999 }
1000
1001 #if 0
1002 GPUShader *GPU_shader_create_lib(const char *code)
1003 {
1004         GLint status;
1005         GLcharARB log[5000];
1006         GLsizei length = 0;
1007         GPUShader *shader;
1008
1009         if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
1010                 return NULL;
1011
1012         shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
1013
1014         shader->lib = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
1015
1016         if (!shader->lib) {
1017                 fprintf(stderr, "GPUShader, object creation failed.\n");
1018                 GPU_shader_free(shader);
1019                 return NULL;
1020         }
1021
1022         glShaderSourceARB(shader->lib, 1, (const char**)&code, NULL);
1023
1024         glCompileShaderARB(shader->lib);
1025         glGetObjectParameterivARB(shader->lib, GL_OBJECT_COMPILE_STATUS_ARB, &status);
1026
1027         if (!status) {
1028                 glGetInfoLogARB(shader->lib, sizeof(log), &length, log);
1029                 shader_print_errors("compile", log, code);
1030
1031                 GPU_shader_free(shader);
1032                 return NULL;
1033         }
1034
1035         return shader;
1036 }
1037 #endif
1038
1039 void GPU_shader_bind(GPUShader *shader)
1040 {
1041         GPU_print_error("Pre Shader Bind");
1042         glUseProgramObjectARB(shader->object);
1043         GPU_print_error("Post Shader Bind");
1044 }
1045
1046 void GPU_shader_unbind()
1047 {
1048         GPU_print_error("Pre Shader Unbind");
1049         glUseProgramObjectARB(0);
1050         GPU_print_error("Post Shader Unbind");
1051 }
1052
1053 void GPU_shader_free(GPUShader *shader)
1054 {
1055         if (shader->lib)
1056                 glDeleteObjectARB(shader->lib);
1057         if (shader->vertex)
1058                 glDeleteObjectARB(shader->vertex);
1059         if (shader->fragment)
1060                 glDeleteObjectARB(shader->fragment);
1061         if (shader->object)
1062                 glDeleteObjectARB(shader->object);
1063         MEM_freeN(shader);
1064 }
1065
1066 int GPU_shader_get_uniform(GPUShader *shader, char *name)
1067 {
1068         return glGetUniformLocationARB(shader->object, name);
1069 }
1070
1071 void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, float *value)
1072 {
1073         if(location == -1)
1074                 return;
1075
1076         GPU_print_error("Pre Uniform Vector");
1077
1078         if (length == 1) glUniform1fvARB(location, arraysize, value);
1079         else if (length == 2) glUniform2fvARB(location, arraysize, value);
1080         else if (length == 3) glUniform3fvARB(location, arraysize, value);
1081         else if (length == 4) glUniform4fvARB(location, arraysize, value);
1082         else if (length == 9) glUniformMatrix3fvARB(location, arraysize, 0, value);
1083         else if (length == 16) glUniformMatrix4fvARB(location, arraysize, 0, value);
1084
1085         GPU_print_error("Post Uniform Vector");
1086 }
1087
1088 void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
1089 {
1090         GLenum arbnumber;
1091
1092         if (tex->number >= GG.maxtextures) {
1093                 GPU_print_error("Not enough texture slots.");
1094                 return;
1095         }
1096                 
1097         if(tex->number == -1)
1098                 return;
1099
1100         if(location == -1)
1101                 return;
1102
1103         GPU_print_error("Pre Uniform Texture");
1104
1105         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
1106
1107         if (tex->number != 0) glActiveTextureARB(arbnumber);
1108         glBindTexture(tex->target, tex->bindcode);
1109         glUniform1iARB(location, tex->number);
1110         glEnable(tex->target);
1111         if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
1112
1113         GPU_print_error("Post Uniform Texture");
1114 }
1115
1116 int GPU_shader_get_attribute(GPUShader *shader, char *name)
1117 {
1118         int index;
1119         
1120         GPU_print_error("Pre Get Attribute");
1121
1122         index = glGetAttribLocationARB(shader->object, name);
1123
1124         GPU_print_error("Post Get Attribute");
1125
1126         return index;
1127 }
1128
1129 #if 0
1130 /* GPUPixelBuffer */
1131
1132 typedef struct GPUPixelBuffer {
1133         GLuint bindcode[2];
1134         GLuint current;
1135         int datasize;
1136         int numbuffers;
1137         int halffloat;
1138 } GPUPixelBuffer;
1139
1140 void GPU_pixelbuffer_free(GPUPixelBuffer *pb)
1141 {
1142         if (pb->bindcode[0])
1143                 glDeleteBuffersARB(pb->numbuffers, pb->bindcode);
1144         MEM_freeN(pb);
1145 }
1146
1147 GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffers)
1148 {
1149         GPUPixelBuffer *pb;
1150
1151         if (!GLEW_ARB_multitexture || !GLEW_EXT_pixel_buffer_object)
1152                 return NULL;
1153         
1154         pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO");
1155         pb->datasize = x*y*4*((halffloat)? 16: 8);
1156         pb->numbuffers = numbuffers;
1157         pb->halffloat = halffloat;
1158
1159            glGenBuffersARB(pb->numbuffers, pb->bindcode);
1160
1161         if (!pb->bindcode[0]) {
1162                 fprintf(stderr, "GPUPixelBuffer allocation failed\n");
1163                 GPU_pixelbuffer_free(pb);
1164                 return NULL;
1165         }
1166
1167         return pb;
1168 }
1169
1170 void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb)
1171 {
1172         void *pixels;
1173         int i;
1174
1175         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
1176  
1177          for (i = 0; i < pb->numbuffers; i++) {
1178                 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->bindcode[pb->current]);
1179                 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->datasize, NULL,
1180                         GL_STREAM_DRAW_ARB);
1181     
1182                 pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
1183                 /*memcpy(pixels, _oImage.data(), pb->datasize);*/
1184     
1185                 if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
1186                         fprintf(stderr, "Could not unmap opengl PBO\n");
1187                         break;
1188                 }
1189         }
1190
1191         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
1192 }
1193
1194 static int pixelbuffer_map_into_gpu(GLuint bindcode)
1195 {
1196         void *pixels;
1197
1198         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
1199         pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
1200
1201         /* do stuff in pixels */
1202
1203         if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
1204                 fprintf(stderr, "Could not unmap opengl PBO\n");
1205                 return 0;
1206         }
1207         
1208         return 1;
1209 }
1210
1211 static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLuint bindcode)
1212 {
1213         GLenum type = (pb->halffloat)? GL_HALF_FLOAT_NV: GL_UNSIGNED_BYTE;
1214         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
1215         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
1216
1217         glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h,
1218                                         GL_RGBA, type, NULL);
1219
1220         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
1221         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
1222 }
1223
1224 void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb)
1225 {
1226         int newbuffer;
1227
1228         if (pb->numbuffers == 1) {
1229                 pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[0]);
1230                 pixelbuffer_map_into_gpu(pb->bindcode[0]);
1231         }
1232         else {
1233                 pb->current = (pb->current+1)%pb->numbuffers;
1234                 newbuffer = (pb->current+1)%pb->numbuffers;
1235
1236                 pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]);
1237                 pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]);
1238         }
1239 }
1240 #endif
1241