Merge branch 'master' into blender2.8
[blender.git] / source / blender / gpu / intern / gpu_extensions.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 /** \file blender/gpu/intern/gpu_extensions.c
29  *  \ingroup gpu
30  *
31  * Wrap OpenGL features such as textures, shaders and GLSL
32  * with checks for drivers and GPU support.
33  */
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_blenlib.h"
38 #include "BLI_utildefines.h"
39 #include "BLI_math_base.h"
40 #include "BLI_math_vector.h"
41
42 #include "BKE_global.h"
43
44 #include "GPU_basic_shader.h"
45 #include "GPU_draw.h"
46 #include "GPU_extensions.h"
47 #include "GPU_glew.h"
48 #include "GPU_texture.h"
49
50 #include "intern/gpu_private.h"
51
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <string.h>
55
56 #ifdef WIN32
57 #  include "BLI_winstuff.h"
58 #endif
59
60 /* Extensions support */
61
62 /* -- extension: version of GL that absorbs it
63  * ARB_framebuffer object: 3.0
64  * EXT_framebuffer_object: 3.0
65  * EXT_framebuffer_blit: 3.0
66  * EXT_framebuffer_multisample: 3.0
67  * EXT_framebuffer_multisample_blit_scaled: ???
68  * ARB_draw_instanced: 3.1
69  * ARB_texture_multisample: 3.2
70  * EXT_geometry_shader4: 3.2
71  * ARB_texture_query_lod: 4.0
72  */
73
74 static struct GPUGlobal {
75         GLint maxtexsize;
76         GLint maxcubemapsize;
77         GLint maxtextures;
78         bool extdisabled;
79         int colordepth;
80         int samples_color_texture_max;
81         GPUDeviceType device;
82         GPUOSType os;
83         GPUDriverType driver;
84         float dfdyfactors[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers
85                                  calculate dfdy in shader differently when drawing to an offscreen buffer. First
86                                  number is factor on screen and second is off-screen */
87         float max_anisotropy;
88 } GG = {1, 0};
89
90 /* GPU Types */
91
92 bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
93 {
94         return (GG.device & device) && (GG.os & os) && (GG.driver & driver);
95 }
96
97 /* GPU Extensions */
98
99 void GPU_extensions_disable(void)
100 {
101         GG.extdisabled = true;
102 }
103
104 int GPU_max_texture_size(void)
105 {
106         return GG.maxtexsize;
107 }
108
109 int GPU_max_textures(void)
110 {
111         return GG.maxtextures;
112 }
113
114 float GPU_max_texture_anisotropy(void)
115 {
116         return GG.max_anisotropy;
117 }
118
119 int GPU_max_color_texture_samples(void)
120 {
121         return GG.samples_color_texture_max;
122 }
123
124 int GPU_max_cube_map_size(void)
125 {
126         return GG.maxcubemapsize;
127 }
128
129 void GPU_get_dfdy_factors(float fac[2])
130 {
131         copy_v2_v2(fac, GG.dfdyfactors);
132 }
133
134 void gpu_extensions_init(void)
135 {
136         /* BLI_assert(GLEW_VERSION_2_1); */
137         /* ^-- maybe a bit extreme? */
138
139         glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GG.maxtextures);
140
141         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GG.maxtexsize);
142         glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GG.maxcubemapsize);
143
144         if (GLEW_EXT_texture_filter_anisotropic)
145                 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &GG.max_anisotropy);
146         else
147                 GG.max_anisotropy = 1.0f;
148
149         GLint r, g, b;
150         glGetIntegerv(GL_RED_BITS, &r);
151         glGetIntegerv(GL_GREEN_BITS, &g);
152         glGetIntegerv(GL_BLUE_BITS, &b);
153         GG.colordepth = r + g + b; /* assumes same depth for RGB */
154
155         if (GLEW_VERSION_3_2 || GLEW_ARB_texture_multisample) {
156                 glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &GG.samples_color_texture_max);
157         }
158
159         const char *vendor = (const char *)glGetString(GL_VENDOR);
160         const char *renderer = (const char *)glGetString(GL_RENDERER);
161         const char *version = (const char *)glGetString(GL_VERSION);
162
163         if (strstr(vendor, "ATI")) {
164                 GG.device = GPU_DEVICE_ATI;
165                 GG.driver = GPU_DRIVER_OFFICIAL;
166         }
167         else if (strstr(vendor, "NVIDIA")) {
168                 GG.device = GPU_DEVICE_NVIDIA;
169                 GG.driver = GPU_DRIVER_OFFICIAL;
170         }
171         else if (strstr(vendor, "Intel") ||
172                  /* src/mesa/drivers/dri/intel/intel_context.c */
173                  strstr(renderer, "Mesa DRI Intel") ||
174                  strstr(renderer, "Mesa DRI Mobile Intel"))
175         {
176                 GG.device = GPU_DEVICE_INTEL;
177                 GG.driver = GPU_DRIVER_OFFICIAL;
178         }
179         else if (strstr(renderer, "Mesa DRI R") || (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI "))) {
180                 GG.device = GPU_DEVICE_ATI;
181                 GG.driver = GPU_DRIVER_OPENSOURCE;
182         }
183         else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) {
184                 GG.device = GPU_DEVICE_NVIDIA;
185                 GG.driver = GPU_DRIVER_OPENSOURCE;
186         }
187         else if (strstr(vendor, "Mesa")) {
188                 GG.device = GPU_DEVICE_SOFTWARE;
189                 GG.driver = GPU_DRIVER_SOFTWARE;
190         }
191         else if (strstr(vendor, "Microsoft")) {
192                 GG.device = GPU_DEVICE_SOFTWARE;
193                 GG.driver = GPU_DRIVER_SOFTWARE;
194         }
195         else if (strstr(renderer, "Apple Software Renderer")) {
196                 GG.device = GPU_DEVICE_SOFTWARE;
197                 GG.driver = GPU_DRIVER_SOFTWARE;
198         }
199         else {
200                 GG.device = GPU_DEVICE_ANY;
201                 GG.driver = GPU_DRIVER_ANY;
202         }
203
204         /* make sure double side isn't used by default and only getting enabled in places where it's
205          * really needed to prevent different unexpected behaviors like with intel gme965 card (sergey) */
206         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
207
208 #ifdef _WIN32
209         GG.os = GPU_OS_WIN;
210 #elif defined(__APPLE__)
211         GG.os = GPU_OS_MAC;
212 #else
213         GG.os = GPU_OS_UNIX;
214 #endif
215
216
217         /* df/dy calculation factors, those are dependent on driver */
218         if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) {
219                 GG.dfdyfactors[0] = 1.0;
220                 GG.dfdyfactors[1] = -1.0;
221         }
222         else if ((GG.device == GPU_DEVICE_INTEL) && (GG.os == GPU_OS_WIN) &&
223                  (strstr(version, "4.0.0 - Build 10.18.10.3308") ||
224                   strstr(version, "4.0.0 - Build 9.18.10.3186") ||
225                   strstr(version, "4.0.0 - Build 9.18.10.3165") ||
226                   strstr(version, "3.1.0 - Build 9.17.10.3347") ||
227                   strstr(version, "3.1.0 - Build 9.17.10.4101") ||
228                   strstr(version, "3.3.0 - Build 8.15.10.2618")))
229         {
230                 GG.dfdyfactors[0] = -1.0;
231                 GG.dfdyfactors[1] = 1.0;
232         }
233         else {
234                 GG.dfdyfactors[0] = 1.0;
235                 GG.dfdyfactors[1] = 1.0;
236         }
237
238
239         GPU_invalid_tex_init();
240         GPU_basic_shaders_init();
241 }
242
243 void gpu_extensions_exit(void)
244 {
245         GPU_basic_shaders_exit();
246         GPU_invalid_tex_free();
247 }
248
249 bool GPU_legacy_support(void)
250 {
251         /* return whether or not current GL context is compatible with legacy OpenGL */
252         static bool checked = false;
253         static bool support = true;
254
255         if (!checked) {
256                 if (GLEW_VERSION_3_2) {
257                         GLint profile;
258                         glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
259
260                         if (G.debug & G_DEBUG_GPU) {
261                                 printf("GL_CONTEXT_PROFILE_MASK = %#x (%s profile)\n", (unsigned int)profile,
262                                        (profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) ? "compatibility" :
263                                        (profile & GL_CONTEXT_CORE_PROFILE_BIT) ? "core" : "unknown");
264                         }
265
266                         if (profile == 0) {
267                                 /* workaround for nVidia's Linux driver */
268                                 support = GLEW_ARB_compatibility;
269                         }
270                         else {
271                                 support = profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
272                         }
273                 }
274                 else if (GLEW_VERSION_3_1) {
275                         support = GLEW_ARB_compatibility;
276                 }
277
278                 /* any OpenGL version <= 3.0 is legacy, so support remains true */
279
280                 checked = true;
281         }
282
283         return support;
284 }
285
286 bool GPU_glsl_support(void)
287 {
288         /* always supported, still queried by game engine */
289         return true;
290 }
291
292 bool GPU_full_non_power_of_two_support(void)
293 {
294         /* always supported on full GL but still relevant for OpenGL ES 2.0 where
295          * NPOT textures can't use mipmaps or repeat wrap mode */
296         return true;
297 }
298
299 bool GPU_display_list_support(void)
300 {
301         /* deprecated in GL 3
302          * supported on older GL and compatibility profile
303          * still queried by game engine
304          */
305         return true;
306 }
307
308 bool GPU_bicubic_bump_support(void)
309 {
310         return GLEW_VERSION_4_0 || (GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0);
311 }
312
313 bool GPU_geometry_shader_support(void)
314 {
315         /* in GL 3.2 geometry shaders are fully supported
316          * core profile clashes with our other shaders so accept compatibility only
317          * other GL versions can use EXT_geometry_shader4 if available
318          */
319         return (GLEW_VERSION_3_2 && GPU_legacy_support()) || GLEW_EXT_geometry_shader4;
320 }
321
322 bool GPU_geometry_shader_support_via_extension(void)
323 {
324         return GLEW_EXT_geometry_shader4 && !(GLEW_VERSION_3_2 && GPU_legacy_support());
325 }
326
327 bool GPU_instanced_drawing_support(void)
328 {
329         return GLEW_VERSION_3_1 || GLEW_ARB_draw_instanced;
330 }
331
332 int GPU_color_depth(void)
333 {
334         return GG.colordepth;
335 }
336
337 bool GPU_mem_stats_supported(void)
338 {
339         return (GLEW_NVX_gpu_memory_info || (GLEW_ATI_meminfo)) && (G.debug & G_DEBUG_GPU_MEM);
340 }
341
342
343 void GPU_mem_stats_get(int *totalmem, int *freemem)
344 {
345         if (GLEW_NVX_gpu_memory_info) {
346                 /* returned value in Kb */
347                 glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, totalmem);
348
349                 glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, freemem);
350         }
351         else if (GLEW_ATI_meminfo) {
352                 int stats[4];
353
354                 glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats);
355                 *freemem = stats[0];
356                 *totalmem = 0;
357         }
358         else {
359                 *totalmem = 0;
360                 *freemem = 0;
361         }
362 }
363