361 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			361 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * ***** BEGIN GPL LICENSE BLOCK *****
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License
 | |
|  * as published by the Free Software Foundation; either version 2
 | |
|  * of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software Foundation,
 | |
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | |
|  *
 | |
|  * The Original Code is Copyright (C) 2005 Blender Foundation.
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * The Original Code is: all of this file.
 | |
|  *
 | |
|  * Contributor(s): Brecht Van Lommel.
 | |
|  *
 | |
|  * ***** END GPL LICENSE BLOCK *****
 | |
|  */
 | |
| 
 | |
| /** \file blender/gpu/intern/gpu_extensions.c
 | |
|  *  \ingroup gpu
 | |
|  *
 | |
|  * Wrap OpenGL features such as textures, shaders and GLSL
 | |
|  * with checks for drivers and GPU support.
 | |
|  */
 | |
| 
 | |
| #include "BLI_utildefines.h"
 | |
| #include "BLI_math_base.h"
 | |
| #include "BLI_math_vector.h"
 | |
| 
 | |
| #include "BKE_global.h"
 | |
| 
 | |
| #include "GPU_basic_shader.h"
 | |
| #include "GPU_extensions.h"
 | |
| #include "GPU_glew.h"
 | |
| #include "GPU_texture.h"
 | |
| 
 | |
| #include "intern/gpu_private.h"
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #ifdef WIN32
 | |
| #  include "BLI_winstuff.h"
 | |
| #endif
 | |
| 
 | |
| /* Extensions support */
 | |
| 
 | |
| /* -- extension: version of GL that absorbs it
 | |
|  * ARB_framebuffer object: 3.0
 | |
|  * EXT_framebuffer_object: 3.0
 | |
|  * EXT_framebuffer_blit: 3.0
 | |
|  * EXT_framebuffer_multisample: 3.0
 | |
|  * EXT_framebuffer_multisample_blit_scaled: ???
 | |
|  * ARB_draw_instanced: 3.1
 | |
|  * ARB_texture_multisample: 3.2
 | |
|  * EXT_geometry_shader4: 3.2
 | |
|  * ARB_texture_query_lod: 4.0
 | |
|  */
 | |
| 
 | |
| static struct GPUGlobal {
 | |
| 	GLint maxtexsize;
 | |
| 	GLint maxcubemapsize;
 | |
| 	GLint maxtextures;
 | |
| 	bool extdisabled;
 | |
| 	int colordepth;
 | |
| 	int samples_color_texture_max;
 | |
| 	GPUDeviceType device;
 | |
| 	GPUOSType os;
 | |
| 	GPUDriverType driver;
 | |
| 	/* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers
 | |
| 	 * calculate dfdy in shader differently when drawing to an offscreen buffer. First
 | |
| 	 * number is factor on screen and second is off-screen */
 | |
| 	float dfdyfactors[2];
 | |
| 	float max_anisotropy;
 | |
| } GG = {1, 0};
 | |
| 
 | |
| /* GPU Types */
 | |
| 
 | |
| bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
 | |
| {
 | |
| 	return (GG.device & device) && (GG.os & os) && (GG.driver & driver);
 | |
| }
 | |
| 
 | |
| /* GPU Extensions */
 | |
| 
 | |
| void GPU_extensions_disable(void)
 | |
| {
 | |
| 	GG.extdisabled = true;
 | |
| }
 | |
| 
 | |
| int GPU_max_texture_size(void)
 | |
| {
 | |
| 	return GG.maxtexsize;
 | |
| }
 | |
| 
 | |
| int GPU_max_textures(void)
 | |
| {
 | |
| 	return GG.maxtextures;
 | |
| }
 | |
| 
 | |
| float GPU_max_texture_anisotropy(void)
 | |
| {
 | |
| 	return GG.max_anisotropy;
 | |
| }
 | |
| 
 | |
| int GPU_max_color_texture_samples(void)
 | |
| {
 | |
| 	return GG.samples_color_texture_max;
 | |
| }
 | |
| 
 | |
| int GPU_max_cube_map_size(void)
 | |
| {
 | |
| 	return GG.maxcubemapsize;
 | |
| }
 | |
| 
 | |
| void GPU_get_dfdy_factors(float fac[2])
 | |
| {
 | |
| 	copy_v2_v2(fac, GG.dfdyfactors);
 | |
| }
 | |
| 
 | |
| void gpu_extensions_init(void)
 | |
| {
 | |
| 	/* BLI_assert(GLEW_VERSION_2_1); */
 | |
| 	/* ^-- maybe a bit extreme? */
 | |
| 
 | |
| 	glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GG.maxtextures);
 | |
| 
 | |
| 	glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GG.maxtexsize);
 | |
| 	glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GG.maxcubemapsize);
 | |
| 
 | |
| 	if (GLEW_EXT_texture_filter_anisotropic)
 | |
| 		glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &GG.max_anisotropy);
 | |
| 	else
 | |
| 		GG.max_anisotropy = 1.0f;
 | |
| 
 | |
| 	GLint r, g, b;
 | |
| 	glGetIntegerv(GL_RED_BITS, &r);
 | |
| 	glGetIntegerv(GL_GREEN_BITS, &g);
 | |
| 	glGetIntegerv(GL_BLUE_BITS, &b);
 | |
| 	GG.colordepth = r + g + b; /* assumes same depth for RGB */
 | |
| 
 | |
| 	if (GLEW_VERSION_3_2 || GLEW_ARB_texture_multisample) {
 | |
| 		glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &GG.samples_color_texture_max);
 | |
| 	}
 | |
| 
 | |
| 	const char *vendor = (const char *)glGetString(GL_VENDOR);
 | |
| 	const char *renderer = (const char *)glGetString(GL_RENDERER);
 | |
| 	const char *version = (const char *)glGetString(GL_VERSION);
 | |
| 
 | |
| 	if (strstr(vendor, "ATI")) {
 | |
| 		GG.device = GPU_DEVICE_ATI;
 | |
| 		GG.driver = GPU_DRIVER_OFFICIAL;
 | |
| 	}
 | |
| 	else if (strstr(vendor, "NVIDIA")) {
 | |
| 		GG.device = GPU_DEVICE_NVIDIA;
 | |
| 		GG.driver = GPU_DRIVER_OFFICIAL;
 | |
| 	}
 | |
| 	else if (strstr(vendor, "Intel") ||
 | |
| 	         /* src/mesa/drivers/dri/intel/intel_context.c */
 | |
| 	         strstr(renderer, "Mesa DRI Intel") ||
 | |
| 	         strstr(renderer, "Mesa DRI Mobile Intel"))
 | |
| 	{
 | |
| 		GG.device = GPU_DEVICE_INTEL;
 | |
| 		GG.driver = GPU_DRIVER_OFFICIAL;
 | |
| 	}
 | |
| 	else if (strstr(renderer, "Mesa DRI R") || (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI "))) {
 | |
| 		GG.device = GPU_DEVICE_ATI;
 | |
| 		GG.driver = GPU_DRIVER_OPENSOURCE;
 | |
| 	}
 | |
| 	else if (strstr(renderer, "Nouveau") || strstr(vendor, "nouveau")) {
 | |
| 		GG.device = GPU_DEVICE_NVIDIA;
 | |
| 		GG.driver = GPU_DRIVER_OPENSOURCE;
 | |
| 	}
 | |
| 	else if (strstr(vendor, "Mesa")) {
 | |
| 		GG.device = GPU_DEVICE_SOFTWARE;
 | |
| 		GG.driver = GPU_DRIVER_SOFTWARE;
 | |
| 	}
 | |
| 	else if (strstr(vendor, "Microsoft")) {
 | |
| 		GG.device = GPU_DEVICE_SOFTWARE;
 | |
| 		GG.driver = GPU_DRIVER_SOFTWARE;
 | |
| 	}
 | |
| 	else if (strstr(renderer, "Apple Software Renderer")) {
 | |
| 		GG.device = GPU_DEVICE_SOFTWARE;
 | |
| 		GG.driver = GPU_DRIVER_SOFTWARE;
 | |
| 	}
 | |
| 	else {
 | |
| 		GG.device = GPU_DEVICE_ANY;
 | |
| 		GG.driver = GPU_DRIVER_ANY;
 | |
| 	}
 | |
| 
 | |
| 	/* make sure double side isn't used by default and only getting enabled in places where it's
 | |
| 	 * really needed to prevent different unexpected behaviors like with intel gme965 card (sergey) */
 | |
| 	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
 | |
| 
 | |
| #ifdef _WIN32
 | |
| 	GG.os = GPU_OS_WIN;
 | |
| #elif defined(__APPLE__)
 | |
| 	GG.os = GPU_OS_MAC;
 | |
| #else
 | |
| 	GG.os = GPU_OS_UNIX;
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 	/* df/dy calculation factors, those are dependent on driver */
 | |
| 	if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) {
 | |
| 		GG.dfdyfactors[0] = 1.0;
 | |
| 		GG.dfdyfactors[1] = -1.0;
 | |
| 	}
 | |
| 	else if ((GG.device == GPU_DEVICE_INTEL) && (GG.os == GPU_OS_WIN) &&
 | |
| 	         (strstr(version, "4.0.0 - Build 10.18.10.3308") ||
 | |
| 	          strstr(version, "4.0.0 - Build 9.18.10.3186") ||
 | |
| 	          strstr(version, "4.0.0 - Build 9.18.10.3165") ||
 | |
| 	          strstr(version, "3.1.0 - Build 9.17.10.3347") ||
 | |
| 	          strstr(version, "3.1.0 - Build 9.17.10.4101") ||
 | |
| 	          strstr(version, "3.3.0 - Build 8.15.10.2618")))
 | |
| 	{
 | |
| 		GG.dfdyfactors[0] = -1.0;
 | |
| 		GG.dfdyfactors[1] = 1.0;
 | |
| 	}
 | |
| 	else {
 | |
| 		GG.dfdyfactors[0] = 1.0;
 | |
| 		GG.dfdyfactors[1] = 1.0;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	GPU_invalid_tex_init();
 | |
| 	GPU_basic_shaders_init();
 | |
| }
 | |
| 
 | |
| void gpu_extensions_exit(void)
 | |
| {
 | |
| 	GPU_basic_shaders_exit();
 | |
| 	GPU_invalid_tex_free();
 | |
| }
 | |
| 
 | |
| bool GPU_legacy_support(void)
 | |
| {
 | |
| 	/* return whether or not current GL context is compatible with legacy OpenGL */
 | |
| 	static bool checked = false;
 | |
| 	static bool support = true;
 | |
| 
 | |
| 	if (!checked) {
 | |
| 		if (GLEW_VERSION_3_2) {
 | |
| 			GLint profile;
 | |
| 			glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
 | |
| 
 | |
| 			if (G.debug & G_DEBUG_GPU) {
 | |
| 				printf("GL_CONTEXT_PROFILE_MASK = %#x (%s profile)\n", (unsigned int)profile,
 | |
| 				       (profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) ? "compatibility" :
 | |
| 				       (profile & GL_CONTEXT_CORE_PROFILE_BIT) ? "core" : "unknown");
 | |
| 			}
 | |
| 
 | |
| 			if (profile == 0) {
 | |
| 				/* workaround for nVidia's Linux driver */
 | |
| 				support = GLEW_ARB_compatibility;
 | |
| 			}
 | |
| 			else {
 | |
| 				support = profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
 | |
| 			}
 | |
| 		}
 | |
| 		else if (GLEW_VERSION_3_1) {
 | |
| 			support = GLEW_ARB_compatibility;
 | |
| 		}
 | |
| 
 | |
| 		/* any OpenGL version <= 3.0 is legacy, so support remains true */
 | |
| 
 | |
| 		checked = true;
 | |
| 	}
 | |
| 
 | |
| 	return support;
 | |
| }
 | |
| 
 | |
| bool GPU_glsl_support(void)
 | |
| {
 | |
| 	/* always supported, still queried by game engine */
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| bool GPU_full_non_power_of_two_support(void)
 | |
| {
 | |
| 	/* always supported on full GL but still relevant for OpenGL ES 2.0 where
 | |
| 	 * NPOT textures can't use mipmaps or repeat wrap mode */
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| bool GPU_display_list_support(void)
 | |
| {
 | |
| 	/* deprecated in GL 3
 | |
| 	 * supported on older GL and compatibility profile
 | |
| 	 * still queried by game engine
 | |
| 	 */
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| bool GPU_bicubic_bump_support(void)
 | |
| {
 | |
| 	return GLEW_VERSION_4_0 || (GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0);
 | |
| }
 | |
| 
 | |
| bool GPU_geometry_shader_support(void)
 | |
| {
 | |
| 	/* in GL 3.2 geometry shaders are fully supported
 | |
| 	 * core profile clashes with our other shaders so accept compatibility only
 | |
| 	 * other GL versions can use EXT_geometry_shader4 if available
 | |
| 	 */
 | |
| 	return (GLEW_VERSION_3_2 && GPU_legacy_support()) || GLEW_EXT_geometry_shader4;
 | |
| }
 | |
| 
 | |
| bool GPU_geometry_shader_support_via_extension(void)
 | |
| {
 | |
| 	return GLEW_EXT_geometry_shader4 && !(GLEW_VERSION_3_2 && GPU_legacy_support());
 | |
| }
 | |
| 
 | |
| bool GPU_instanced_drawing_support(void)
 | |
| {
 | |
| 	return GLEW_VERSION_3_1 || GLEW_ARB_draw_instanced;
 | |
| }
 | |
| 
 | |
| int GPU_color_depth(void)
 | |
| {
 | |
| 	return GG.colordepth;
 | |
| }
 | |
| 
 | |
| bool GPU_mem_stats_supported(void)
 | |
| {
 | |
| 	return (GLEW_NVX_gpu_memory_info || (GLEW_ATI_meminfo)) && (G.debug & G_DEBUG_GPU_MEM);
 | |
| }
 | |
| 
 | |
| 
 | |
| void GPU_mem_stats_get(int *totalmem, int *freemem)
 | |
| {
 | |
| 	if (GLEW_NVX_gpu_memory_info) {
 | |
| 		/* returned value in Kb */
 | |
| 		glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, totalmem);
 | |
| 
 | |
| 		glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, freemem);
 | |
| 	}
 | |
| 	else if (GLEW_ATI_meminfo) {
 | |
| 		int stats[4];
 | |
| 
 | |
| 		glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats);
 | |
| 		*freemem = stats[0];
 | |
| 		*totalmem = 0;
 | |
| 	}
 | |
| 	else {
 | |
| 		*totalmem = 0;
 | |
| 		*freemem = 0;
 | |
| 	}
 | |
| }
 | |
| 
 |