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