Files
UnrealEngineUWP/Engine/Source/Developer/ShaderFormatOpenGL/Private/ShaderFormatOpenGL.cpp
Mark Satterthwaite 83ad7e246f Implemented desktop OpenGL support for GL_ARB_separate_shader_objects without requiring any additional shader platforms to reduce shader compile/link hitches.
- Shaders which emit layout location data use INTERFACE_LOCATION & INTERFACE_BLOCK macros to defer to the runtime whether they can be used as separable or non-separable shaders.
- The runtime supplies the correct #define for each so that the shaders still work on platforms where the glLinkProgram implementation fails with separable shader code.
- Shader model 5 platforms (GLSL 430 or ES 3.10) which were already specifying & using layout location data continue to do so, even when using glLinkProgram.
- The 'OpenGL.UseSeparateShaderObjects' console variable allows switching between SSO/Link modes between executions, but not dynamically at runtime.
- Only defaults to on for Mac as that is the only platform which can guarantee that the extension is always available & so far the most tested platform.
- Updated hlslcc binaries are supplied for Mac, Linux & Windows.
- Added an OpenGL RHI stat for shader first draw time so that it is easy to see why hitches occur during runtime due to in-driver shader compilation.

reviewedby michael.trepka, nick.penwarden, dmitry.rekman, rolando.caloca

[CL 2435530 by Mark Satterthwaite in Main branch]
2015-02-06 11:35:30 -05:00

199 lines
5.7 KiB
C++

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "ShaderFormatOpenGL.h"
#include "Core.h"
#include "ModuleInterface.h"
#include "ModuleManager.h"
#include "TargetPlatform.h"
#include "hlslcc.h"
#include "ShaderCore.h"
static FName NAME_GLSL_150(TEXT("GLSL_150"));
static FName NAME_GLSL_150_MAC(TEXT("GLSL_150_MAC"));
static FName NAME_GLSL_430(TEXT("GLSL_430"));
static FName NAME_GLSL_ES2(TEXT("GLSL_ES2"));
static FName NAME_GLSL_ES2_WEBGL(TEXT("GLSL_ES2_WEBGL"));
static FName NAME_GLSL_150_ES2(TEXT("GLSL_150_ES2"));
static FName NAME_GLSL_ES2_IOS(TEXT("GLSL_ES2_IOS"));
static FName NAME_GLSL_310_ES_EXT(TEXT("GLSL_310_ES_EXT"));
class FShaderFormatGLSL : public IShaderFormat
{
enum
{
/** Version for shader format, this becomes part of the DDC key. */
UE_SHADER_GLSL_150_VER = 24,
UE_SHADER_GLSL_150_MAC_VER = 4,
UE_SHADER_GLSL_430_VER = 54,
UE_SHADER_GLSL_ES2_VER = 12,
UE_SHADER_GLSL_150ES2_VER = 15,
UE_SHADER_GLSL_ES2_VER_WEBGL = 13,
UE_SHADER_GLSL_ES2_IOS_VER = 3,
UE_SHADER_GLSL_310_ES_EXT_VER = 1,
};
void CheckFormat(FName Format) const
{
check( Format == NAME_GLSL_150 ||
Format == NAME_GLSL_150_MAC ||
Format == NAME_GLSL_430 ||
Format == NAME_GLSL_ES2 ||
Format == NAME_GLSL_150_ES2 ||
Format == NAME_GLSL_ES2_WEBGL ||
Format == NAME_GLSL_ES2_IOS ||
Format == NAME_GLSL_310_ES_EXT
);
}
public:
virtual uint16 GetVersion(FName Format) const override
{
CheckFormat(Format);
uint32 GLSLVersion = 0;
if (Format == NAME_GLSL_150)
{
GLSLVersion = UE_SHADER_GLSL_150_VER;
}
else if (Format == NAME_GLSL_150_MAC)
{
GLSLVersion = UE_SHADER_GLSL_150_MAC_VER;
}
else if (Format == NAME_GLSL_430)
{
GLSLVersion = UE_SHADER_GLSL_430_VER;
}
else if (Format == NAME_GLSL_ES2)
{
GLSLVersion = UE_SHADER_GLSL_ES2_VER;
}
else if (Format == NAME_GLSL_150_ES2)
{
GLSLVersion = UE_SHADER_GLSL_150ES2_VER;
}
else if (Format == NAME_GLSL_ES2_WEBGL)
{
GLSLVersion = UE_SHADER_GLSL_ES2_VER_WEBGL;
}
else if (Format == NAME_GLSL_ES2_IOS)
{
GLSLVersion = UE_SHADER_GLSL_ES2_IOS_VER;
}
else if (Format == NAME_GLSL_310_ES_EXT)
{
GLSLVersion = UE_SHADER_GLSL_310_ES_EXT_VER;
}
else
{
check(0);
}
const uint8 HLSLCCVersion = ((HLSLCC_VersionMajor & 0x0f) << 4) | (HLSLCC_VersionMinor & 0x0f);
const uint16 Version = ((HLSLCCVersion & 0xff) << 8) | (GLSLVersion & 0xff);
return Version;
}
virtual void GetSupportedFormats(TArray<FName>& OutFormats) const
{
OutFormats.Add(NAME_GLSL_150);
OutFormats.Add(NAME_GLSL_150_MAC);
OutFormats.Add(NAME_GLSL_430);
OutFormats.Add(NAME_GLSL_ES2);
OutFormats.Add(NAME_GLSL_ES2_WEBGL);
OutFormats.Add(NAME_GLSL_150_ES2);
OutFormats.Add(NAME_GLSL_ES2_IOS);
OutFormats.Add(NAME_GLSL_310_ES_EXT);
}
virtual void CompileShader(FName Format, const struct FShaderCompilerInput& Input, struct FShaderCompilerOutput& Output,const FString& WorkingDirectory) const
{
CheckFormat(Format);
if (Format == NAME_GLSL_150)
{
CompileShader_Windows_OGL(Input, Output, WorkingDirectory, GLSL_150);
}
else if (Format == NAME_GLSL_150_MAC)
{
CompileShader_Windows_OGL(Input, Output, WorkingDirectory, GLSL_150_MAC);
}
else if (Format == NAME_GLSL_430)
{
CompileShader_Windows_OGL(Input, Output, WorkingDirectory, GLSL_430);
}
else if (Format == NAME_GLSL_ES2)
{
CompileShader_Windows_OGL(Input, Output, WorkingDirectory, GLSL_ES2);
if (Input.DumpDebugInfoPath != TEXT("") && IFileManager::Get().DirectoryExists(*Input.DumpDebugInfoPath))
{
FShaderCompilerInput ES2Input = Input;
ES2Input.DumpDebugInfoPath = ES2Input.DumpDebugInfoPath.Replace(TEXT("GLSL_150_ES2"), TEXT("GLSL_ES2"), ESearchCase::CaseSensitive);
if (!IFileManager::Get().DirectoryExists(*ES2Input.DumpDebugInfoPath))
{
verifyf(IFileManager::Get().MakeDirectory(*ES2Input.DumpDebugInfoPath, true), TEXT("Failed to create directory for shader debug info '%s'"), *ES2Input.DumpDebugInfoPath);
}
FShaderCompilerOutput ES2Output;
CompileShader_Windows_OGL(ES2Input, ES2Output, WorkingDirectory, GLSL_ES2);
}
}
else if (Format == NAME_GLSL_ES2_WEBGL )
{
CompileShader_Windows_OGL(Input, Output, WorkingDirectory, GLSL_ES2_WEBGL);
}
else if (Format == NAME_GLSL_ES2_IOS )
{
CompileShader_Windows_OGL(Input, Output, WorkingDirectory, GLSL_ES2_IOS);
}
else if (Format == NAME_GLSL_150_ES2)
{
CompileShader_Windows_OGL(Input, Output, WorkingDirectory, GLSL_150_ES2);
if (Input.DumpDebugInfoPath != TEXT("") && IFileManager::Get().DirectoryExists(*Input.DumpDebugInfoPath))
{
FShaderCompilerInput ES2Input = Input;
ES2Input.DumpDebugInfoPath = ES2Input.DumpDebugInfoPath.Replace(TEXT("GLSL_150_ES2"), TEXT("GLSL_ES2_150"), ESearchCase::CaseSensitive);
if (!IFileManager::Get().DirectoryExists(*ES2Input.DumpDebugInfoPath))
{
verifyf(IFileManager::Get().MakeDirectory(*ES2Input.DumpDebugInfoPath, true), TEXT("Failed to create directory for shader debug info '%s'"), *ES2Input.DumpDebugInfoPath);
}
FShaderCompilerOutput ES2Output;
CompileShader_Windows_OGL(ES2Input, ES2Output, WorkingDirectory, GLSL_ES2);
}
}
else if (Format == NAME_GLSL_310_ES_EXT)
{
CompileShader_Windows_OGL(Input, Output, WorkingDirectory, GLSL_310_ES_EXT);
}
else
{
check(0);
}
}
};
/**
* Module for OpenGL shaders
*/
static IShaderFormat* Singleton = NULL;
class FShaderFormatOpenGLModule : public IShaderFormatModule
{
public:
virtual ~FShaderFormatOpenGLModule()
{
delete Singleton;
Singleton = NULL;
}
virtual IShaderFormat* GetShaderFormat()
{
if (!Singleton)
{
Singleton = new FShaderFormatGLSL();
}
return Singleton;
}
};
IMPLEMENT_MODULE( FShaderFormatOpenGLModule, ShaderFormatOpenGL);