BKE: Add "--debug-gpu-force-workarounds" to force gpu workarounds
[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 "BLI_utildefines.h"
36 #include "BLI_math_base.h"
37 #include "BLI_math_vector.h"
38
39 #include "BKE_global.h"
40 #include "MEM_guardedalloc.h"
41
42 #include "GPU_extensions.h"
43 #include "GPU_framebuffer.h"
44 #include "GPU_glew.h"
45 #include "GPU_texture.h"
46
47 #include "intern/gpu_private.h"
48
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <string.h>
52
53 #ifdef WIN32
54 #  include "BLI_winstuff.h"
55 #endif
56
57 /* Extensions support */
58
59 /* -- extension: version of GL that absorbs it
60  * EXT_gpu_shader4: 3.0
61  * ARB_framebuffer object: 3.0
62  * EXT_framebuffer_multisample_blit_scaled: ???
63  * ARB_draw_instanced: 3.1
64  * ARB_texture_multisample: 3.2
65  * ARB_texture_query_lod: 4.0
66  */
67
68 static struct GPUGlobal {
69         GLint maxtexsize;
70         GLint maxtexlayers;
71         GLint maxcubemapsize;
72         GLint maxtextures;
73         GLint maxtexturesfrag;
74         GLint maxtexturesgeom;
75         GLint maxtexturesvert;
76         GLint maxubosize;
77         GLint maxubobinds;
78         int colordepth;
79         int samples_color_texture_max;
80         GPUDeviceType device;
81         GPUOSType os;
82         GPUDriverType driver;
83         float line_width_range[2];
84         /* 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 dfdyfactors[2];
88         float max_anisotropy;
89         /* Some Intel drivers have issues with using mips as framebuffer targets if
90          * GL_TEXTURE_MAX_LEVEL is higher than the target mip.
91          * We need a workaround in this cases. */
92         bool mip_render_workaround;
93         /* There is an issue with the glBlitFramebuffer on MacOS with radeon pro graphics.
94          * Blitting depth with GL_DEPTH24_STENCIL8 is buggy so the workaround is to use
95          * GPU_DEPTH32F_STENCIL8. Then Blitting depth will work but blitting stencil will
96          * still be broken. */
97         bool depth_blitting_workaround;
98         /* Crappy driver don't know how to map framebuffer slot to output vars...
99          * We need to have no "holes" in the output buffer slots. */
100         bool unused_fb_slot_workaround;
101 } GG = {1, 0};
102
103
104 static void gpu_detect_mip_render_workaround(void)
105 {
106         int cube_size = 2;
107         float *source_pix = MEM_callocN(sizeof(float) * 4 * 6 * cube_size * cube_size, __func__);
108         float clear_color[4] = {1.0f, 0.5f, 0.0f, 0.0f};
109
110         GPUTexture *tex = GPU_texture_create_cube(cube_size, GPU_RGBA16F, source_pix, NULL);
111         MEM_freeN(source_pix);
112
113         GPU_texture_bind(tex, 0);
114         GPU_texture_generate_mipmap(tex);
115         glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0);
116         glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, 0);
117         GPU_texture_unbind(tex);
118
119         GPUFrameBuffer *fb = GPU_framebuffer_create();
120         GPU_framebuffer_texture_attach(fb, tex, 0, 1);
121         GPU_framebuffer_bind(fb);
122         GPU_framebuffer_clear_color(fb, clear_color);
123         GPU_framebuffer_restore();
124         GPU_framebuffer_free(fb);
125
126         float *data = GPU_texture_read(tex, GPU_DATA_FLOAT, 1);
127         GG.mip_render_workaround = !equals_v4v4(clear_color, data);
128
129         MEM_freeN(data);
130         GPU_texture_free(tex);
131 }
132
133 /* GPU Types */
134
135 bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
136 {
137         return (GG.device & device) && (GG.os & os) && (GG.driver & driver);
138 }
139
140 /* GPU Extensions */
141
142 int GPU_max_texture_size(void)
143 {
144         return GG.maxtexsize;
145 }
146
147 int GPU_max_texture_layers(void)
148 {
149         return GG.maxtexlayers;
150 }
151
152 int GPU_max_textures(void)
153 {
154         return GG.maxtextures;
155 }
156
157 int GPU_max_textures_frag(void)
158 {
159         return GG.maxtexturesfrag;
160 }
161
162 int GPU_max_textures_geom(void)
163 {
164         return GG.maxtexturesgeom;
165 }
166
167 int GPU_max_textures_vert(void)
168 {
169         return GG.maxtexturesvert;
170 }
171
172 float GPU_max_texture_anisotropy(void)
173 {
174         return GG.max_anisotropy;
175 }
176
177 int GPU_max_color_texture_samples(void)
178 {
179         return GG.samples_color_texture_max;
180 }
181
182 int GPU_max_cube_map_size(void)
183 {
184         return GG.maxcubemapsize;
185 }
186
187 int GPU_max_ubo_binds(void)
188 {
189         return GG.maxubobinds;
190 }
191
192 int GPU_max_ubo_size(void)
193 {
194         return GG.maxubosize;
195 }
196
197 float GPU_max_line_width(void)
198 {
199         return GG.line_width_range[1];
200 }
201
202 void GPU_get_dfdy_factors(float fac[2])
203 {
204         copy_v2_v2(fac, GG.dfdyfactors);
205 }
206
207 bool GPU_mip_render_workaround(void)
208 {
209         return GG.mip_render_workaround;
210 }
211
212 bool GPU_depth_blitting_workaround(void)
213 {
214         return GG.depth_blitting_workaround;
215 }
216
217 bool GPU_unused_fb_slot_workaround(void)
218 {
219         return GG.unused_fb_slot_workaround;
220 }
221
222 void gpu_extensions_init(void)
223 {
224         /* during 2.8 development each platform has its own OpenGL minimum requirements
225          * final 2.8 release will be unified on OpenGL 3.3 core profile, no required extensions
226          * see developer.blender.org/T49012 for details
227          */
228         BLI_assert(GLEW_VERSION_3_3);
229
230         glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GG.maxtexturesfrag);
231         glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &GG.maxtexturesvert);
232         glGetIntegerv(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &GG.maxtexturesgeom);
233         glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &GG.maxtextures);
234
235         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GG.maxtexsize);
236         glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &GG.maxtexlayers);
237         glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GG.maxcubemapsize);
238
239         if (GLEW_EXT_texture_filter_anisotropic)
240                 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &GG.max_anisotropy);
241         else
242                 GG.max_anisotropy = 1.0f;
243
244         glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &GG.maxubobinds);
245         glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GG.maxubosize);
246
247         glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, GG.line_width_range);
248
249 #ifndef NDEBUG
250         GLint ret;
251         glBindFramebuffer(GL_FRAMEBUFFER, 0);
252         glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &ret);
253         /* We expect FRONT_LEFT to be the default buffer. */
254         BLI_assert(ret == GL_FRAMEBUFFER_DEFAULT);
255 #endif
256
257         GLint r, g, b;
258         glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &r);
259         glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, &g);
260         glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, &b);
261         GG.colordepth = r + g + b; /* Assumes same depth for RGB. */
262
263         glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &GG.samples_color_texture_max);
264
265         const char *vendor = (const char *)glGetString(GL_VENDOR);
266         const char *renderer = (const char *)glGetString(GL_RENDERER);
267         const char *version = (const char *)glGetString(GL_VERSION);
268
269         if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) {
270                 GG.device = GPU_DEVICE_ATI;
271                 GG.driver = GPU_DRIVER_OFFICIAL;
272
273 #ifdef _WIN32
274                 if (strstr(vendor, "Radeon HD 7500M") ||
275                     strstr(vendor, "Radeon HD 7570M"))
276                 {
277                         GG.unused_fb_slot_workaround = true;
278                 }
279 #endif
280
281 #if defined(__APPLE__)
282                 if (strstr(renderer, "AMD Radeon Pro") ||
283                     strstr(renderer, "AMD Radeon R9") ||
284                     strstr(renderer, "AMD Radeon RX"))
285                 {
286                         GG.depth_blitting_workaround = true;
287                 }
288 #endif
289         }
290         else if (strstr(vendor, "NVIDIA")) {
291                 GG.device = GPU_DEVICE_NVIDIA;
292                 GG.driver = GPU_DRIVER_OFFICIAL;
293         }
294         else if (strstr(vendor, "Intel") ||
295                  /* src/mesa/drivers/dri/intel/intel_context.c */
296                  strstr(renderer, "Mesa DRI Intel") ||
297                  strstr(renderer, "Mesa DRI Mobile Intel"))
298         {
299                 GG.device = GPU_DEVICE_INTEL;
300                 GG.driver = GPU_DRIVER_OFFICIAL;
301
302                 if (strstr(renderer, "UHD Graphics")) {
303                         GG.device |= GPU_DEVICE_INTEL_UHD;
304                 }
305         }
306         else if ((strstr(renderer, "Mesa DRI R")) ||
307                  (strstr(renderer, "Radeon") && strstr(vendor, "X.Org")) ||
308                  (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) ||
309                  (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD ")))
310         {
311                 GG.device = GPU_DEVICE_ATI;
312                 GG.driver = GPU_DRIVER_OPENSOURCE;
313         }
314         else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) {
315                 GG.device = GPU_DEVICE_NVIDIA;
316                 GG.driver = GPU_DRIVER_OPENSOURCE;
317         }
318         else if (strstr(vendor, "Mesa")) {
319                 GG.device = GPU_DEVICE_SOFTWARE;
320                 GG.driver = GPU_DRIVER_SOFTWARE;
321         }
322         else if (strstr(vendor, "Microsoft")) {
323                 GG.device = GPU_DEVICE_SOFTWARE;
324                 GG.driver = GPU_DRIVER_SOFTWARE;
325         }
326         else if (strstr(renderer, "Apple Software Renderer")) {
327                 GG.device = GPU_DEVICE_SOFTWARE;
328                 GG.driver = GPU_DRIVER_SOFTWARE;
329         }
330         else {
331                 printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n");
332                 GG.device = GPU_DEVICE_ANY;
333                 GG.driver = GPU_DRIVER_ANY;
334         }
335
336 #ifdef _WIN32
337         GG.os = GPU_OS_WIN;
338 #elif defined(__APPLE__)
339         GG.os = GPU_OS_MAC;
340 #else
341         GG.os = GPU_OS_UNIX;
342 #endif
343
344         gpu_detect_mip_render_workaround();
345
346         if (G.debug & G_DEBUG_GPU_FORCE_WORKAROUNDS) {
347                 GG.mip_render_workaround = true;
348                 GG.depth_blitting_workaround = true;
349                 GG.unused_fb_slot_workaround = true;
350         }
351
352         /* df/dy calculation factors, those are dependent on driver */
353         if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) {
354                 GG.dfdyfactors[0] = 1.0;
355                 GG.dfdyfactors[1] = -1.0;
356         }
357         else if ((GG.device == GPU_DEVICE_INTEL) && (GG.os == GPU_OS_WIN) &&
358                  (strstr(version, "4.0.0 - Build 10.18.10.3308") ||
359                   strstr(version, "4.0.0 - Build 9.18.10.3186") ||
360                   strstr(version, "4.0.0 - Build 9.18.10.3165") ||
361                   strstr(version, "3.1.0 - Build 9.17.10.3347") ||
362                   strstr(version, "3.1.0 - Build 9.17.10.4101") ||
363                   strstr(version, "3.3.0 - Build 8.15.10.2618")))
364         {
365                 GG.dfdyfactors[0] = -1.0;
366                 GG.dfdyfactors[1] = 1.0;
367         }
368         else {
369                 GG.dfdyfactors[0] = 1.0;
370                 GG.dfdyfactors[1] = 1.0;
371         }
372
373
374         GPU_invalid_tex_init();
375 }
376
377 void gpu_extensions_exit(void)
378 {
379         GPU_invalid_tex_free();
380 }
381
382 int GPU_color_depth(void)
383 {
384         return GG.colordepth;
385 }
386
387 bool GPU_mem_stats_supported(void)
388 {
389         return (GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo) && (G.debug & G_DEBUG_GPU_MEM);
390 }
391
392
393 void GPU_mem_stats_get(int *totalmem, int *freemem)
394 {
395         /* TODO(merwin): use Apple's platform API to get this info */
396
397         if (GLEW_NVX_gpu_memory_info) {
398                 /* returned value in Kb */
399                 glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, totalmem);
400
401                 glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, freemem);
402         }
403         else if (GLEW_ATI_meminfo) {
404                 int stats[4];
405
406                 glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats);
407                 *freemem = stats[0];
408                 *totalmem = 0;
409         }
410         else {
411                 *totalmem = 0;
412                 *freemem = 0;
413         }
414 }