converted more mixed tab/space indentations to tabs. only whitespace changes.
[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 /** \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                 BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'",
262                         (int)status, err);
263         }
264         else {
265                 fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n",
266                         (int)status, err);
267         }
268 }
269
270 /* GPUTexture */
271
272 struct GPUTexture {
273         int w, h;                               /* width/height */
274         int number;                             /* number for multitexture binding */
275         int refcount;                   /* reference count */
276         GLenum target;                  /* GL_TEXTURE_* */
277         GLuint bindcode;                /* opengl identifier for texture */
278         int fromblender;                /* we got the texture from Blender */
279
280         GPUFrameBuffer *fb;             /* GPUFramebuffer this texture is attached to */
281         int depth;                              /* is a depth texture? */
282 };
283
284 static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels)
285 {
286         unsigned char *pixels, *p;
287         float *fp;
288         int a, len;
289
290         len = 4*length;
291         fp = fpixels;
292         p = pixels = MEM_callocN(sizeof(unsigned char)*len, "GPUTexturePixels");
293
294         for (a=0; a<len; a++, p++, fp++)
295                 *p = FTOCHAR((*fp));
296
297         return pixels;
298 }
299
300 static int is_pow2(int n)
301 {
302         return ((n)&(n-1))==0;
303 }
304
305 static int larger_pow2(int n)
306 {
307         if (is_pow2(n))
308                 return n;
309
310         while(!is_pow2(n))
311                 n= n&(n-1);
312
313         return n*2;
314 }
315
316 static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
317 {
318         void *pixels = MEM_callocN(sizeof(char)*4*w*h, "GPUTextureEmptyPixels");
319
320         if (target == GL_TEXTURE_1D)
321                 glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels);
322         else
323                 glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
324         
325         MEM_freeN(pixels);
326 }
327
328 static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, int depth, char err_out[256])
329 {
330         GPUTexture *tex;
331         GLenum type, format, internalformat;
332         void *pixels = NULL;
333
334         if(depth && !GLEW_ARB_depth_texture)
335                 return NULL;
336
337         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
338         tex->w = w;
339         tex->h = h;
340         tex->number = -1;
341         tex->refcount = 1;
342         tex->target = (n == 1)? GL_TEXTURE_1D: GL_TEXTURE_2D;
343         tex->depth = depth;
344
345         glGenTextures(1, &tex->bindcode);
346
347         if (!tex->bindcode) {
348                 if(err_out) {
349                         BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d",
350                                 (int)glGetError());
351                 }
352                 else {
353                         fprintf(stderr, "GPUTexture: texture create failed: %d\n",
354                                 (int)glGetError());
355                 }
356                 GPU_texture_free(tex);
357                 return NULL;
358         }
359
360         if (!GPU_non_power_of_two_support()) {
361                 tex->w = larger_pow2(tex->w);
362                 tex->h = larger_pow2(tex->h);
363         }
364
365         tex->number = 0;
366         glBindTexture(tex->target, tex->bindcode);
367
368         if(depth) {
369                 type = GL_UNSIGNED_BYTE;
370                 format = GL_DEPTH_COMPONENT;
371                 internalformat = GL_DEPTH_COMPONENT;
372         }
373         else {
374                 type = GL_UNSIGNED_BYTE;
375                 format = GL_RGBA;
376                 internalformat = GL_RGBA8;
377
378                 if (fpixels)
379                         pixels = GPU_texture_convert_pixels(w*h, fpixels);
380         }
381
382         if (tex->target == GL_TEXTURE_1D) {
383                 glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL);
384
385                 if (fpixels) {
386                         glTexSubImage1D(tex->target, 0, 0, w, format, type,
387                                 pixels? pixels: fpixels);
388
389                         if (tex->w > w)
390                                 GPU_glTexSubImageEmpty(tex->target, format, w, 0,
391                                         tex->w-w, 1);
392                 }
393         }
394         else {
395                 glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0,
396                         format, type, NULL);
397
398                 if (fpixels) {
399                         glTexSubImage2D(tex->target, 0, 0, 0, w, h,
400                                 format, type, pixels? pixels: fpixels);
401
402                         if (tex->w > w)
403                                 GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w-w, tex->h);
404                         if (tex->h > h)
405                                 GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h-h);
406                 }
407         }
408
409         if (pixels)
410                 MEM_freeN(pixels);
411
412         if(depth) {
413                 glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
414                 glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
415                 glTexParameteri(tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
416                 glTexParameteri(tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
417                 glTexParameteri(tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);  
418         }
419         else {
420                 glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
421                 glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
422         }
423
424         if (tex->target != GL_TEXTURE_1D) {
425                 /* CLAMP_TO_BORDER is an OpenGL 1.3 core feature */
426                 GLenum wrapmode = (depth)? GL_CLAMP_TO_EDGE: GL_CLAMP_TO_BORDER;
427                 glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, wrapmode);
428                 glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, wrapmode);
429
430 #if 0
431                 float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
432                 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); 
433 #endif
434         }
435         else
436                 glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
437
438         return tex;
439 }
440
441
442 GPUTexture *GPU_texture_create_3D(int w, int h, int depth, float *fpixels)
443 {
444         GPUTexture *tex;
445         GLenum type, format, internalformat;
446         void *pixels = NULL;
447         float vfBorderColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
448
449         if(!GLEW_VERSION_1_2)
450                 return NULL;
451
452         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
453         tex->w = w;
454         tex->h = h;
455         tex->depth = depth;
456         tex->number = -1;
457         tex->refcount = 1;
458         tex->target = GL_TEXTURE_3D;
459
460         glGenTextures(1, &tex->bindcode);
461
462         if (!tex->bindcode) {
463                 fprintf(stderr, "GPUTexture: texture create failed: %d\n",
464                         (int)glGetError());
465                 GPU_texture_free(tex);
466                 return NULL;
467         }
468
469         if (!GPU_non_power_of_two_support()) {
470                 tex->w = larger_pow2(tex->w);
471                 tex->h = larger_pow2(tex->h);
472                 tex->depth = larger_pow2(tex->depth);
473         }
474
475         tex->number = 0;
476         glBindTexture(tex->target, tex->bindcode);
477
478         GPU_print_error("3D glBindTexture");
479
480         type = GL_FLOAT; // GL_UNSIGNED_BYTE
481         format = GL_RED;
482         internalformat = GL_INTENSITY;
483
484         //if (fpixels)
485         //      pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
486
487         glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, 0);
488
489         GPU_print_error("3D glTexImage3D");
490
491         if (fpixels) {
492                 if(!GPU_non_power_of_two_support() && (w != tex->w || h != tex->h || depth != tex->depth)) {
493                         /* clear first to avoid unitialized pixels */
494                         float *zero= MEM_callocN(sizeof(float)*tex->w*tex->h*tex->depth, "zero");
495                         glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->depth, format, type, zero);
496                         MEM_freeN(zero);
497                 }
498
499                 glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels);
500                 GPU_print_error("3D glTexSubImage3D");
501         }
502
503
504         glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, vfBorderColor);
505         GPU_print_error("3D GL_TEXTURE_BORDER_COLOR");
506         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
507         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
508         GPU_print_error("3D GL_LINEAR");
509         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
510         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
511         glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
512         GPU_print_error("3D GL_CLAMP_TO_BORDER");
513
514         if (pixels)
515                 MEM_freeN(pixels);
516
517         if (tex)
518                 GPU_texture_unbind(tex);
519
520         return tex;
521 }
522
523 GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, double time, int mipmap)
524 {
525         GPUTexture *tex;
526         GLint w, h, border, lastbindcode, bindcode;
527
528         glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode);
529
530         GPU_update_image_time(ima, time);
531         bindcode = GPU_verify_image(ima, iuser, 0, 0, mipmap);
532
533         if(ima->gputexture) {
534                 ima->gputexture->bindcode = bindcode;
535                 glBindTexture(GL_TEXTURE_2D, lastbindcode);
536                 return ima->gputexture;
537         }
538
539         if(!bindcode) {
540                 glBindTexture(GL_TEXTURE_2D, lastbindcode);
541                 return NULL;
542         }
543
544         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
545         tex->bindcode = bindcode;
546         tex->number = -1;
547         tex->refcount = 1;
548         tex->target = GL_TEXTURE_2D;
549         tex->fromblender = 1;
550
551         ima->gputexture= tex;
552
553         if (!glIsTexture(tex->bindcode)) {
554                 GPU_print_error("Blender Texture");
555         }
556         else {
557                 glBindTexture(GL_TEXTURE_2D, tex->bindcode);
558                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
559                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
560                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border);
561
562                 tex->w = w - border;
563                 tex->h = h - border;
564         }
565
566         glBindTexture(GL_TEXTURE_2D, lastbindcode);
567
568         return tex;
569 }
570
571 GPUTexture *GPU_texture_create_1D(int w, float *fpixels, char err_out[256])
572 {
573         GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, err_out);
574
575         if (tex)
576                 GPU_texture_unbind(tex);
577         
578         return tex;
579 }
580
581 GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels, char err_out[256])
582 {
583         GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, err_out);
584
585         if (tex)
586                 GPU_texture_unbind(tex);
587         
588         return tex;
589 }
590
591 GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
592 {
593         GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, err_out);
594
595         if (tex)
596                 GPU_texture_unbind(tex);
597         
598         return tex;
599 }
600
601 void GPU_texture_bind(GPUTexture *tex, int number)
602 {
603         GLenum arbnumber;
604
605         if (number >= GG.maxtextures) {
606                 GPU_print_error("Not enough texture slots.");
607                 return;
608         }
609
610         if(number == -1)
611                 return;
612
613         GPU_print_error("Pre Texture Bind");
614
615         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + number);
616         if (number != 0) glActiveTextureARB(arbnumber);
617         glBindTexture(tex->target, tex->bindcode);
618         glEnable(tex->target);
619         if (number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
620
621         tex->number = number;
622
623         GPU_print_error("Post Texture Bind");
624 }
625
626 void GPU_texture_unbind(GPUTexture *tex)
627 {
628         GLenum arbnumber;
629
630         if (tex->number >= GG.maxtextures) {
631                 GPU_print_error("Not enough texture slots.");
632                 return;
633         }
634
635         if(tex->number == -1)
636                 return;
637         
638         GPU_print_error("Pre Texture Unbind");
639
640         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
641         if (tex->number != 0) glActiveTextureARB(arbnumber);
642         glBindTexture(tex->target, 0);
643         glDisable(tex->target);
644         if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
645
646         tex->number = -1;
647
648         GPU_print_error("Post Texture Unbind");
649 }
650
651 void GPU_texture_free(GPUTexture *tex)
652 {
653         tex->refcount--;
654
655         if (tex->refcount < 0)
656                 fprintf(stderr, "GPUTexture: negative refcount\n");
657         
658         if (tex->refcount == 0) {
659                 if (tex->fb)
660                         GPU_framebuffer_texture_detach(tex->fb, tex);
661                 if (tex->bindcode && !tex->fromblender)
662                         glDeleteTextures(1, &tex->bindcode);
663
664                 MEM_freeN(tex);
665         }
666 }
667
668 void GPU_texture_ref(GPUTexture *tex)
669 {
670         tex->refcount++;
671 }
672
673 int GPU_texture_target(GPUTexture *tex)
674 {
675         return tex->target;
676 }
677
678 int GPU_texture_opengl_width(GPUTexture *tex)
679 {
680         return tex->w;
681 }
682
683 int GPU_texture_opengl_height(GPUTexture *tex)
684 {
685         return tex->h;
686 }
687
688 GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex)
689 {
690         return tex->fb;
691 }
692
693 /* GPUFrameBuffer */
694
695 struct GPUFrameBuffer {
696         GLuint object;
697         GPUTexture *colortex;
698         GPUTexture *depthtex;
699 };
700
701 GPUFrameBuffer *GPU_framebuffer_create(void)
702 {
703         GPUFrameBuffer *fb;
704
705         if (!GLEW_EXT_framebuffer_object)
706                 return NULL;
707         
708         fb= MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
709         glGenFramebuffersEXT(1, &fb->object);
710
711         if (!fb->object) {
712                 fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
713                         (int)glGetError());
714                 GPU_framebuffer_free(fb);
715                 return NULL;
716         }
717
718         return fb;
719 }
720
721 int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, char err_out[256])
722 {
723         GLenum status;
724         GLenum attachment;
725
726         if(tex->depth)
727                 attachment = GL_DEPTH_ATTACHMENT_EXT;
728         else
729                 attachment = GL_COLOR_ATTACHMENT0_EXT;
730
731         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
732         GG.currentfb = fb->object;
733
734         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, 
735                 tex->target, tex->bindcode, 0);
736
737         if(tex->depth) {
738                 glDrawBuffer(GL_NONE);
739                 glReadBuffer(GL_NONE);
740         }
741         else {
742                 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
743                 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
744         }
745
746         status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
747
748         if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
749                 GPU_framebuffer_restore();
750                 GPU_print_framebuffer_error(status, err_out);
751                 return 0;
752         }
753
754         if(tex->depth)
755                 fb->depthtex = tex;
756         else
757                 fb->colortex = tex;
758
759         tex->fb= fb;
760
761         return 1;
762 }
763
764 void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
765 {
766         GLenum attachment;
767
768         if(!tex->fb)
769                 return;
770
771         if(GG.currentfb != tex->fb->object) {
772                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
773                 GG.currentfb = tex->fb->object;
774         }
775
776         if(tex->depth) {
777                 fb->depthtex = NULL;
778                 attachment = GL_DEPTH_ATTACHMENT_EXT;
779         }
780         else {
781                 fb->colortex = NULL;
782                 attachment = GL_COLOR_ATTACHMENT0_EXT;
783         }
784
785         glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
786                 tex->target, 0, 0);
787
788         tex->fb = NULL;
789 }
790
791 void GPU_framebuffer_texture_bind(GPUFrameBuffer *UNUSED(fb), GPUTexture *tex)
792 {
793         /* push attributes */
794         glPushAttrib(GL_ENABLE_BIT);
795         glPushAttrib(GL_VIEWPORT_BIT);
796         glDisable(GL_SCISSOR_TEST);
797
798         /* bind framebuffer */
799         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
800
801         /* push matrices and set default viewport and matrix */
802         glViewport(0, 0, tex->w, tex->h);
803         GG.currentfb = tex->fb->object;
804
805         glMatrixMode(GL_PROJECTION);
806         glPushMatrix();
807         glLoadIdentity();
808         glMatrixMode(GL_MODELVIEW);
809         glPushMatrix();
810         glLoadIdentity();
811 }
812
813 void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
814 {
815         /* restore matrix */
816         glMatrixMode(GL_PROJECTION);
817         glPopMatrix();
818         glMatrixMode(GL_MODELVIEW);
819         glPopMatrix();
820
821         /* restore attributes */
822         glPopAttrib();
823         glPopAttrib();
824         glEnable(GL_SCISSOR_TEST);
825 }
826
827 void GPU_framebuffer_free(GPUFrameBuffer *fb)
828 {
829         if(fb->depthtex)
830                 GPU_framebuffer_texture_detach(fb, fb->depthtex);
831         if(fb->colortex)
832                 GPU_framebuffer_texture_detach(fb, fb->colortex);
833
834         if(fb->object) {
835                 glDeleteFramebuffersEXT(1, &fb->object);
836
837                 if (GG.currentfb == fb->object) {
838                         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
839                         GG.currentfb = 0;
840                 }
841         }
842
843         MEM_freeN(fb);
844 }
845
846 void GPU_framebuffer_restore(void)
847 {
848         if (GG.currentfb != 0) {
849                 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
850                 GG.currentfb = 0;
851         }
852 }
853
854 /* GPUOffScreen */
855
856 struct GPUOffScreen {
857         GPUFrameBuffer *fb;
858         GPUTexture *color;
859         GPUTexture *depth;
860 };
861
862 GPUOffScreen *GPU_offscreen_create(int *width, int *height, char err_out[256])
863 {
864         GPUOffScreen *ofs;
865
866         ofs= MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
867
868         ofs->fb = GPU_framebuffer_create();
869         if(!ofs->fb) {
870                 GPU_offscreen_free(ofs);
871                 return NULL;
872         }
873
874         ofs->depth = GPU_texture_create_depth(*width, *height, err_out);
875         if(!ofs->depth) {
876                 GPU_offscreen_free(ofs);
877                 return NULL;
878         }
879
880         if(*width!=ofs->depth->w || *height!=ofs->depth->h) {
881                 *width= ofs->depth->w;
882                 *height= ofs->depth->h;
883                 printf("Offscreen size differs from given size!\n");
884         }
885         
886         if(!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, err_out)) {
887                 GPU_offscreen_free(ofs);
888                 return NULL;
889         }
890
891         ofs->color = GPU_texture_create_2D(*width, *height, NULL, err_out);
892         if(!ofs->color) {
893                 GPU_offscreen_free(ofs);
894                 return NULL;
895         }
896
897         if(!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, err_out)) {
898                 GPU_offscreen_free(ofs);
899                 return NULL;
900         }
901
902         GPU_framebuffer_restore();
903
904         return ofs;
905 }
906
907 void GPU_offscreen_free(GPUOffScreen *ofs)
908 {
909         if(ofs->fb)
910                 GPU_framebuffer_free(ofs->fb);
911         if(ofs->color)
912                 GPU_texture_free(ofs->color);
913         if(ofs->depth)
914                 GPU_texture_free(ofs->depth);
915         
916         MEM_freeN(ofs);
917 }
918
919 void GPU_offscreen_bind(GPUOffScreen *ofs)
920 {
921         glDisable(GL_SCISSOR_TEST);
922         GPU_framebuffer_texture_bind(ofs->fb, ofs->color);
923 }
924
925 void GPU_offscreen_unbind(GPUOffScreen *ofs)
926 {
927         GPU_framebuffer_texture_unbind(ofs->fb, ofs->color);
928         GPU_framebuffer_restore();
929         glEnable(GL_SCISSOR_TEST);
930 }
931
932 /* GPUShader */
933
934 struct GPUShader {
935         GLhandleARB object;             /* handle for full shader */
936         GLhandleARB vertex;             /* handle for vertex shader */
937         GLhandleARB fragment;   /* handle for fragment shader */
938         GLhandleARB lib;                /* handle for libment shader */
939         int totattrib;                  /* total number of attributes */
940 };
941
942 static void shader_print_errors(const char *task, char *log, const char *code)
943 {
944         const char *c, *pos, *end = code + strlen(code);
945         int line = 1;
946
947         fprintf(stderr, "GPUShader: %s error:\n", task);
948
949         if(G.f & G_DEBUG) {
950                 c = code;
951                 while ((c < end) && (pos = strchr(c, '\n'))) {
952                         fprintf(stderr, "%2d  ", line);
953                         fwrite(c, (pos+1)-c, 1, stderr);
954                         c = pos+1;
955                         line++;
956                 }
957
958                 fprintf(stderr, "%s", c);
959         }
960
961         fprintf(stderr, "%s\n", log);
962 }
963
964 GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPUShader *lib,*/ const char *libcode)
965 {
966         GLint status;
967         GLcharARB log[5000];
968         const char *fragsource[2];
969         GLsizei length = 0;
970         GLint count;
971         GPUShader *shader;
972
973         if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
974                 return NULL;
975
976         shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
977
978         if(vertexcode)
979                 shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
980         if(fragcode)
981                 shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
982         shader->object = glCreateProgramObjectARB();
983
984         if (!shader->object ||
985                 (vertexcode && !shader->vertex) ||
986                 (fragcode && !shader->fragment)) {
987                 fprintf(stderr, "GPUShader, object creation failed.\n");
988                 GPU_shader_free(shader);
989                 return NULL;
990         }
991
992         if(vertexcode) {
993                 glAttachObjectARB(shader->object, shader->vertex);
994                 glShaderSourceARB(shader->vertex, 1, (const char**)&vertexcode, NULL);
995
996                 glCompileShaderARB(shader->vertex);
997                 glGetObjectParameterivARB(shader->vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status);
998
999                 if (!status) {
1000                         glGetInfoLogARB(shader->vertex, sizeof(log), &length, log);
1001                         shader_print_errors("compile", log, vertexcode);
1002
1003                         GPU_shader_free(shader);
1004                         return NULL;
1005                 }
1006         }
1007
1008         if(fragcode) {
1009                 count = 0;
1010                 if(libcode) fragsource[count++] = libcode;
1011                 if(fragcode) fragsource[count++] = fragcode;
1012
1013                 glAttachObjectARB(shader->object, shader->fragment);
1014                 glShaderSourceARB(shader->fragment, count, fragsource, NULL);
1015
1016                 glCompileShaderARB(shader->fragment);
1017                 glGetObjectParameterivARB(shader->fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status);
1018
1019                 if (!status) {
1020                         glGetInfoLogARB(shader->fragment, sizeof(log), &length, log);
1021                         shader_print_errors("compile", log, fragcode);
1022
1023                         GPU_shader_free(shader);
1024                         return NULL;
1025                 }
1026         }
1027
1028         /*if(lib && lib->lib)
1029                 glAttachObjectARB(shader->object, lib->lib);*/
1030
1031         glLinkProgramARB(shader->object);
1032         glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status);
1033         if (!status) {
1034                 glGetInfoLogARB(shader->object, sizeof(log), &length, log);
1035                 if (fragcode) shader_print_errors("linking", log, fragcode);
1036                 else if (vertexcode) shader_print_errors("linking", log, vertexcode);
1037                 else if (libcode) shader_print_errors("linking", log, libcode);
1038
1039                 GPU_shader_free(shader);
1040                 return NULL;
1041         }
1042
1043         return shader;
1044 }
1045
1046 #if 0
1047 GPUShader *GPU_shader_create_lib(const char *code)
1048 {
1049         GLint status;
1050         GLcharARB log[5000];
1051         GLsizei length = 0;
1052         GPUShader *shader;
1053
1054         if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
1055                 return NULL;
1056
1057         shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
1058
1059         shader->lib = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
1060
1061         if (!shader->lib) {
1062                 fprintf(stderr, "GPUShader, object creation failed.\n");
1063                 GPU_shader_free(shader);
1064                 return NULL;
1065         }
1066
1067         glShaderSourceARB(shader->lib, 1, (const char**)&code, NULL);
1068
1069         glCompileShaderARB(shader->lib);
1070         glGetObjectParameterivARB(shader->lib, GL_OBJECT_COMPILE_STATUS_ARB, &status);
1071
1072         if (!status) {
1073                 glGetInfoLogARB(shader->lib, sizeof(log), &length, log);
1074                 shader_print_errors("compile", log, code);
1075
1076                 GPU_shader_free(shader);
1077                 return NULL;
1078         }
1079
1080         return shader;
1081 }
1082 #endif
1083
1084 void GPU_shader_bind(GPUShader *shader)
1085 {
1086         GPU_print_error("Pre Shader Bind");
1087         glUseProgramObjectARB(shader->object);
1088         GPU_print_error("Post Shader Bind");
1089 }
1090
1091 void GPU_shader_unbind(GPUShader *UNUSED(shader))
1092 {
1093         GPU_print_error("Pre Shader Unbind");
1094         glUseProgramObjectARB(0);
1095         GPU_print_error("Post Shader Unbind");
1096 }
1097
1098 void GPU_shader_free(GPUShader *shader)
1099 {
1100         if (shader->lib)
1101                 glDeleteObjectARB(shader->lib);
1102         if (shader->vertex)
1103                 glDeleteObjectARB(shader->vertex);
1104         if (shader->fragment)
1105                 glDeleteObjectARB(shader->fragment);
1106         if (shader->object)
1107                 glDeleteObjectARB(shader->object);
1108         MEM_freeN(shader);
1109 }
1110
1111 int GPU_shader_get_uniform(GPUShader *shader, const char *name)
1112 {
1113         return glGetUniformLocationARB(shader->object, name);
1114 }
1115
1116 void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, float *value)
1117 {
1118         if(location == -1)
1119                 return;
1120
1121         GPU_print_error("Pre Uniform Vector");
1122
1123         if (length == 1) glUniform1fvARB(location, arraysize, value);
1124         else if (length == 2) glUniform2fvARB(location, arraysize, value);
1125         else if (length == 3) glUniform3fvARB(location, arraysize, value);
1126         else if (length == 4) glUniform4fvARB(location, arraysize, value);
1127         else if (length == 9) glUniformMatrix3fvARB(location, arraysize, 0, value);
1128         else if (length == 16) glUniformMatrix4fvARB(location, arraysize, 0, value);
1129
1130         GPU_print_error("Post Uniform Vector");
1131 }
1132
1133 void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
1134 {
1135         GLenum arbnumber;
1136
1137         if (tex->number >= GG.maxtextures) {
1138                 GPU_print_error("Not enough texture slots.");
1139                 return;
1140         }
1141                 
1142         if(tex->number == -1)
1143                 return;
1144
1145         if(location == -1)
1146                 return;
1147
1148         GPU_print_error("Pre Uniform Texture");
1149
1150         arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
1151
1152         if (tex->number != 0) glActiveTextureARB(arbnumber);
1153         glBindTexture(tex->target, tex->bindcode);
1154         glUniform1iARB(location, tex->number);
1155         glEnable(tex->target);
1156         if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
1157
1158         GPU_print_error("Post Uniform Texture");
1159 }
1160
1161 int GPU_shader_get_attribute(GPUShader *shader, char *name)
1162 {
1163         int index;
1164         
1165         GPU_print_error("Pre Get Attribute");
1166
1167         index = glGetAttribLocationARB(shader->object, name);
1168
1169         GPU_print_error("Post Get Attribute");
1170
1171         return index;
1172 }
1173
1174 #if 0
1175 /* GPUPixelBuffer */
1176
1177 typedef struct GPUPixelBuffer {
1178         GLuint bindcode[2];
1179         GLuint current;
1180         int datasize;
1181         int numbuffers;
1182         int halffloat;
1183 } GPUPixelBuffer;
1184
1185 void GPU_pixelbuffer_free(GPUPixelBuffer *pb)
1186 {
1187         if (pb->bindcode[0])
1188                 glDeleteBuffersARB(pb->numbuffers, pb->bindcode);
1189         MEM_freeN(pb);
1190 }
1191
1192 GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffers)
1193 {
1194         GPUPixelBuffer *pb;
1195
1196         if (!GLEW_ARB_multitexture || !GLEW_EXT_pixel_buffer_object)
1197                 return NULL;
1198         
1199         pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO");
1200         pb->datasize = x*y*4*((halffloat)? 16: 8);
1201         pb->numbuffers = numbuffers;
1202         pb->halffloat = halffloat;
1203
1204            glGenBuffersARB(pb->numbuffers, pb->bindcode);
1205
1206         if (!pb->bindcode[0]) {
1207                 fprintf(stderr, "GPUPixelBuffer allocation failed\n");
1208                 GPU_pixelbuffer_free(pb);
1209                 return NULL;
1210         }
1211
1212         return pb;
1213 }
1214
1215 void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb)
1216 {
1217         void *pixels;
1218         int i;
1219
1220         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
1221
1222         for (i = 0; i < pb->numbuffers; i++) {
1223                 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->bindcode[pb->current]);
1224                 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->datasize, NULL,
1225                 GL_STREAM_DRAW_ARB);
1226
1227                 pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
1228                 /*memcpy(pixels, _oImage.data(), pb->datasize);*/
1229
1230                 if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
1231                         fprintf(stderr, "Could not unmap opengl PBO\n");
1232                         break;
1233                 }
1234         }
1235
1236         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
1237 }
1238
1239 static int pixelbuffer_map_into_gpu(GLuint bindcode)
1240 {
1241         void *pixels;
1242
1243         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
1244         pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
1245
1246         /* do stuff in pixels */
1247
1248         if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
1249                 fprintf(stderr, "Could not unmap opengl PBO\n");
1250                 return 0;
1251         }
1252         
1253         return 1;
1254 }
1255
1256 static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLuint bindcode)
1257 {
1258         GLenum type = (pb->halffloat)? GL_HALF_FLOAT_NV: GL_UNSIGNED_BYTE;
1259         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
1260         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
1261
1262         glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h,
1263                                         GL_RGBA, type, NULL);
1264
1265         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
1266         glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
1267 }
1268
1269 void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb)
1270 {
1271         int newbuffer;
1272
1273         if (pb->numbuffers == 1) {
1274                 pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[0]);
1275                 pixelbuffer_map_into_gpu(pb->bindcode[0]);
1276         }
1277         else {
1278                 pb->current = (pb->current+1)%pb->numbuffers;
1279                 newbuffer = (pb->current+1)%pb->numbuffers;
1280
1281                 pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]);
1282                 pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]);
1283         }
1284 }
1285 #endif
1286