diff options
| author | chai <chaifix@163.com> | 2019-08-14 22:50:43 +0800 | 
|---|---|---|
| committer | chai <chaifix@163.com> | 2019-08-14 22:50:43 +0800 | 
| commit | 15740faf9fe9fe4be08965098bbf2947e096aeeb (patch) | |
| tree | a730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Shaders/GraphicsCaps.cpp | |
Diffstat (limited to 'Runtime/Shaders/GraphicsCaps.cpp')
| -rw-r--r-- | Runtime/Shaders/GraphicsCaps.cpp | 610 | 
1 files changed, 610 insertions, 0 deletions
| diff --git a/Runtime/Shaders/GraphicsCaps.cpp b/Runtime/Shaders/GraphicsCaps.cpp new file mode 100644 index 0000000..a2382ac --- /dev/null +++ b/Runtime/Shaders/GraphicsCaps.cpp @@ -0,0 +1,610 @@ +#include "UnityPrefix.h" +#include "GraphicsCaps.h" +#include "Runtime/GfxDevice/GfxDevice.h" +#include "Runtime/Misc/BuildSettings.h" +#include "Runtime/Misc/SystemInfo.h" + +GraphicsCaps gGraphicsCaps; + +#if UNITY_EDITOR + +#include "Runtime/Graphics/GraphicsHelper.h" +#include "Runtime/Graphics/RenderTexture.h" +#include "Runtime/Camera/Light.h" +#include "Editor/Platform/Interface/EditorWindows.h" +#include "Editor/Src/EditorUserBuildSettings.h" +#include "Editor/Src/BuildPipeline/BuildTargetPlatformSpecific.h" +#include "Runtime/Misc/PlayerSettings.h" +#include "Runtime/Modules/ExportModules.h" + +static bool  gDidInitializeOriginalCaps = false; +GraphicsCaps EXPORT_COREMODULE gOriginalCaps; + +void InvalidateGraphicsStateInEditorWindows(); // EditorWindow + + +#if GFX_SUPPORTS_D3D9 +void InitializeCombinerCapsD3D9(); // CombinerD3D.cpp +#endif + +inline bool RarelySupportedFormat(RenderTextureFormat format) +{ +	return (format == kRTFormatARGB4444) || (format == kRTFormatARGB1555); +} + +bool CheckEmulationValid( const GraphicsCaps& origCaps, GraphicsCaps& emulatedCaps ) +{ +	if (origCaps.shaderCaps < emulatedCaps.shaderCaps) +		return false; +	if (!origCaps.hasFixedFunction && emulatedCaps.hasFixedFunction) +		return false; +	for (int i = 0; i < kRTFormatCount; ++i) +	{ +		if (!RarelySupportedFormat((RenderTextureFormat)i)) +			if (!origCaps.supportsRenderTextureFormat[i] && emulatedCaps.supportsRenderTextureFormat[i]) +				return false; +	} +	if (origCaps.maxTexUnits < emulatedCaps.maxTexUnits) +		return false; +	if (!origCaps.has3DTexture && emulatedCaps.has3DTexture) +		return false; +	if (origCaps.npot < emulatedCaps.npot) +		return false; +	if (!origCaps.hasAutoMipMapGeneration && emulatedCaps.hasAutoMipMapGeneration) +		return false; +	if (!origCaps.hasRenderTargetStencil && emulatedCaps.hasRenderTargetStencil) +		return false; + +	#if GFX_SUPPORTS_OPENGL +	if (GetGfxDevice().GetRenderer() == kGfxRendererOpenGL) +	{ +		if (!origCaps.gl.hasGLSL && emulatedCaps.gl.hasGLSL) +			return false; +		if (!origCaps.gl.hasTextureEnvCombine3ATI && emulatedCaps.gl.hasTextureEnvCombine3ATI) +			return false; +	} +	#endif + +	return true; +} + +void GraphicsCaps::ApplyEmulationSetingsOnly( const GraphicsCaps& origCaps, const Emulation emul ) +{ +	for (int q = 0; q < kTexFormatPCCount; ++q) +		supportsTextureFormat[q] = true; + +	bool glesTargetAndroid = GetBuildTargetGroup(GetEditorUserBuildSettings().GetActiveBuildTarget()) == kPlatformAndroid; + +	switch( emul ) +	{ +	case kEmulNone: +		*this = origCaps; +		break; +	case kEmulSM3: +		// do not set texture units; just let all SM3.0 hardware use whatever they support +		shaderCaps = kShaderLevel3; +		supportsRenderTextureFormat[kRTFormatDepth]		= true; +		supportsRenderTextureFormat[kRTFormatARGBHalf]	= true; +		hasComputeShader = false; +		// GL specific +		#if GFX_SUPPORTS_OPENGL +		gl.hasGLSL = true; +		#endif +		// names +		rendererString = "Emulated Shader Model 3.0"; +		vendorString = "Emulated"; +		#if UNITY_WIN +		fixedVersionString = "Direct3D 9.0c [emulated]"; +		#else +		fixedVersionString = "OpenGL 2.0 [emulated]"; +		#endif +		break; +	case kEmulSM2: +		shaderCaps = kShaderLevel2; +		supportsRenderTextureFormat[kRTFormatDepth]		= true; +		supportsRenderTextureFormat[kRTFormatARGBHalf]	= false; +		maxTexUnits = 4; +		maxTexCoords = 8; +		hasComputeShader = false; +		hasInstancing = false; +		// GL specific +		#if GFX_SUPPORTS_OPENGL +		gl.hasGLSL = true; +		#endif +		// names +		rendererString = "Emulated Shader Model 2.0"; +		vendorString = "Emulated"; +		#if UNITY_WIN +		fixedVersionString = "Direct3D 9.0c [emulated]"; +		#else +		fixedVersionString = "OpenGL 2.0 [emulated]"; +		#endif +		break; +	case kEmulGLES20: +		shaderCaps = kShaderLevel3; +		//hasSRGBReadWrite = glesTargetAndroid; // while only supported on handful devices, lets allow people to use it in emu +		hasSRGBReadWrite = false; +		hasComputeShader = false; +		hasInstancing = false; +		supportsTextureFormat[kTexFormatAlphaLum16]		= false; +		supportsTextureFormat[kTexFormatDXT1]			= glesTargetAndroid; +		supportsTextureFormat[kTexFormatDXT3]			= glesTargetAndroid; +		supportsTextureFormat[kTexFormatDXT5]			= glesTargetAndroid; +		supportsTextureFormat[kTexFormatPVRTC_RGB2]		= true; +		supportsTextureFormat[kTexFormatPVRTC_RGBA2]	= true; +		supportsTextureFormat[kTexFormatPVRTC_RGB4]		= true; +		supportsTextureFormat[kTexFormatPVRTC_RGBA4]	= true; +		supportsTextureFormat[kTexFormatETC_RGB4]		= true; +		supportsTextureFormat[kTexFormatATC_RGB4]		= glesTargetAndroid; +		supportsTextureFormat[kTexFormatATC_RGBA8]		= glesTargetAndroid; +		supportsRenderTextureFormat[kRTFormatARGB32]	= true; +		supportsRenderTextureFormat[kRTFormatARGBHalf]	= true;	// supported on high-end mobiles ;-) +		hasRenderToTexture = true; +		hasTiledGPU = true; // assume tiled GPU when emulating ES2 +		warnRenderTargetUnresolves = true; + +		// don't touch 16bit rt formats, as they depend on underlying hw + +		hasNativeShadowMap = false; +		supportsRenderTextureFormat[kRTFormatDepth]		 = true; +		supportsRenderTextureFormat[kRTFormatShadowMap]	 = false; // will use depth texture for shadows + +		// There is no fixed function texture units in ES2 +		maxTexUnits = maxTexImageUnits = maxTexCoords = 8; +		maxMRTs = 1; +		has3DTexture = false; + +		// gles2.0 has hard shadows. +		disableSoftShadows = true; + +		hasRenderToCubemap = true; +		npotRT = npot = kNPOTFull; +		maxTextureSize = 4096; +		maxCubeMapSize = 512; +		// GL specific +		#if GFX_SUPPORTS_OPENGL +		gl.hasGLSL = true; +		gl.hasTextureEnvCombine3ATI = false; +		gl.hasTextureEnvCombine3NV = false; +		#endif +		// D3D9 specific +		#if GFX_SUPPORTS_D3D9 +		d3d.hasTextureFormatL16 = false; +		d3d.hasTextureFormatA8L8 = false; +		d3d.d3dcaps.MaxSimultaneousTextures = maxTexUnits; +		d3d.d3dcaps.RasterCaps &= ~D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS; +		#endif +		rendererString = "Emulated GPU running OpenGL ES 2.0"; +		vendorString = "Emulated"; +		fixedVersionString = "OpenGL ES 2.0 [emulated]"; +		break; + +	case kEmulXBox360: +	case kEmulPS3: +		shaderCaps = kShaderLevel3; +		hasFixedFunction = false; + +		maxLights = 8; +		maxMRTs = 1; //@TODO: possibly needs change for MRTs on console emulation +		hasAnisoFilter = true; +		maxAnisoLevel = 16; +		hasMipLevelBias = true; + +		hasMultiSample = (emul == kEmulPS3); + +		hasComputeShader = false; +		hasInstancing = false; + +		hasBlendSquare = true; +		hasSeparateAlphaBlend = true; + +		hasS3TCCompression = true; +		hasVertexTextures = true; + +		hasAutoMipMapGeneration = false; + +		maxTexImageUnits = 16; +		maxTexCoords = 8; + +		maxTexUnits = 8; + +		maxTextureSize = 4096; +		maxCubeMapSize = 512; + +		supportsRenderTextureFormat[kRTFormatARGB32] = true; +		supportsRenderTextureFormat[kRTFormatDepth] = true; +		supportsRenderTextureFormat[kRTFormatARGBHalf] = true; +		supportsRenderTextureFormat[kRTFormatShadowMap] = (emul == kEmulPS3); + +		has3DTexture = true; +		npotRT = npot = kNPOTFull; + +		hasRenderToTexture = true; +		hasRenderToCubemap = true; +		hasTwoSidedStencil = true; +		hasSRGBReadWrite = true; +		hasNativeDepthTexture = true; +		hasStencilInDepthTexture = true; +		hasNativeShadowMap = (emul == kEmulPS3); + +		rendererString = "Emulated Shader Model 3.0 (XBOX360/PS3)"; +		vendorString = "Emulated"; +		fixedVersionString = "XBOX360/PS3 (emulated)"; +		break; +	case kEmulDX11_9_1: +	case kEmulDX11_9_3: +		shaderCaps = emul == kEmulDX11_9_3  ? kShaderLevel3 : kShaderLevel2;  +		hasFixedFunction =  emul == kEmulDX11_9_3; + +		maxLights = 8; +		maxMRTs = 1; +		hasAnisoFilter = true; +		maxAnisoLevel = emul == kEmulDX11_9_3 ? 16 : 2; +		hasMipLevelBias = true; + +		hasMultiSample = true; + +		hasComputeShader = false; +		hasInstancing = false; + +		hasBlendSquare = true; +		hasSeparateAlphaBlend = false; + +		hasS3TCCompression = true; +		hasVertexTextures = true; + +		maxTexImageUnits = 16; +		maxTexCoords = 8; + +		maxTexUnits = 8; + +		maxTextureSize = emul == kEmulDX11_9_3 ? 4096 : 2048; +		maxCubeMapSize = emul == kEmulDX11_9_3 ? 4096 : 512; + +		supportsRenderTextureFormat[kRTFormatARGB32] = true; +		supportsRenderTextureFormat[kRTFormatDepth] = true; +		supportsRenderTextureFormat[kRTFormatShadowMap] = true; + +		has3DTexture = true; +		npotRT = npot = kNPOTRestricted; + +		hasTiledGPU = true; // assume tiled GPU when emulating DX11 9.x +		warnRenderTargetUnresolves = true; + +		hasRenderToTexture = true; +		hasRenderToCubemap = false; +		hasTwoSidedStencil = true; +		hasSRGBReadWrite = true; +		hasNativeDepthTexture = true; +		hasStencilInDepthTexture = true; +		hasNativeShadowMap = true; +#if GFX_SUPPORTS_D3D11 +		d3d11.hasShadows10Level9 = true; +#endif + +		rendererString = "Emulated DirectX 11 9.1 No Fixed Function Shaders"; +		vendorString = "Emulated"; +		fixedVersionString = "DirectX 11 9.1 (emulated)"; +		break; +	} +} + +void GraphicsCaps::InitializeOriginalEmulationCapsIfNeeded() +{ +	if (!gDidInitializeOriginalCaps) +	{ +		gDidInitializeOriginalCaps = true; +		SET_ALLOC_OWNER(NULL); +		gOriginalCaps = *this; +	} +} + +void GraphicsCaps::ResetOriginalEmulationCaps() +{ +	gDidInitializeOriginalCaps = false; +} + +bool GraphicsCaps::CheckEmulationSupported( Emulation emul ) +{ +	InitializeOriginalEmulationCapsIfNeeded(); + +	GraphicsCaps emulatedCaps = gOriginalCaps; +	emulatedCaps.ApplyEmulationSetingsOnly(gOriginalCaps, emul); + +	return CheckEmulationValid(gOriginalCaps, emulatedCaps); +} + +bool EmulationWants16bitDepth( GraphicsCaps::Emulation emul ) +{ +	if(    (emul == GraphicsCaps::kEmulGLES20) +	    && GetBuildTargetGroup(GetEditorUserBuildSettings().GetActiveBuildTarget()) == kPlatformAndroid +	    && !GetPlayerSettings().GetUse24BitDepthBuffer() +	  ) +	{ +		return true; +	} + +	return false; +} + +GraphicsCaps::Emulation _CurrentEmulation = GraphicsCaps::kEmulNone; + +void GraphicsCaps::ApplyEmulationSettingsAffectingGUI() +{ +	// well, not the best solution... + +	if( EmulationWants16bitDepth(_CurrentEmulation) ) +		GUIView::RecreateAllOnDepthBitsChange(32, 16); +	else +		GUIView::RecreateAllOnDepthBitsChange(16, 32); +} + +GraphicsCaps::Emulation GraphicsCaps::GetEmulation() const +{ +	return _CurrentEmulation; +} + +void GraphicsCaps::SetEmulation( Emulation emul ) +{ +	if( emul == _CurrentEmulation ) +		return; + +	if (!CheckEmulationSupported(emul)) +	{ +		ErrorString("Attempting to switch to unsupported emulation"); +		return; +	} + +	// must be released before the emulation is set, since the memory usage is estimated from the deviceCaps +	RenderTexture::ReleaseAll(); + +	_CurrentEmulation = emul; + +	InitializeOriginalEmulationCapsIfNeeded(); + +	*this = gOriginalCaps; + +	GfxDevice& device = GetGfxDevice(); +	device.InvalidateState(); +	ShaderLab::SubProgram* nullShaders[kShaderTypeCount] = {0}; +	GraphicsHelper::SetShaders (device, nullShaders, 0); +	InvalidateGraphicsStateInEditorWindows(); + +	ApplyEmulationSettingsAffectingGUI(); +	ApplyEmulationSetingsOnly(gOriginalCaps, emul); +	SharedCapsPostInitialize(); + +	device.CommonReloadResources(GfxDevice::kReleaseRenderTextures | GfxDevice::kReloadShaders | GfxDevice::kReloadTextures); + +	#if GFX_SUPPORTS_D3D9 +	InitializeCombinerCapsD3D9(); +	#endif + +	// Give a chance for image effects (which mostly execute in edit mode +	// as well) to recheck hardware support for them. +	MonoBehaviour::RestartExecuteInEditModeScripts(); + +	// update all lights +	std::vector<Light*> lights; +	Object::FindObjectsOfType (&lights); +	for( std::vector<Light*>::iterator i = lights.begin(); i != lights.end(); ++i ) +	{ +		Light& light = (**i); +		light.Precalc(); +	} +} + +bool GraphicsCaps::IsEmulatingGLES20() const +{ +	return _CurrentEmulation == kEmulGLES20; +} + +#endif // UNITY_EDITOR + + +std::string GraphicsCaps::CheckGPUSupported() const +{ +#if !ENABLE_GFXDEVICE_REMOTE_PROCESS_CLIENT +	GfxDeviceRenderer type = GetGfxDevice().GetRenderer(); + +	// OpenGL +#	if GFX_SUPPORTS_OPENGL +	if (type == kGfxRendererOpenGL) +	{ +		extern bool QueryExtensionGL (const char* ext); + +		// OS X 10.5 on GMA 950 has GL1.2. When we drop 10.5 support we can move +		// up to GL1.4. +		if (gl.glVersion < 12) +		{ +			return Format("OpenGL 1.2 is required. Your GPU (%s) only supports OpenGL %i.%i", rendererString.c_str(), gl.glVersion/10, gl.glVersion%10); +		} +		// Require GLSL +		if (!gl.hasGLSL) +		{ +			return Format("OpenGL GLSL support is required. Your GPU (%s) does not support it", rendererString.c_str()); +		} +		// Require ARB VP/FP +		if (!QueryExtensionGL("GL_ARB_vertex_program") || !QueryExtensionGL("GL_ARB_fragment_program")) +		{ +			return Format("OpenGL vertex/fragment program support is required. Your GPU (%s) does not support it", rendererString.c_str()); +		} + +		// Require VBO, multitexture, ... +		if (gl.glVersion < 15 && !QueryExtensionGL("GL_ARB_vertex_buffer_object")) +		{ +			return Format("OpenGL vertex buffer support is required. Your GPU (%s) does not support it", rendererString.c_str()); +		} +		if (gl.glVersion < 13 && !QueryExtensionGL ("GL_ARB_multitexture")) +		{ +			return Format("OpenGL multitexture support is required. Your GPU (%s) does not support it", rendererString.c_str()); +		} +		if (gl.glVersion < 13 && !QueryExtensionGL ("GL_ARB_texture_cube_map")) +		{ +			return Format("OpenGL cubemap support is required. Your GPU (%s) does not support it", rendererString.c_str()); +		} +		if (gl.glVersion < 13 && !QueryExtensionGL ("GL_ARB_texture_env_dot3")) +		{ +			return Format("OpenGL dot3 combiner support is required. Your GPU (%s) does not support it", rendererString.c_str()); +		} +	} +#	endif // if GFX_SUPPORTS_OPENGL + + +	// D3D9 +#	if GFX_SUPPORTS_D3D9 +	if (type == kGfxRendererD3D9) +	{ +		// Require SM2.0 at least. +		// Note, vertex shaders can be reported as zero in case of software vertex processing. +		// That is a valid & supported case (d3d runtime will run shaders on the CPU, but +		// otherwise they will behave as supported). +		const int kShaderVersion20 = (2 << 8) + 0; +		const int d3dVS = LOWORD(d3d.d3dcaps.VertexShaderVersion); +		const int d3dPS = LOWORD(d3d.d3dcaps.PixelShaderVersion); +		if ((d3dVS != 0 && d3dVS < kShaderVersion20) || (d3dPS < kShaderVersion20)) +		{ +			return Format("DirectX9 GPU (Shader Model 2.0) is required.\r\nYour GPU (%s)\r\nonly supports Shader Model %i.%i", rendererString.c_str(), d3dPS>>8, d3dPS&0xFF); +		} +	} +#	endif // if GFX_SUPPORTS_D3D9 + +	UNUSED(type); + +#endif +	return ""; // all ok +} + + +void GraphicsCaps::SharedCapsPostInitialize() +{ +	// do some sanity checks +	Assert (!hasStencilInDepthTexture || (hasStencilInDepthTexture && hasNativeDepthTexture)); // stencil in depth texture implies native depth texture + +	// requirements for deferred lighting +	const int systemMemoryMB = systeminfo::GetPhysicalMemoryMB(); + +	hasPrePassRenderLoop =  +#		if GFX_SUPPORTS_RENDERLOOP_PREPASS +		(shaderCaps >= kShaderLevel3) &&				// needs SM3.0 +		hasRenderToTexture &&							// needs render textures +		supportsRenderTextureFormat[kRTFormatDepth] &&	// needs depth RT +		hasRenderTargetStencil &&						// needs stencil in RT +		hasTwoSidedStencil &&							// needs two sided stencil +		(systemMemoryMB==0 || systemMemoryMB >= 450)	// disable on old devices that have <512MB RAM (check for zero in case platform doesn't implement it at all...) +#		else +		false +#		endif +		; +} + + +void GraphicsCaps::InitWithBuildVersion() +{ +	#if GFX_SUPPORTS_OPENGL +	// Before 4.2, we never used native shadow maps on GL, so keep that behavior. +	if (GetGfxDevice().GetRenderer() == kGfxRendererOpenGL) +	{ +		// First restore original flag (same player instance can be +		// reused across different content versions) +		hasNativeShadowMap = gl.originalHasNativeShadowMaps; +		supportsRenderTextureFormat[kRTFormatShadowMap] = hasNativeShadowMap; +		 +		if (!IS_CONTENT_NEWER_OR_SAME(kUnityVersion4_2_a1)) +		{ +			hasNativeShadowMap = false; +			supportsRenderTextureFormat[kRTFormatShadowMap] = false; +		} +	} +	#endif +} + + +#if GFX_SUPPORTS_OPENGL || GFX_SUPPORTS_OPENGLES20 +bool FindGLExtension (const char* extensions, const char* ext) +{ +	// Extension names should not have spaces, be NULL or empty +	if (!ext || ext[0] == 0) +		return false; +	if (strchr(ext, ' ')) +		return false; + +	Assert (extensions != NULL); +	if (!extensions) +		return false; + +	const char* start = extensions; +	for (;;) +	{ +		const char* where = strstr (start, ext); +		if (!where) +			break; +		const char* terminator = where + strlen (ext); +		if (where == start || *(where - 1) == ' ') +		{ +			if (*terminator == ' ' || *terminator == '\0') +				return true; +		} +		start = terminator; +	} +	return false; +} +#endif // GFX_SUPPORTS_OPENGL || GFX_SUPPORTS_OPENGLES20 + +#if GFX_SUPPORTS_OPENGLES20 +#if GFX_SUPPORTS_OPENGLES20 +#	include "Runtime/GfxDevice/opengles20/IncludesGLES20.h" +#endif + +bool QueryExtension (const char* ext) +{ +	static const char* extensions = NULL; +	if (!extensions) +		extensions = (const char*)glGetString(GL_EXTENSIONS); +	if (!extensions) +		return false; +	return FindGLExtension (extensions, ext); +} + +#endif // GFX_SUPPORTS_OPENGLES20 + + + +// ------------------------------------------------------------------- + + + +#if ENABLE_UNIT_TESTS +#include "External/UnitTest++/src/UnitTest++.h" + +SUITE (GraphicsCapsTest) +{ +	TEST (GraphicsCaps_DeviceIDs) +	{ +		#if UNITY_EDITOR +		if (gGraphicsCaps.GetEmulation() != GraphicsCaps::kEmulNone) +			return; +		#endif + +		const int vendorID = gGraphicsCaps.vendorID; +		if (vendorID == 0) +			return; + +		std::string vendor = ToLower(gGraphicsCaps.vendorString); + +		if (vendorID == 0x10de) +		{ +			CHECK (vendor.find("nvidia") != std::string::npos); +		} +		if (vendorID == 0x1002) +		{ +			CHECK (vendor.find("ati") != std::string::npos || vendor.find("amd") != std::string::npos); +		} +		if (vendorID == 0x8086) +		{ +			CHECK (vendor.find("intel") != std::string::npos); +		} +	} +} + +#endif // #if ENABLE_UNIT_TESTS | 
