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