Draw Engine: remove hard coded limit on array sizes
[blender.git] / source / blender / gpu / intern / gpu_texture.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Brecht Van Lommel.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include "MEM_guardedalloc.h"
29
30 #include "DNA_image_types.h"
31
32 #include "BLI_blenlib.h"
33 #include "BLI_utildefines.h"
34 #include "BLI_math_base.h"
35
36 #include "BKE_global.h"
37
38 #include "GPU_debug.h"
39 #include "GPU_draw.h"
40 #include "GPU_extensions.h"
41 #include "GPU_framebuffer.h"
42 #include "GPU_glew.h"
43 #include "GPU_texture.h"
44
45 static struct GPUTextureGlobal {
46         GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */
47         GPUTexture *invalid_tex_2D;
48         GPUTexture *invalid_tex_3D;
49 } GG = {NULL, NULL, NULL};
50
51 /* GPUTexture */
52 struct GPUTexture {
53         int w, h, d;        /* width/height/depth */
54         int number;         /* number for multitexture binding */
55         int refcount;       /* reference count */
56         GLenum target;      /* GL_TEXTURE_* */
57         GLenum target_base; /* same as target, (but no multisample)
58                              * use it for unbinding */
59         GLuint bindcode;    /* opengl identifier for texture */
60         int fromblender;    /* we got the texture from Blender */
61
62         GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */
63         int fb_attachment;  /* slot the texture is attached to */
64         bool depth;         /* is a depth texture? */
65         bool stencil;       /* is a stencil texture? */
66 };
67
68 static GLenum GPU_texture_get_format(int components, GPUTextureFormat data_type, GLenum *format, GLenum *data_format, bool *is_depth, bool *is_stencil)
69 {
70         if (data_type == GPU_DEPTH_COMPONENT24 ||
71             data_type == GPU_DEPTH_COMPONENT16 ||
72             data_type == GPU_DEPTH_COMPONENT32F)
73         {
74                 *is_depth = true;
75                 *is_stencil = false;
76                 *data_format = GL_FLOAT;
77                 *format = GL_DEPTH_COMPONENT;
78         }
79         else if (data_type == GPU_DEPTH24_STENCIL8) {
80                 *is_depth = true;
81                 *is_stencil = true;
82                 *data_format = GL_UNSIGNED_INT_24_8;
83                 *format = GL_DEPTH_STENCIL;
84         }
85         else {
86                 *is_depth = false;
87                 *is_stencil = false;
88                 *data_format = GL_FLOAT;
89
90                 switch (components) {
91                         case 1: *format = GL_RED; break;
92                         case 2: *format = GL_RG; break;
93                         case 3: *format = GL_RGB; break;
94                         case 4: *format = GL_RGBA; break;
95                         default: break;
96                 }
97         }
98
99         /* You can add any of the available type to this list
100          * For available types see GPU_texture.h */
101         switch (data_type) {
102                 /* Formats texture & renderbuffer */
103                 case GPU_RGBA16F: return GL_RGBA16F;
104                 case GPU_RG32F: return GL_RG32F;
105                 case GPU_RG16F: return GL_RG16F;
106                 case GPU_RGBA8: return GL_RGBA8;
107                 case GPU_R16F: return GL_R16F;
108                 case GPU_R8: return GL_R8;
109                 /* Special formats texture & renderbuffer */
110                 case GPU_DEPTH24_STENCIL8: return GL_DEPTH24_STENCIL8;
111                 /* Texture only format */
112                 /* ** Add Format here **/
113                 /* Special formats texture only */
114                 /* ** Add Format here **/
115                 /* Depth Formats */
116                 case GPU_DEPTH_COMPONENT32F: return GL_DEPTH_COMPONENT32F;
117                 case GPU_DEPTH_COMPONENT24: return GL_DEPTH_COMPONENT24;
118                 case GPU_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT16;
119                 default:
120                         fprintf(stderr, "Texture format incorrect or unsupported\n");
121                         return 0;
122         }
123 }
124
125 static float *GPU_texture_3D_rescale(GPUTexture *tex, int w, int h, int d, int channels, const float *fpixels)
126 {
127         const unsigned int xf = w / tex->w, yf = h / tex->h, zf = d / tex->d;
128         float *nfpixels = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->d, "GPUTexture Rescaled 3Dtex");
129
130         if (nfpixels) {
131                 GPU_print_error_debug("You need to scale a 3D texture, feel the pain!");
132
133                 for (unsigned k = 0; k < tex->d; k++) {
134                         for (unsigned j = 0; j < tex->h; j++) {
135                                 for (unsigned i = 0; i < tex->w; i++) {
136                                         /* obviously doing nearest filtering here,
137                                          * it's going to be slow in any case, let's not make it worse */
138                                         float xb = i * xf;
139                                         float yb = j * yf;
140                                         float zb = k * zf;
141                                         unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j;
142                                         unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb);
143
144                                         if (channels == 4) {
145                                                 nfpixels[offset * 4] = fpixels[offset_orig * 4];
146                                                 nfpixels[offset * 4 + 1] = fpixels[offset_orig * 4 + 1];
147                                                 nfpixels[offset * 4 + 2] = fpixels[offset_orig * 4 + 2];
148                                                 nfpixels[offset * 4 + 3] = fpixels[offset_orig * 4 + 3];
149                                         }
150                                         else
151                                                 nfpixels[offset] = fpixels[offset_orig];
152                                 }
153                         }
154                 }
155         }
156
157         return nfpixels;
158 }
159
160 /* This tries to allocate video memory for a given texture
161  * If alloc fails, lower the resolution until it fits. */
162 static bool GPU_texture_try_alloc(
163         GPUTexture *tex, GLenum proxy, GLenum internalformat, GLenum format, GLenum data_format,
164         int channels, bool try_rescale, const float *fpixels, float **rescaled_fpixels)
165 {
166         int r_width;
167
168         switch (proxy) {
169                 case GL_PROXY_TEXTURE_1D:
170                         glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, data_format, NULL);
171                         break;
172                 case GL_PROXY_TEXTURE_1D_ARRAY:
173                 case GL_PROXY_TEXTURE_2D:
174                         glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, data_format, NULL);
175                         break;
176                 case GL_PROXY_TEXTURE_2D_ARRAY:
177                 case GL_PROXY_TEXTURE_3D:
178                         glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, NULL);
179                         break;
180         }
181
182         glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &r_width);
183
184         if (r_width == 0 && try_rescale) {
185                 const int w = tex->w, h = tex->h, d = tex->d;
186
187                 /* Find largest texture possible */
188                 while (r_width == 0) {
189                         tex->w /= 2;
190                         tex->h /= 2;
191                         tex->d /= 2;
192
193                         /* really unlikely to happen but keep this just in case */
194                         if (tex->w == 0) break;
195                         if (tex->h == 0 && proxy != GL_PROXY_TEXTURE_1D) break;
196                         if (tex->d == 0 && proxy == GL_PROXY_TEXTURE_3D) break;
197
198                         if (proxy == GL_PROXY_TEXTURE_1D)
199                                 glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, data_format, NULL);
200                         else if (proxy == GL_PROXY_TEXTURE_2D)
201                                 glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, data_format, NULL);
202                         else if (proxy == GL_PROXY_TEXTURE_3D)
203                                 glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, NULL);
204
205                         glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
206                 }
207
208                 /* Rescale */
209                 if (r_width > 0) {
210                         switch (proxy) {
211                                 case GL_PROXY_TEXTURE_1D:
212                                 case GL_PROXY_TEXTURE_2D:
213                                         /* Do nothing for now */
214                                         return false;
215                                 case GL_PROXY_TEXTURE_3D:
216                                         *rescaled_fpixels = GPU_texture_3D_rescale(tex, w, h, d, channels, fpixels);
217                                         return (bool)*rescaled_fpixels;
218                         }
219                 }
220         }
221
222         return (r_width > 0);
223 }
224
225 static GPUTexture *GPU_texture_create_nD(
226         int w, int h, int d, int n, const float *fpixels,
227         GPUTextureFormat data_type, int components, int samples,
228         const bool can_rescale, char err_out[256])
229 {
230         GLenum format, internalformat, proxy, data_format;
231         float *rescaled_fpixels = NULL;
232         const float *pix;
233         bool valid;
234
235         if (samples) {
236                 CLAMP_MAX(samples, GPU_max_color_texture_samples());
237         }
238
239         GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
240         tex->w = w;
241         tex->h = h;
242         tex->d = d;
243         tex->number = -1;
244         tex->refcount = 1;
245         tex->fb_attachment = -1;
246
247         if (n == 1) {
248                 if (h == 0)
249                         tex->target_base = tex->target = GL_TEXTURE_1D;
250                 else
251                         tex->target_base = tex->target = GL_TEXTURE_1D_ARRAY;
252         }
253         else if (n == 2) {
254                 if (d == 0)
255                         tex->target_base = tex->target = GL_TEXTURE_2D;
256                 else
257                         tex->target_base = tex->target = GL_TEXTURE_2D_ARRAY;
258         }
259         else if (n == 3) {
260                 tex->target_base = tex->target = GL_TEXTURE_3D;
261         }
262
263         if (samples && n == 2 && d == 0)
264                 tex->target = GL_TEXTURE_2D_MULTISAMPLE;
265
266         internalformat = GPU_texture_get_format(components, data_type, &format, &data_format, &tex->depth, &tex->stencil);
267
268         /* Generate Texture object */
269         glGenTextures(1, &tex->bindcode);
270
271         if (!tex->bindcode) {
272                 if (err_out)
273                         BLI_snprintf(err_out, 256, "GPUTexture: texture create failed");
274                 else
275                         fprintf(stderr, "GPUTexture: texture create failed");
276                 GPU_texture_free(tex);
277                 return NULL;
278         }
279
280         tex->number = 0;
281         glBindTexture(tex->target, tex->bindcode);
282
283         /* Check if texture fit in VRAM */
284         if (n == 1) {
285                 if (h == 0)
286                         proxy = GL_PROXY_TEXTURE_1D;
287                 else
288                         proxy = GL_PROXY_TEXTURE_1D_ARRAY;
289         }
290         else if (n == 2) {
291                 if (d == 0)
292                         proxy = GL_PROXY_TEXTURE_2D;
293                 else
294                         proxy = GL_PROXY_TEXTURE_2D_ARRAY;
295         }
296         else if (n == 3) {
297                 proxy = GL_PROXY_TEXTURE_3D;
298         }
299
300         valid = GPU_texture_try_alloc(tex, proxy, internalformat, format, data_format, components, can_rescale, fpixels,
301                                       &rescaled_fpixels);
302
303         if (!valid) {
304                 if (err_out)
305                         BLI_snprintf(err_out, 256, "GPUTexture: texture alloc failed");
306                 else
307                         fprintf(stderr, "GPUTexture: texture alloc failed. Not enough Video Memory.");
308                 GPU_texture_free(tex);
309                 return NULL;
310         }
311
312         /* Upload Texture */
313         pix = (rescaled_fpixels) ? rescaled_fpixels : fpixels;
314
315         if (tex->target == GL_TEXTURE_1D) {
316                 glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, data_format, pix);
317         }
318         else if (tex->target == GL_TEXTURE_1D_ARRAY ||
319                  tex->target == GL_TEXTURE_2D ||
320                  tex->target == GL_TEXTURE_2D_MULTISAMPLE)
321         {
322                 if (samples) {
323                         glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true);
324                         if (pix)
325                                 glTexSubImage2D(tex->target, 0, 0, 0, tex->w, tex->h, format, data_format, pix);
326                 }
327                 else {
328                         glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, format, data_format, pix);
329                 }
330         }
331         else {
332                 glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, pix);
333         }
334
335         if (rescaled_fpixels)
336                 MEM_freeN(rescaled_fpixels);
337
338         /* Texture Parameters */
339         if (tex->depth) {
340                 glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
341                 glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
342                 glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
343                 glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
344                 glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
345         }
346         else {
347                 glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
348                 glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
349         }
350
351         glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
352         if (n > 1)      {
353                 glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
354         }
355         if (n > 2)      {
356                 glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
357         }
358
359         GPU_texture_unbind(tex);
360
361         return tex;
362 }
363
364 static GPUTexture *GPU_texture_cube_create(
365         int w, int d,
366         const float *fpixels_px, const float *fpixels_py, const float *fpixels_pz,
367         const float *fpixels_nx, const float *fpixels_ny, const float *fpixels_nz,
368         GPUTextureFormat data_type, int components,
369         char err_out[256])
370 {
371         GLenum format, internalformat, data_format;
372
373         GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
374         tex->w = w;
375         tex->h = w;
376         tex->d = d;
377         tex->number = -1;
378         tex->refcount = 1;
379         tex->fb_attachment = -1;
380
381         if (d == 0) {
382                 tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP;
383         }
384         else {
385                 BLI_assert(false && "Cubemap array Not implemented yet");
386                 // tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY;
387         }
388
389         internalformat = GPU_texture_get_format(components, data_type, &format, &data_format, &tex->depth, &tex->stencil);
390
391         /* Generate Texture object */
392         glGenTextures(1, &tex->bindcode);
393
394         if (!tex->bindcode) {
395                 if (err_out)
396                         BLI_snprintf(err_out, 256, "GPUTexture: texture create failed");
397                 else
398                         fprintf(stderr, "GPUTexture: texture create failed");
399                 GPU_texture_free(tex);
400                 return NULL;
401         }
402
403         tex->number = 0;
404         glBindTexture(tex->target, tex->bindcode);
405
406         /* Upload Texture */
407         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_px);
408         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_py);
409         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_pz);
410         glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_nx);
411         glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_ny);
412         glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_nz);
413
414         /* Texture Parameters */
415         if (tex->depth) {
416                 glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
417                 glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
418                 glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
419                 glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
420                 glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
421         }
422         else {
423                 glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
424                 glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
425         }
426
427         glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
428         glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
429         glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
430
431         GPU_texture_unbind(tex);
432
433         return tex;
434 }
435
436 GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget, bool is_data, double time, int mipmap)
437 {
438         int gputt;
439         /* this binds a texture, so that's why to restore it to 0 */
440         GLint bindcode = GPU_verify_image(ima, iuser, textarget, 0, 0, mipmap, is_data);
441         GPU_update_image_time(ima, time);
442
443         /* see GPUInput::textarget: it can take two values - GL_TEXTURE_2D and GL_TEXTURE_CUBE_MAP
444          * these values are correct for glDisable, so textarget can be safely used in
445          * GPU_texture_bind/GPU_texture_unbind through tex->target_base */
446         if (textarget == GL_TEXTURE_2D)
447                 gputt = TEXTARGET_TEXTURE_2D;
448         else
449                 gputt = TEXTARGET_TEXTURE_CUBE_MAP;
450
451         if (ima->gputexture[gputt]) {
452                 ima->gputexture[gputt]->bindcode = bindcode;
453                 glBindTexture(textarget, 0);
454                 return ima->gputexture[gputt];
455         }
456
457         GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
458         tex->bindcode = bindcode;
459         tex->number = -1;
460         tex->refcount = 1;
461         tex->target = textarget;
462         tex->target_base = textarget;
463         tex->fromblender = 1;
464
465         ima->gputexture[gputt] = tex;
466
467         if (!glIsTexture(tex->bindcode)) {
468                 GPU_print_error_debug("Blender Texture Not Loaded");
469         }
470         else {
471                 GLint w, h, border;
472
473                 GLenum gettarget;
474
475                 if (textarget == GL_TEXTURE_2D)
476                         gettarget = GL_TEXTURE_2D;
477                 else
478                         gettarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
479
480                 glBindTexture(textarget, tex->bindcode);
481                 glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_WIDTH, &w);
482                 glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_HEIGHT, &h);
483                 glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_BORDER, &border);
484
485                 tex->w = w - border;
486                 tex->h = h - border;
487         }
488
489         glBindTexture(textarget, 0);
490
491         return tex;
492 }
493
494 GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
495 {
496         GPUTexture *tex = prv->gputexture[0];
497         GLuint bindcode = 0;
498         
499         if (tex)
500                 bindcode = tex->bindcode;
501         
502         /* this binds a texture, so that's why we restore it to 0 */
503         if (bindcode == 0) {
504                 GPU_create_gl_tex(&bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], GL_TEXTURE_2D, mipmap, 0, NULL);
505         }
506         if (tex) {
507                 tex->bindcode = bindcode;
508                 glBindTexture(GL_TEXTURE_2D, 0);
509                 return tex;
510         }
511
512         tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
513         tex->bindcode = bindcode;
514         tex->number = -1;
515         tex->refcount = 1;
516         tex->target = GL_TEXTURE_2D;
517         tex->target_base = GL_TEXTURE_2D;
518         
519         prv->gputexture[0] = tex;
520         
521         if (!glIsTexture(tex->bindcode)) {
522                 GPU_print_error_debug("Blender Texture Not Loaded");
523         }
524         else {
525                 GLint w, h;
526
527                 glBindTexture(GL_TEXTURE_2D, tex->bindcode);
528                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
529                 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
530                 
531                 tex->w = w;
532                 tex->h = h;
533         }
534         
535         glBindTexture(GL_TEXTURE_2D, 0);
536         
537         return tex;
538
539 }
540
541 GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256])
542 {
543         return GPU_texture_create_nD(w, 0, 0, 1, pixels, GPU_RGBA8, 4, 0, false, err_out);
544 }
545
546 GPUTexture *GPU_texture_create_1D_custom(
547         int w, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256])
548 {
549         return GPU_texture_create_nD(w, 0, 0, 1, pixels, data_type, channels, 0, false, err_out);
550 }
551
552 GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, char err_out[256])
553 {
554         return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, 0, false, err_out);
555 }
556
557 GPUTexture *GPU_texture_create_2D_custom(
558         int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256])
559 {
560         return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, channels, 0, false, err_out);
561 }
562
563 GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, int samples, char err_out[256])
564 {
565         return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, samples, false, err_out);
566 }
567
568 GPUTexture *GPU_texture_create_2D_array_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256])
569 {
570         return GPU_texture_create_nD(w, h, d, 2, pixels, data_type, channels, 0, false, err_out);
571 }
572
573 GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char err_out[256])
574 {
575         return GPU_texture_create_nD(w, h, d, 3, pixels, GPU_RGBA8, 4, 0, true, err_out);
576 }
577
578 GPUTexture *GPU_texture_create_3D_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256])
579 {
580         return GPU_texture_create_nD(w, h, d, 3, pixels, data_type, channels, 0, true, err_out);
581 }
582 GPUTexture *GPU_texture_create_cube_custom(int w, int channels, GPUTextureFormat data_type, const float *fpixels, char err_out[256])
583 {
584         const float *fpixels_px, *fpixels_py, *fpixels_pz, *fpixels_nx, *fpixels_ny, *fpixels_nz;
585
586         if (fpixels) {
587                 fpixels_px = fpixels + 0 * w * w;
588                 fpixels_py = fpixels + 1 * w * w;
589                 fpixels_pz = fpixels + 2 * w * w;
590                 fpixels_nx = fpixels + 3 * w * w;
591                 fpixels_ny = fpixels + 4 * w * w;
592                 fpixels_nz = fpixels + 5 * w * w;
593         }
594         else {
595                 fpixels_px = fpixels_py = fpixels_pz = fpixels_nx = fpixels_ny = fpixels_nz = NULL;
596         }
597
598         return GPU_texture_cube_create(w, 0, fpixels_px, fpixels_py, fpixels_pz, fpixels_nx, fpixels_ny, fpixels_nz, data_type, channels, err_out);
599 }
600
601 GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
602 {
603         return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH_COMPONENT24, 1, 0, false, err_out);
604 }
605
606 GPUTexture *GPU_texture_create_depth_with_stencil(int w, int h, char err_out[256])
607 {
608         return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH24_STENCIL8, 1, 0, false, err_out);
609 }
610
611 GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256])
612 {
613         return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH_COMPONENT24, 1, samples, false, err_out);
614 }
615
616 void GPU_invalid_tex_init(void)
617 {
618         const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
619         GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL);
620         GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, NULL);
621         GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, color, NULL);
622 }
623
624 void GPU_invalid_tex_bind(int mode)
625 {
626         switch (mode) {
627                 case GL_TEXTURE_1D:
628                         glBindTexture(GL_TEXTURE_1D, GG.invalid_tex_1D->bindcode);
629                         break;
630                 case GL_TEXTURE_2D:
631                         glBindTexture(GL_TEXTURE_2D, GG.invalid_tex_2D->bindcode);
632                         break;
633                 case GL_TEXTURE_3D:
634                         glBindTexture(GL_TEXTURE_3D, GG.invalid_tex_3D->bindcode);
635                         break;
636         }
637 }
638
639 void GPU_invalid_tex_free(void)
640 {
641         if (GG.invalid_tex_1D)
642                 GPU_texture_free(GG.invalid_tex_1D);
643         if (GG.invalid_tex_2D)
644                 GPU_texture_free(GG.invalid_tex_2D);
645         if (GG.invalid_tex_3D)
646                 GPU_texture_free(GG.invalid_tex_3D);
647 }
648
649
650 void GPU_texture_bind(GPUTexture *tex, int number)
651 {
652         if (number >= GPU_max_textures()) {
653                 fprintf(stderr, "Not enough texture slots.\n");
654                 return;
655         }
656
657         if ((G.debug & G_DEBUG)) {
658                 if (tex->fb && GPU_framebuffer_bound(tex->fb)) {
659                         fprintf(stderr, "Feedback loop warning!: Attempting to bind texture attached to current framebuffer!\n");
660                 }
661         }
662
663         if (number < 0)
664                 return;
665
666         if (number != 0)
667                 glActiveTexture(GL_TEXTURE0 + number);
668
669         if (tex->bindcode != 0)
670                 glBindTexture(tex->target_base, tex->bindcode);
671         else
672                 GPU_invalid_tex_bind(tex->target_base);
673
674         /* TODO: remove this lines once we're using GLSL everywhere */
675         GLenum target = tex->target_base;
676         if (tex->target_base == GL_TEXTURE_1D_ARRAY)
677                 target = GL_TEXTURE_2D;
678         if (tex->target_base == GL_TEXTURE_2D_ARRAY)
679                 target = GL_TEXTURE_3D;
680         glEnable(target);
681
682         if (number != 0)
683                 glActiveTexture(GL_TEXTURE0);
684
685         tex->number = number;
686 }
687
688 void GPU_texture_unbind(GPUTexture *tex)
689 {
690         if (tex->number >= GPU_max_textures()) {
691                 fprintf(stderr, "Not enough texture slots.\n");
692                 return;
693         }
694
695         if (tex->number == -1)
696                 return;
697
698         if (tex->number != 0)
699                 glActiveTexture(GL_TEXTURE0 + tex->number);
700
701         glBindTexture(tex->target_base, 0);
702
703         /* TODO: remove this lines */
704         GLenum target = tex->target_base;
705         if (tex->target_base == GL_TEXTURE_1D_ARRAY)
706                 target = GL_TEXTURE_2D;
707         if (tex->target_base == GL_TEXTURE_2D_ARRAY)
708                 target = GL_TEXTURE_3D;
709         glDisable(target);
710
711         if (tex->number != 0)
712                 glActiveTexture(GL_TEXTURE0);
713
714         tex->number = -1;
715 }
716
717 int GPU_texture_bound_number(GPUTexture *tex)
718 {
719         return tex->number;
720 }
721
722 void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare)
723 {
724         if (tex->number >= GPU_max_textures()) {
725                 fprintf(stderr, "Not enough texture slots.\n");
726                 return;
727         }
728
729         if (tex->number == -1)
730                 return;
731
732         if (tex->number != 0)
733                 glActiveTexture(GL_TEXTURE0 + tex->number);
734
735         /* TODO viewport: use GL_COMPARE_REF_TO_TEXTURE after we switch to core profile */
736         if (tex->depth)
737                 glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, use_compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE);
738
739         if (tex->number != 0)
740                 glActiveTexture(GL_TEXTURE0);
741 }
742
743 void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter)
744 {
745         if (tex->number >= GPU_max_textures()) {
746                 fprintf(stderr, "Not enough texture slots.\n");
747                 return;
748         }
749
750         if (tex->number == -1)
751                 return;
752
753         if (tex->number != 0)
754                 glActiveTexture(GL_TEXTURE0 + tex->number);
755
756         GLenum filter = use_filter ? GL_LINEAR : GL_NEAREST;
757         glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter);
758         glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter);
759
760         if (tex->number != 0)
761                 glActiveTexture(GL_TEXTURE0);
762 }
763
764 void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat)
765 {
766         if (tex->number >= GPU_max_textures()) {
767                 fprintf(stderr, "Not enough texture slots.\n");
768                 return;
769         }
770
771         if (tex->number == -1)
772                 return;
773
774         if (tex->number != 0)
775                 glActiveTexture(GL_TEXTURE0 + tex->number);
776
777         GLenum repeat = use_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE;
778         glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, repeat);
779         if (tex->target_base != GL_TEXTURE_1D)
780                 glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, repeat);
781         if (tex->target_base == GL_TEXTURE_3D)
782                 glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, repeat);
783
784         if (tex->number != 0)
785                 glActiveTexture(GL_TEXTURE0);
786 }
787
788 void GPU_texture_free(GPUTexture *tex)
789 {
790         tex->refcount--;
791
792         if (tex->refcount < 0)
793                 fprintf(stderr, "GPUTexture: negative refcount\n");
794         
795         if (tex->refcount == 0) {
796                 if (tex->fb)
797                         GPU_framebuffer_texture_detach(tex);
798                 if (tex->bindcode && !tex->fromblender)
799                         glDeleteTextures(1, &tex->bindcode);
800
801                 MEM_freeN(tex);
802         }
803 }
804
805 void GPU_texture_ref(GPUTexture *tex)
806 {
807         tex->refcount++;
808 }
809
810 int GPU_texture_target(const GPUTexture *tex)
811 {
812         return tex->target;
813 }
814
815 int GPU_texture_width(const GPUTexture *tex)
816 {
817         return tex->w;
818 }
819
820 int GPU_texture_height(const GPUTexture *tex)
821 {
822         return tex->h;
823 }
824
825 bool GPU_texture_depth(const GPUTexture *tex)
826 {
827         return tex->depth;
828 }
829
830 bool GPU_texture_stencil(const GPUTexture *tex)
831 {
832         return tex->stencil;
833 }
834
835 int GPU_texture_opengl_bindcode(const GPUTexture *tex)
836 {
837         return tex->bindcode;
838 }
839
840 GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex)
841 {
842         return tex->fb;
843 }
844
845 int GPU_texture_framebuffer_attachment(GPUTexture *tex)
846 {
847         return tex->fb_attachment;
848 }
849
850 void GPU_texture_framebuffer_set(GPUTexture *tex, GPUFrameBuffer *fb, int attachment)
851 {
852         tex->fb = fb;
853         tex->fb_attachment = attachment;
854 }
855