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