Browse Source

Moved the shader source compilation code outside RenderingDevice and Vulkan

Juan Linietsky 6 years ago
parent
commit
4fe3ee1730

+ 0 - 58
drivers/vulkan/SCsub

@@ -4,63 +4,5 @@ Import('env')
 
 env.add_source_files(env.drivers_sources,"*.cpp")
 
-# Thirdparty source files
-# Not unbundled so far since not widespread as shared library
-thirdparty_dir = "#thirdparty/glslang/"
-thirdparty_sources = [
-"glslang/MachineIndependent/RemoveTree.cpp",
-"glslang/MachineIndependent/ParseHelper.cpp",
-"glslang/MachineIndependent/iomapper.cpp",
-"glslang/MachineIndependent/propagateNoContraction.cpp",
-"glslang/MachineIndependent/Intermediate.cpp",
-"glslang/MachineIndependent/linkValidate.cpp",
-"glslang/MachineIndependent/attribute.cpp",
-"glslang/MachineIndependent/Scan.cpp",
-"glslang/MachineIndependent/Initialize.cpp",
-"glslang/MachineIndependent/Constant.cpp",
-"glslang/MachineIndependent/reflection.cpp",
-"glslang/MachineIndependent/limits.cpp",
-"glslang/MachineIndependent/preprocessor/PpScanner.cpp",
-"glslang/MachineIndependent/preprocessor/PpTokens.cpp",
-"glslang/MachineIndependent/preprocessor/PpAtom.cpp",
-"glslang/MachineIndependent/preprocessor/PpContext.cpp",
-"glslang/MachineIndependent/preprocessor/Pp.cpp",
-"glslang/MachineIndependent/InfoSink.cpp",
-"glslang/MachineIndependent/intermOut.cpp",
-"glslang/MachineIndependent/SymbolTable.cpp",
-"glslang/MachineIndependent/glslang_tab.cpp",
-"glslang/MachineIndependent/pch.cpp",
-"glslang/MachineIndependent/Versions.cpp",
-"glslang/MachineIndependent/ShaderLang.cpp",
-"glslang/MachineIndependent/parseConst.cpp",
-"glslang/MachineIndependent/PoolAlloc.cpp",
-"glslang/MachineIndependent/ParseContextBase.cpp",
-"glslang/MachineIndependent/IntermTraverse.cpp",
-"glslang/GenericCodeGen/Link.cpp",
-"glslang/GenericCodeGen/CodeGen.cpp",
-"OGLCompilersDLL/InitializeDll.cpp",
-"SPIRV/InReadableOrder.cpp",
-"SPIRV/GlslangToSpv.cpp",
-"SPIRV/SpvBuilder.cpp",
-"SPIRV/SpvTools.cpp",
-"SPIRV/disassemble.cpp",
-"SPIRV/doc.cpp",
-"SPIRV/SPVRemapper.cpp",
-"SPIRV/SpvPostProcess.cpp",
-"SPIRV/Logger.cpp"
-]
-
-if (env["platform"]=="windows"):
-	thirdparty_sources.append("glslang/OSDependent/Windows/ossource.cpp")
-else:
-	thirdparty_sources.append("glslang/OSDependent/Unix/ossource.cpp")
-
-thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-
-env_thirdparty = env.Clone()
-#env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources)
-
-env.Prepend(CPPPATH=[thirdparty_dir])
 
 #SConscript("shaders/SCsub")

+ 12 - 271
drivers/vulkan/rendering_device_vulkan.cpp

@@ -3,8 +3,6 @@
 #include "core/os/file_access.h"
 #include "core/project_settings.h"
 #include "drivers/vulkan/vulkan_context.h"
-#include "thirdparty/glslang/SPIRV/GlslangToSpv.h"
-#include "thirdparty/glslang/glslang/Include/Types.h"
 #include "thirdparty/spirv-reflect/spirv_reflect.h"
 
 void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) {
@@ -3212,103 +3210,6 @@ RID RenderingDeviceVulkan::index_array_create(RID p_index_buffer, uint32_t p_ind
 /**** SHADER ****/
 /****************/
 
-static const TBuiltInResource default_builtin_resource = {
-	.maxLights = 32,
-	.maxClipPlanes = 6,
-	.maxTextureUnits = 32,
-	.maxTextureCoords = 32,
-	.maxVertexAttribs = 64,
-	.maxVertexUniformComponents = 4096,
-	.maxVaryingFloats = 64,
-	.maxVertexTextureImageUnits = 32,
-	.maxCombinedTextureImageUnits = 80,
-	.maxTextureImageUnits = 32,
-	.maxFragmentUniformComponents = 4096,
-	.maxDrawBuffers = 32,
-	.maxVertexUniformVectors = 128,
-	.maxVaryingVectors = 8,
-	.maxFragmentUniformVectors = 16,
-	.maxVertexOutputVectors = 16,
-	.maxFragmentInputVectors = 15,
-	.minProgramTexelOffset = -8,
-	.maxProgramTexelOffset = 7,
-	.maxClipDistances = 8,
-	.maxComputeWorkGroupCountX = 65535,
-	.maxComputeWorkGroupCountY = 65535,
-	.maxComputeWorkGroupCountZ = 65535,
-	.maxComputeWorkGroupSizeX = 1024,
-	.maxComputeWorkGroupSizeY = 1024,
-	.maxComputeWorkGroupSizeZ = 64,
-	.maxComputeUniformComponents = 1024,
-	.maxComputeTextureImageUnits = 16,
-	.maxComputeImageUniforms = 8,
-	.maxComputeAtomicCounters = 8,
-	.maxComputeAtomicCounterBuffers = 1,
-	.maxVaryingComponents = 60,
-	.maxVertexOutputComponents = 64,
-	.maxGeometryInputComponents = 64,
-	.maxGeometryOutputComponents = 128,
-	.maxFragmentInputComponents = 128,
-	.maxImageUnits = 8,
-	.maxCombinedImageUnitsAndFragmentOutputs = 8,
-	.maxCombinedShaderOutputResources = 8,
-	.maxImageSamples = 0,
-	.maxVertexImageUniforms = 0,
-	.maxTessControlImageUniforms = 0,
-	.maxTessEvaluationImageUniforms = 0,
-	.maxGeometryImageUniforms = 0,
-	.maxFragmentImageUniforms = 8,
-	.maxCombinedImageUniforms = 8,
-	.maxGeometryTextureImageUnits = 16,
-	.maxGeometryOutputVertices = 256,
-	.maxGeometryTotalOutputComponents = 1024,
-	.maxGeometryUniformComponents = 1024,
-	.maxGeometryVaryingComponents = 64,
-	.maxTessControlInputComponents = 128,
-	.maxTessControlOutputComponents = 128,
-	.maxTessControlTextureImageUnits = 16,
-	.maxTessControlUniformComponents = 1024,
-	.maxTessControlTotalOutputComponents = 4096,
-	.maxTessEvaluationInputComponents = 128,
-	.maxTessEvaluationOutputComponents = 128,
-	.maxTessEvaluationTextureImageUnits = 16,
-	.maxTessEvaluationUniformComponents = 1024,
-	.maxTessPatchComponents = 120,
-	.maxPatchVertices = 32,
-	.maxTessGenLevel = 64,
-	.maxViewports = 16,
-	.maxVertexAtomicCounters = 0,
-	.maxTessControlAtomicCounters = 0,
-	.maxTessEvaluationAtomicCounters = 0,
-	.maxGeometryAtomicCounters = 0,
-	.maxFragmentAtomicCounters = 8,
-	.maxCombinedAtomicCounters = 8,
-	.maxAtomicCounterBindings = 1,
-	.maxVertexAtomicCounterBuffers = 0,
-	.maxTessControlAtomicCounterBuffers = 0,
-	.maxTessEvaluationAtomicCounterBuffers = 0,
-	.maxGeometryAtomicCounterBuffers = 0,
-	.maxFragmentAtomicCounterBuffers = 1,
-	.maxCombinedAtomicCounterBuffers = 1,
-	.maxAtomicCounterBufferSize = 16384,
-	.maxTransformFeedbackBuffers = 4,
-	.maxTransformFeedbackInterleavedComponents = 64,
-	.maxCullDistances = 8,
-	.maxCombinedClipAndCullDistances = 8,
-	.maxSamples = 4,
-	.limits = {
-			.nonInductiveForLoops = 1,
-			.whileLoops = 1,
-			.doWhileLoops = 1,
-			.generalUniformIndexing = 1,
-			.generalAttributeMatrixVectorIndexing = 1,
-			.generalVaryingIndexing = 1,
-			.generalSamplerIndexing = 1,
-			.generalVariableIndexing = 1,
-			.generalConstantMatrixVectorIndexing = 1,
-	}
-};
-
 static const char *shader_stage_names[RenderingDevice::SHADER_STAGE_MAX] = {
 	"Vertex",
 	"Fragment",
@@ -3347,7 +3248,7 @@ String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) {
 	}
 	return ret;
 }
-
+#if 0
 bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLayoutBinding> > &bindings, Vector<Vector<UniformInfo> > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error) {
 
 	VkDescriptorSetLayoutBinding layout_binding;
@@ -3543,30 +3444,12 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
 
 	return true;
 }
+#endif
 
-RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSource> &p_stages, String *r_error, ShaderStage *r_error_stage, bool p_allow_cache) {
+RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages) {
 
 	_THREAD_SAFE_METHOD_
 
-	// initialize in case it's not initialized. This is done once per thread
-	// and it's safe to call multiple times
-	glslang::InitializeProcess();
-	EShLanguage stages[SHADER_STAGE_MAX] = {
-		EShLangVertex,
-		EShLangFragment,
-		EShLangTessControl,
-		EShLangTessEvaluation,
-		EShLangCompute
-	};
-
-	int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100
-	glslang::EShTargetClientVersion VulkanClientVersion = glslang::EShTargetVulkan_1_0;
-	glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_0;
-
-	Vector<std::vector<unsigned int> > spirv_code;
-
-	glslang::TShader::ForbidIncluder includer;
-
 	//descriptor layouts
 	Vector<Vector<VkDescriptorSetLayoutBinding> > set_bindings;
 	Vector<Vector<UniformInfo> > uniform_info;
@@ -3581,148 +3464,13 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
 
 	for (int i = 0; i < p_stages.size(); i++) {
 
-		if (stages_processed & (1 << p_stages[i].shader_stage)) {
-			if (r_error) {
-				(*r_error) = "Stage " + String(shader_stage_names[p_stages[i].shader_stage]) + " submitted more than once.";
-			}
-			return RID();
-		}
-		glslang::TShader shader(stages[p_stages[i].shader_stage]);
-		CharString cs = p_stages[i].shader_source.utf8();
-		const char *cs_strings = cs.get_data();
-		shader.setStrings(&cs_strings, 1);
-		shader.setEnvInput(glslang::EShSourceGlsl, stages[p_stages[i].shader_stage], glslang::EShClientVulkan, ClientInputSemanticsVersion);
-		shader.setEnvClient(glslang::EShClientVulkan, VulkanClientVersion);
-		shader.setEnvTarget(glslang::EShTargetSpv, TargetVersion);
-
-		EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
-		const int DefaultVersion = 100;
-		std::string pre_processed_code;
-
-		//preprocess
-		if (!shader.preprocess(&default_builtin_resource, DefaultVersion, ENoProfile, false, false, messages, &pre_processed_code, includer)) {
-
-			if (r_error) {
-				(*r_error) = "Failed pre-processing on shader stage: " + String(shader_stage_names[p_stages[i].shader_stage]) + "\n";
-				(*r_error) += shader.getInfoLog();
-				(*r_error) += "\n";
-				(*r_error) += shader.getInfoDebugLog();
-			}
-
-			if (r_error_stage) {
-				*r_error_stage = p_stages[i].shader_stage;
-			}
-
-			return RID();
-		}
-		//set back..
-		cs_strings = pre_processed_code.c_str();
-		shader.setStrings(&cs_strings, 1);
-
-		//parse
-		if (!shader.parse(&default_builtin_resource, DefaultVersion, false, messages)) {
-			if (r_error) {
-				(*r_error) = "Failed parsing on shader stage: " + String(shader_stage_names[p_stages[i].shader_stage]) + "\n";
-				(*r_error) += shader.getInfoLog();
-				(*r_error) += "\n";
-				(*r_error) += shader.getInfoDebugLog();
-			}
-			if (r_error_stage) {
-				*r_error_stage = p_stages[i].shader_stage;
-			}
-
-			return RID();
-		}
-
-		//link
-		glslang::TProgram program;
-		program.addShader(&shader);
-
-		if (!program.link(messages)) {
-			if (r_error) {
-				(*r_error) = "Failed linking on shader stage: " + String(shader_stage_names[p_stages[i].shader_stage]) + "\n";
-				(*r_error) += program.getInfoLog();
-				(*r_error) += "\n";
-				(*r_error) += program.getInfoDebugLog();
-			}
-			if (r_error_stage) {
-				*r_error_stage = p_stages[i].shader_stage;
-			}
-
-			return RID();
-		}
-
-#if 0
-		//obtain bindings for descriptor layout
-		program.mapIO();
-		program.buildReflection(EShReflectionAllBlockVariables);
-		//program.dumpReflection();
-
-		for (int j = 0; j < program.getNumUniformBlocks(); j++) {
-			const glslang::TObjectReflection &reflection = program.getUniformBlock(j);
-			if (reflection.getType()->getBasicType() == glslang::EbtBlock && reflection.getType()->getQualifier().storage == glslang::EvqUniform && reflection.getType()->getQualifier().layoutPushConstant) {
-				uint32_t len = reflection.size;
-				if (push_constant_debug.push_constant_size != 0 && push_constant_debug.push_constant_size != len) {
-					print_line("eep");
-				}
-
-				push_constant_debug.push_constant_size = len;
-				push_constant_debug.push_constants_vk_stage |= shader_stage_masks[p_stages[i].shader_stage];
-				//print_line("Debug stage " + String(shader_stage_names[p_stages[i].shader_stage]) + " push constant size: " + itos(push_constant_debug.push_constant_size));
-			}
-		}
-
-
-		for (int j = 0; j < program.getNumUniformVariables(); j++) {
-			if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, push_constant, r_error)) {
-				return RID();
-			}
-		}
-
-		for (int j = 0; j < program.getNumUniformBlocks(); j++) {
-			if (!_uniform_add_binding(bindings, uniform_info, program.getUniformBlock(j), p_stages[i].shader_stage, push_constant, r_error)) {
-				return RID();
-			}
-		}
-
-		for (int j = 0; j < program.getNumBufferVariables(); j++) {
-			if (!_uniform_add_binding(bindings, uniform_info, program.getBufferVariable(j), p_stages[i].shader_stage, push_constant, r_error)) {
-				return RID();
-			}
-		}
-
-		for (int j = 0; j < program.getNumBufferBlocks(); j++) {
-			if (!_uniform_add_binding(bindings, uniform_info, program.getBufferBlock(j), p_stages[i].shader_stage, push_constant, r_error)) {
-				return RID();
-			}
-		}
-
-		if (p_stages[i].shader_stage == SHADER_STAGE_VERTEX) {
-			for (int j = 0; j < program.getNumPipeInputs(); j++) {
-				if (program.getPipeInput(i).getType()->getQualifier().hasLocation()) {
-					int location = program.getPipeInput(i).getType()->getQualifier().layoutLocation;
-
-					if (vertex_input_locations.find(location) == -1) {
-						vertex_input_locations.push_back(location);
-					}
-				}
-			}
-		}
-
-		if (p_stages[i].shader_stage == SHADER_STAGE_FRAGMENT) {
-
-			fragment_outputs = program.getNumPipeOutputs();
-		}
-
-#endif
-		std::vector<uint32_t> SpirV;
-		spv::SpvBuildLogger logger;
-		glslang::SpvOptions spvOptions;
-		glslang::GlslangToSpv(*program.getIntermediate(stages[p_stages[i].shader_stage]), SpirV, &logger, &spvOptions);
+		ERR_FAIL_COND_V_MSG(stages_processed & (1 << p_stages[i].shader_stage), RID(),
+				"Stage " + String(shader_stage_names[p_stages[i].shader_stage]) + " submitted more than once.");
 
 		{
 			SpvReflectShaderModule module;
-			SpvReflectResult result = spvReflectCreateShaderModule(SpirV.size() * sizeof(uint32_t), &SpirV[0], &module);
+			PoolVector<uint8_t>::Read spirv = p_stages[i].spir_v.read();
+			SpvReflectResult result = spvReflectCreateShaderModule(p_stages[i].spir_v.size(), spirv.ptr(), &module);
 			ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(),
 					"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed parsing shader.");
 
@@ -3941,8 +3689,6 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
 			spvReflectDestroyShaderModule(&module);
 		}
 
-		spirv_code.push_back(SpirV);
-
 		stages_processed |= (1 << p_stages[i].shader_stage);
 	}
 
@@ -3962,8 +3708,10 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
 		shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
 		shader_module_create_info.pNext = NULL;
 		shader_module_create_info.flags = 0;
-		shader_module_create_info.codeSize = spirv_code[i].size() * sizeof(uint32_t);
-		shader_module_create_info.pCode = &spirv_code[i][0];
+		shader_module_create_info.codeSize = p_stages[i].spir_v.size();
+		PoolVector<uint8_t>::Read r = p_stages[i].spir_v.read();
+
+		shader_module_create_info.pCode = (const uint32_t *)r.ptr();
 
 		VkShaderModule module;
 		VkResult res = vkCreateShaderModule(device, &shader_module_create_info, NULL, &module);
@@ -4087,14 +3835,7 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector<ShaderStageSou
 			vkDestroyDescriptorSetLayout(device, shader.sets[i].descriptor_set_layout, NULL);
 		}
 
-		if (r_error) {
-			*r_error = error_text;
-		}
-		if (r_error_stage) {
-			*r_error_stage = SHADER_STAGE_MAX;
-		}
-
-		return RID();
+		ERR_FAIL_V_MSG(RID(), error_text);
 	}
 
 	return shader_owner.make_rid(shader);

+ 3 - 4
drivers/vulkan/rendering_device_vulkan.h

@@ -5,7 +5,7 @@
 #include "core/os/thread_safe.h"
 #include "core/rid_owner.h"
 #include "servers/visual/rendering_device.h"
-#include "thirdparty/glslang/glslang/Public/ShaderLang.h"
+
 #ifdef DEBUG_ENABLED
 #define _DEBUG
 #endif
@@ -494,7 +494,6 @@ class RenderingDeviceVulkan : public RenderingDevice {
 	};
 
 	String _shader_uniform_debug(RID p_shader, int p_set = -1);
-	bool _uniform_add_binding(Vector<Vector<VkDescriptorSetLayoutBinding> > &bindings, Vector<Vector<UniformInfo> > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error);
 
 	RID_Owner<Shader> shader_owner;
 
@@ -608,7 +607,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
 	// was not supplied as intended.
 
 	struct RenderPipeline {
-		//Cached values for validation
+	//Cached values for validation
 #ifdef DEBUG_ENABLED
 		struct Validation {
 			FramebufferFormatID framebuffer_format;
@@ -853,7 +852,7 @@ public:
 	/**** SHADER ****/
 	/****************/
 
-	virtual RID shader_create_from_source(const Vector<ShaderStageSource> &p_stages, String *r_error = NULL, ShaderStage *r_error_stage = NULL, bool p_allow_cache = true);
+	virtual RID shader_create(const Vector<ShaderStageData> &p_stages);
 	virtual Vector<int> shader_get_vertex_input_locations_used(RID p_shader);
 
 	/*****************/

+ 2 - 0
main/main.cpp

@@ -1207,6 +1207,8 @@ error:
 
 Error Main::setup2(Thread::ID p_main_tid_override) {
 
+	preregister_module_types();
+
 	// Print engine name and version
 	print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE));
 

+ 11 - 1
methods.py

@@ -137,6 +137,7 @@ def detect_modules():
     includes_cpp = ""
     register_cpp = ""
     unregister_cpp = ""
+    preregister_cpp = ""
 
     files = glob.glob("modules/*")
     files.sort()  # so register_module_types does not change that often, and also plugins are registered in alphabetic order
@@ -154,6 +155,11 @@ def detect_modules():
                 register_cpp += '#ifdef MODULE_' + x.upper() + '_ENABLED\n'
                 register_cpp += '\tregister_' + x + '_types();\n'
                 register_cpp += '#endif\n'
+                preregister_cpp += '#ifdef MODULE_' + x.upper() + '_ENABLED\n'
+                preregister_cpp += '#ifdef MODULE_' + x.upper() + '_HAS_PREREGISTER\n'
+                preregister_cpp += '\tpreregister_' + x + '_types();\n'
+                preregister_cpp += '#endif\n'
+                preregister_cpp += '#endif\n'
                 unregister_cpp += '#ifdef MODULE_' + x.upper() + '_ENABLED\n'
                 unregister_cpp += '\tunregister_' + x + '_types();\n'
                 unregister_cpp += '#endif\n'
@@ -168,6 +174,10 @@ def detect_modules():
 
 %s
 
+void preregister_module_types() {
+%s
+}
+
 void register_module_types() {
 %s
 }
@@ -175,7 +185,7 @@ void register_module_types() {
 void unregister_module_types() {
 %s
 }
-""" % (includes_cpp, register_cpp, unregister_cpp)
+""" % (includes_cpp, preregister_cpp, register_cpp, unregister_cpp)
 
     # NOTE: It is safe to generate this file here, since this is still executed serially
     with open("modules/register_module_types.gen.cpp", "w") as f:

+ 68 - 0
modules/glslang/SCsub

@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+
+Import('env')
+Import('env_modules')
+
+env_glslang = env_modules.Clone()
+
+# Thirdparty source files
+# Not unbundled so far since not widespread as shared library
+thirdparty_dir = "#thirdparty/glslang/"
+thirdparty_sources = [
+"glslang/MachineIndependent/RemoveTree.cpp",
+"glslang/MachineIndependent/ParseHelper.cpp",
+"glslang/MachineIndependent/iomapper.cpp",
+"glslang/MachineIndependent/propagateNoContraction.cpp",
+"glslang/MachineIndependent/Intermediate.cpp",
+"glslang/MachineIndependent/linkValidate.cpp",
+"glslang/MachineIndependent/attribute.cpp",
+"glslang/MachineIndependent/Scan.cpp",
+"glslang/MachineIndependent/Initialize.cpp",
+"glslang/MachineIndependent/Constant.cpp",
+"glslang/MachineIndependent/reflection.cpp",
+"glslang/MachineIndependent/limits.cpp",
+"glslang/MachineIndependent/preprocessor/PpScanner.cpp",
+"glslang/MachineIndependent/preprocessor/PpTokens.cpp",
+"glslang/MachineIndependent/preprocessor/PpAtom.cpp",
+"glslang/MachineIndependent/preprocessor/PpContext.cpp",
+"glslang/MachineIndependent/preprocessor/Pp.cpp",
+"glslang/MachineIndependent/InfoSink.cpp",
+"glslang/MachineIndependent/intermOut.cpp",
+"glslang/MachineIndependent/SymbolTable.cpp",
+"glslang/MachineIndependent/glslang_tab.cpp",
+"glslang/MachineIndependent/pch.cpp",
+"glslang/MachineIndependent/Versions.cpp",
+"glslang/MachineIndependent/ShaderLang.cpp",
+"glslang/MachineIndependent/parseConst.cpp",
+"glslang/MachineIndependent/PoolAlloc.cpp",
+"glslang/MachineIndependent/ParseContextBase.cpp",
+"glslang/MachineIndependent/IntermTraverse.cpp",
+"glslang/GenericCodeGen/Link.cpp",
+"glslang/GenericCodeGen/CodeGen.cpp",
+"OGLCompilersDLL/InitializeDll.cpp",
+"SPIRV/InReadableOrder.cpp",
+"SPIRV/GlslangToSpv.cpp",
+"SPIRV/SpvBuilder.cpp",
+"SPIRV/SpvTools.cpp",
+"SPIRV/disassemble.cpp",
+"SPIRV/doc.cpp",
+"SPIRV/SPVRemapper.cpp",
+"SPIRV/SpvPostProcess.cpp",
+"SPIRV/Logger.cpp"
+]
+
+if (env["platform"]=="windows"):
+	thirdparty_sources.append("glslang/OSDependent/Windows/ossource.cpp")
+else:
+	thirdparty_sources.append("glslang/OSDependent/Unix/ossource.cpp")
+
+thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+
+env_glslang.add_source_files(env.modules_sources, thirdparty_sources)
+# Godot's own source files
+env_glslang.add_source_files(env.modules_sources, "*.cpp")
+env.Prepend(CPPPATH=[thirdparty_dir])
+
+
+

+ 5 - 0
modules/glslang/config.py

@@ -0,0 +1,5 @@
+def can_build(env, platform):
+    return True
+
+def configure(env):
+    pass

+ 240 - 0
modules/glslang/register_types.cpp

@@ -0,0 +1,240 @@
+/*************************************************************************/
+/*  register_types.cpp                                                   */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "register_types.h"
+#include "servers/visual/rendering_device.h"
+
+#include "thirdparty/glslang/SPIRV/GlslangToSpv.h"
+#include "thirdparty/glslang/glslang/Include/Types.h"
+#include "thirdparty/glslang/glslang/Public/ShaderLang.h"
+
+static const TBuiltInResource default_builtin_resource = {
+	.maxLights = 32,
+	.maxClipPlanes = 6,
+	.maxTextureUnits = 32,
+	.maxTextureCoords = 32,
+	.maxVertexAttribs = 64,
+	.maxVertexUniformComponents = 4096,
+	.maxVaryingFloats = 64,
+	.maxVertexTextureImageUnits = 32,
+	.maxCombinedTextureImageUnits = 80,
+	.maxTextureImageUnits = 32,
+	.maxFragmentUniformComponents = 4096,
+	.maxDrawBuffers = 32,
+	.maxVertexUniformVectors = 128,
+	.maxVaryingVectors = 8,
+	.maxFragmentUniformVectors = 16,
+	.maxVertexOutputVectors = 16,
+	.maxFragmentInputVectors = 15,
+	.minProgramTexelOffset = -8,
+	.maxProgramTexelOffset = 7,
+	.maxClipDistances = 8,
+	.maxComputeWorkGroupCountX = 65535,
+	.maxComputeWorkGroupCountY = 65535,
+	.maxComputeWorkGroupCountZ = 65535,
+	.maxComputeWorkGroupSizeX = 1024,
+	.maxComputeWorkGroupSizeY = 1024,
+	.maxComputeWorkGroupSizeZ = 64,
+	.maxComputeUniformComponents = 1024,
+	.maxComputeTextureImageUnits = 16,
+	.maxComputeImageUniforms = 8,
+	.maxComputeAtomicCounters = 8,
+	.maxComputeAtomicCounterBuffers = 1,
+	.maxVaryingComponents = 60,
+	.maxVertexOutputComponents = 64,
+	.maxGeometryInputComponents = 64,
+	.maxGeometryOutputComponents = 128,
+	.maxFragmentInputComponents = 128,
+	.maxImageUnits = 8,
+	.maxCombinedImageUnitsAndFragmentOutputs = 8,
+	.maxCombinedShaderOutputResources = 8,
+	.maxImageSamples = 0,
+	.maxVertexImageUniforms = 0,
+	.maxTessControlImageUniforms = 0,
+	.maxTessEvaluationImageUniforms = 0,
+	.maxGeometryImageUniforms = 0,
+	.maxFragmentImageUniforms = 8,
+	.maxCombinedImageUniforms = 8,
+	.maxGeometryTextureImageUnits = 16,
+	.maxGeometryOutputVertices = 256,
+	.maxGeometryTotalOutputComponents = 1024,
+	.maxGeometryUniformComponents = 1024,
+	.maxGeometryVaryingComponents = 64,
+	.maxTessControlInputComponents = 128,
+	.maxTessControlOutputComponents = 128,
+	.maxTessControlTextureImageUnits = 16,
+	.maxTessControlUniformComponents = 1024,
+	.maxTessControlTotalOutputComponents = 4096,
+	.maxTessEvaluationInputComponents = 128,
+	.maxTessEvaluationOutputComponents = 128,
+	.maxTessEvaluationTextureImageUnits = 16,
+	.maxTessEvaluationUniformComponents = 1024,
+	.maxTessPatchComponents = 120,
+	.maxPatchVertices = 32,
+	.maxTessGenLevel = 64,
+	.maxViewports = 16,
+	.maxVertexAtomicCounters = 0,
+	.maxTessControlAtomicCounters = 0,
+	.maxTessEvaluationAtomicCounters = 0,
+	.maxGeometryAtomicCounters = 0,
+	.maxFragmentAtomicCounters = 8,
+	.maxCombinedAtomicCounters = 8,
+	.maxAtomicCounterBindings = 1,
+	.maxVertexAtomicCounterBuffers = 0,
+	.maxTessControlAtomicCounterBuffers = 0,
+	.maxTessEvaluationAtomicCounterBuffers = 0,
+	.maxGeometryAtomicCounterBuffers = 0,
+	.maxFragmentAtomicCounterBuffers = 1,
+	.maxCombinedAtomicCounterBuffers = 1,
+	.maxAtomicCounterBufferSize = 16384,
+	.maxTransformFeedbackBuffers = 4,
+	.maxTransformFeedbackInterleavedComponents = 64,
+	.maxCullDistances = 8,
+	.maxCombinedClipAndCullDistances = 8,
+	.maxSamples = 4,
+	.limits = {
+			.nonInductiveForLoops = 1,
+			.whileLoops = 1,
+			.doWhileLoops = 1,
+			.generalUniformIndexing = 1,
+			.generalAttributeMatrixVectorIndexing = 1,
+			.generalVaryingIndexing = 1,
+			.generalSamplerIndexing = 1,
+			.generalVariableIndexing = 1,
+			.generalConstantMatrixVectorIndexing = 1,
+	}
+};
+
+
+
+static PoolVector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage, const String &p_source_code, RenderingDevice::ShaderLanguage p_language, String *r_error) {
+
+	PoolVector<uint8_t> ret;
+
+	ERR_FAIL_COND_V(p_language==RenderingDevice::SHADER_LANGUAGE_HLSL,ret);
+
+	// initialize in case it's not initialized. This is done once per thread
+	// and it's safe to call multiple times
+	glslang::InitializeProcess();
+	EShLanguage stages[RenderingDevice::SHADER_STAGE_MAX] = {
+		EShLangVertex,
+		EShLangFragment,
+		EShLangTessControl,
+		EShLangTessEvaluation,
+		EShLangCompute
+	};
+
+	int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100
+
+	glslang::EShTargetClientVersion VulkanClientVersion = glslang::EShTargetVulkan_1_0;
+	glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_0;
+	glslang::TShader::ForbidIncluder includer;
+
+	glslang::TShader shader(stages[p_stage]);
+	CharString cs = p_source_code.ascii();
+	const char *cs_strings = cs.get_data();
+
+	shader.setStrings(&cs_strings, 1);
+	shader.setEnvInput(glslang::EShSourceGlsl, stages[p_stage], glslang::EShClientVulkan, ClientInputSemanticsVersion);
+	shader.setEnvClient(glslang::EShClientVulkan, VulkanClientVersion);
+	shader.setEnvTarget(glslang::EShTargetSpv, TargetVersion);
+
+	EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
+	const int DefaultVersion = 100;
+	std::string pre_processed_code;
+
+		//preprocess
+	if (!shader.preprocess(&default_builtin_resource, DefaultVersion, ENoProfile, false, false, messages, &pre_processed_code, includer)) {
+
+		if (r_error) {
+			(*r_error) = "Failed pre-process:\n";
+			(*r_error) += shader.getInfoLog();
+			(*r_error) += "\n";
+			(*r_error) += shader.getInfoDebugLog();
+		}
+
+		return ret;
+	}
+	//set back..
+	cs_strings = pre_processed_code.c_str();
+	shader.setStrings(&cs_strings, 1);
+
+	//parse
+	if (!shader.parse(&default_builtin_resource, DefaultVersion, false, messages)) {
+		if (r_error) {
+			(*r_error) = "Failed parse:\n";
+			(*r_error) += shader.getInfoLog();
+			(*r_error) += "\n";
+			(*r_error) += shader.getInfoDebugLog();
+		}
+		return ret;
+	}
+
+	//link
+	glslang::TProgram program;
+	program.addShader(&shader);
+
+	if (!program.link(messages)) {
+		if (r_error) {
+			(*r_error) = "Failed link:\n";
+			(*r_error) += program.getInfoLog();
+			(*r_error) += "\n";
+			(*r_error) += program.getInfoDebugLog();
+		}
+
+		return ret;
+	}
+
+
+	std::vector<uint32_t> SpirV;
+	spv::SpvBuildLogger logger;
+	glslang::SpvOptions spvOptions;
+	glslang::GlslangToSpv(*program.getIntermediate(stages[p_stage]), SpirV, &logger, &spvOptions);
+
+
+	ret.resize(SpirV.size() * sizeof(uint32_t));
+	{
+		PoolVector<uint8_t>::Write w = ret.write();
+		copymem(w.ptr(),&SpirV[0],SpirV.size()*sizeof(uint32_t));
+	}
+
+	return ret;
+}
+
+void preregister_glslang_types() {
+	RenderingDevice::shader_set_compile_function(_compile_shader_glsl);
+}
+
+void register_glslang_types() {
+}
+void unregister_glslang_types() {
+
+
+}

+ 34 - 0
modules/glslang/register_types.h

@@ -0,0 +1,34 @@
+/*************************************************************************/
+/*  register_types.h                                                     */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#define MODULE_GLSLANG_HAS_PREREGISTER
+void preregister_glslang_types();
+void register_glslang_types();
+void unregister_glslang_types();

+ 1 - 0
modules/register_module_types.h

@@ -31,6 +31,7 @@
 #ifndef REGISTER_MODULE_TYPES_H
 #define REGISTER_MODULE_TYPES_H
 
+void preregister_module_types();
 void register_module_types();
 void unregister_module_types();
 

+ 8 - 8
servers/visual/rasterizer_rd/rasterizer_rd.cpp

@@ -61,9 +61,9 @@ void RasterizerRD::end_frame(bool p_swap_buffers) {
 void RasterizerRD::initialize() {
 
 	{ //create framebuffer copy shader
-		RenderingDevice::ShaderStageSource vert;
+		RenderingDevice::ShaderStageData vert;
 		vert.shader_stage = RenderingDevice::SHADER_STAGE_VERTEX;
-		vert.shader_source =
+		vert.spir_v = RenderingDevice::get_singleton()->shader_compile_from_source(RenderingDevice::SHADER_STAGE_VERTEX,
 				"#version 450\n"
 				"layout(push_constant, binding = 0, std140) uniform Pos { vec4 dst_rect; } pos;\n"
 				"layout(location =0) out vec2 uv;\n"
@@ -72,22 +72,22 @@ void RasterizerRD::initialize() {
 				" uv = base_arr[gl_VertexIndex];\n"
 				" vec2 vtx = pos.dst_rect.xy+uv*pos.dst_rect.zw;\n"
 				" gl_Position = vec4(vtx * 2.0 - 1.0,0.0,1.0);\n"
-				"}\n";
+				"}\n");
 
-		RenderingDevice::ShaderStageSource frag;
+		RenderingDevice::ShaderStageData frag;
 		frag.shader_stage = RenderingDevice::SHADER_STAGE_FRAGMENT;
-		frag.shader_source =
+		frag.spir_v =RenderingDevice::get_singleton()->shader_compile_from_source(RenderingDevice::SHADER_STAGE_FRAGMENT,
 				"#version 450\n"
 				"layout (location = 0) in vec2 uv;\n"
 				"layout (location = 0) out vec4 color;\n"
 				"layout (binding = 0) uniform sampler2D src_rt;\n"
-				"void main() { color=texture(src_rt,uv); }\n";
+				"void main() { color=texture(src_rt,uv); }\n");
 
-		Vector<RenderingDevice::ShaderStageSource> source;
+		Vector<RenderingDevice::ShaderStageData> source;
 		source.push_back(vert);
 		source.push_back(frag);
 		String error;
-		copy_viewports_rd_shader = RD::get_singleton()->shader_create_from_source(source, &error);
+		copy_viewports_rd_shader = RD::get_singleton()->shader_create(source);
 		if (!copy_viewports_rd_shader.is_valid()) {
 			print_line("failed compilation: " + error);
 		} else {

+ 43 - 22
servers/visual/rasterizer_rd/shader_rd.cpp

@@ -171,7 +171,12 @@ void ShaderRD::_compile_version(Version *p_version) {
 
 	for (int i = 0; i < variant_defines.size(); i++) {
 
-		Vector<RD::ShaderStageSource> stages;
+		Vector<RD::ShaderStageData> stages;
+
+		String error;
+		String current_source;
+		RD::ShaderStage current_stage = RD::SHADER_STAGE_VERTEX;
+		bool build_ok=true;
 
 		{
 			//vertex stage
@@ -201,15 +206,21 @@ void ShaderRD::_compile_version(Version *p_version) {
 
 			builder.append(vertex_code3.get_data()); //fourth of vertex
 
-			RD::ShaderStageSource stage;
-			stage.shader_source = builder.as_string();
-			stage.shader_stage = RD::SHADER_STAGE_VERTEX;
+			current_source = builder.as_string();
+			RD::ShaderStageData stage;
+			stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_VERTEX,current_source,RD::SHADER_LANGUAGE_GLSL,&error);
+			if (stage.spir_v.size()==0) {
+				build_ok=false;
+			} else {
 
-			stages.push_back(stage);
+				stage.shader_stage = RD::SHADER_STAGE_VERTEX;
+				stages.push_back(stage);
+			}
 		}
 
-		{
+		if (build_ok){
 			//fragment stage
+			current_stage =RD::SHADER_STAGE_FRAGMENT;
 
 			StringBuilder builder;
 
@@ -240,29 +251,26 @@ void ShaderRD::_compile_version(Version *p_version) {
 
 			builder.append(fragment_code4.get_data()); //fourth part of fragment
 
-			RD::ShaderStageSource stage;
-			stage.shader_source = builder.as_string();
-			stage.shader_stage = RD::SHADER_STAGE_FRAGMENT;
-#if 0
-			if (stage.shader_stage == RD::SHADER_STAGE_FRAGMENT && p_version->uniforms.length()) {
-				print_line(stage.shader_source.get_with_code_lines());
+			current_source = builder.as_string();
+			RD::ShaderStageData stage;
+			stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_FRAGMENT,current_source,RD::SHADER_LANGUAGE_GLSL,&error);
+			if (stage.spir_v.size()==0) {
+				build_ok=false;
+			} else {
+
+				stage.shader_stage = RD::SHADER_STAGE_FRAGMENT;
+				stages.push_back(stage);
 			}
-#endif
-			stages.push_back(stage);
+
 		}
 
-		String error;
-		RD::ShaderStage error_stage;
-		RID shader = RD::get_singleton()->shader_create_from_source(stages, &error, &error_stage);
 
-		if (shader.is_null() && error != String()) {
-			ERR_PRINT("Error compiling shader, variant #" + itos(i) + " (" + variant_defines[i].get_data() + ").");
+		if (!build_ok) {
+			ERR_PRINT("Error compiling " + String(current_stage == RD::SHADER_STAGE_VERTEX ? "Vertex" : "Fragment") + " shader, variant #" + itos(i) + " (" + variant_defines[i].get_data() + ").");
 			ERR_PRINT(error);
 
 #ifdef DEBUG_ENABLED
-			if (error_stage < RD::SHADER_STAGE_MAX) {
-				ERR_PRINT("code:\n" + stages[error_stage].shader_source.get_with_code_lines());
-			}
+			ERR_PRINT("code:\n" + current_source.get_with_code_lines());
 #endif
 			//clear versions if they exist
 			for (int j = 0; j < i; j++) {
@@ -274,6 +282,19 @@ void ShaderRD::_compile_version(Version *p_version) {
 			return;
 		}
 
+		RID shader = RD::get_singleton()->shader_create(stages);
+
+		if (shader.is_null()) {
+			//clear versions if they exist
+			for (int j = 0; j < i; j++) {
+				RD::get_singleton()->free(p_version->variants[j]);
+			}
+
+			memdelete_arr(p_version->variants);
+			p_version->variants = NULL;
+			return;
+		}
+
 		p_version->variants[i] = shader;
 	}
 

+ 28 - 3
servers/visual/rendering_device.cpp

@@ -1,13 +1,38 @@
 #include "rendering_device.h"
 
-
-RenderingDevice *RenderingDevice::singleton=NULL;
+RenderingDevice *RenderingDevice::singleton = NULL;
 
 RenderingDevice *RenderingDevice::get_singleton() {
 	return singleton;
 }
 
+RenderingDevice::ShaderCompileFunction RenderingDevice::compile_function = NULL;
+RenderingDevice::ShaderCacheFunction RenderingDevice::cache_function = NULL;
+
+void RenderingDevice::shader_set_compile_function(ShaderCompileFunction p_function) {
+	compile_function = p_function;
+}
+void RenderingDevice::shader_set_cache_function(ShaderCacheFunction p_function) {
+	cache_function = p_function;
+}
+
+PoolVector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, bool p_allow_cache) {
+	if (p_allow_cache && cache_function) {
+		PoolVector<uint8_t> cache = cache_function(p_stage, p_source_code, p_language);
+		if (cache.size()) {
+			return cache;
+		}
+	}
+
+	ERR_FAIL_COND_V(!compile_function, PoolVector<uint8_t>());
+
+	return compile_function(p_stage, p_source_code, p_language, r_error);
+}
+
 RenderingDevice::RenderingDevice() {
 
-	singleton=this;
+	ShaderCompileFunction compile_function;
+	ShaderCacheFunction cache_function;
+
+	singleton = this;
 }

+ 35 - 17
servers/visual/rendering_device.h

@@ -5,6 +5,32 @@
 
 class RenderingDevice : public Object {
 	GDCLASS(RenderingDevice, Object)
+public:
+	enum ShaderStage {
+		SHADER_STAGE_VERTEX,
+		SHADER_STAGE_FRAGMENT,
+		SHADER_STAGE_TESSELATION_CONTROL,
+		SHADER_STAGE_TESSELATION_EVALUATION,
+		SHADER_STAGE_COMPUTE,
+		SHADER_STAGE_MAX,
+		SHADER_STAGE_VERTEX_BIT = (1 << SHADER_STAGE_VERTEX),
+		SHADER_STAGE_FRAGMENT_BIT = (1 << SHADER_STAGE_FRAGMENT),
+		SHADER_STAGE_TESSELATION_CONTROL_BIT = (1 << SHADER_STAGE_TESSELATION_CONTROL),
+		SHADER_STAGE_TESSELATION_EVALUATION_BIT = (1 << SHADER_STAGE_TESSELATION_EVALUATION),
+		SHADER_STAGE_COMPUTE_BIT = (1 << SHADER_STAGE_COMPUTE),
+	};
+
+	enum ShaderLanguage {
+		SHADER_LANGUAGE_GLSL,
+		SHADER_LANGUAGE_HLSL
+	};
+
+	typedef PoolVector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error);
+	typedef PoolVector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language);
+
+private:
+	static ShaderCompileFunction compile_function;
+	static ShaderCacheFunction cache_function;
 
 	static RenderingDevice *singleton;
 
@@ -497,29 +523,21 @@ public:
 	/**** SHADER ****/
 	/****************/
 
-	enum ShaderStage {
-		SHADER_STAGE_VERTEX,
-		SHADER_STAGE_FRAGMENT,
-		SHADER_STAGE_TESSELATION_CONTROL,
-		SHADER_STAGE_TESSELATION_EVALUATION,
-		SHADER_STAGE_COMPUTE,
-		SHADER_STAGE_MAX,
-		SHADER_STAGE_VERTEX_BIT = (1 << SHADER_STAGE_VERTEX),
-		SHADER_STAGE_FRAGMENT_BIT = (1 << SHADER_STAGE_FRAGMENT),
-		SHADER_STAGE_TESSELATION_CONTROL_BIT = (1 << SHADER_STAGE_TESSELATION_CONTROL),
-		SHADER_STAGE_TESSELATION_EVALUATION_BIT = (1 << SHADER_STAGE_TESSELATION_EVALUATION),
-		SHADER_STAGE_COMPUTE_BIT = (1 << SHADER_STAGE_COMPUTE),
-	};
+	virtual PoolVector<uint8_t> shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = NULL, bool p_allow_cache = true);
 
-	struct ShaderStageSource {
+	static void shader_set_compile_function(ShaderCompileFunction p_function);
+	static void shader_set_cache_function(ShaderCacheFunction p_function);
+
+	struct ShaderStageData {
 		ShaderStage shader_stage;
-		String shader_source;
-		ShaderStageSource() {
+		PoolVector<uint8_t> spir_v;
+
+		ShaderStageData() {
 			shader_stage = SHADER_STAGE_VERTEX;
 		}
 	};
 
-	virtual RID shader_create_from_source(const Vector<ShaderStageSource> &p_stages, String *r_error = NULL, ShaderStage *r_error_stage = NULL, bool p_allow_cache = true) = 0;
+	virtual RID shader_create(const Vector<ShaderStageData> &p_stages) = 0;
 	virtual Vector<int> shader_get_vertex_input_locations_used(RID p_shader) = 0;
 
 	/******************/