Browse Source

More work on the parser

Panagiotis Christopoulos Charitos 6 years ago
parent
commit
c51b983a6a

+ 9 - 0
src/anki/gr/Enums.h

@@ -499,6 +499,15 @@ enum class ShaderVariableDataType : U8
 	NUMERICS_FIRST = INT,
 	NUMERICS_LAST = MAT4,
 
+	NUMERIC_1_COMPONENT_FIRST = INT,
+	NUMERIC_1_COMPONENT_LAST = FLOAT,
+	NUMERIC_2_COMPONENT_FIRST = IVEC2,
+	NUMERIC_2_COMPONENT_LAST = VEC2,
+	NUMERIC_3_COMPONENT_FIRST = IVEC3,
+	NUMERIC_3_COMPONENT_LAST = VEC3,
+	NUMERIC_4_COMPONENT_FIRST = IVEC4,
+	NUMERIC_4_COMPONENT_LAST = VEC4,
+
 	MATRIX_FIRST = MAT3,
 	MATRIX_LAST = MAT4,
 

+ 145 - 0
src/anki/shader_compiler/Glslang.cpp

@@ -0,0 +1,145 @@
+// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/shader_compiler/Glslang.h>
+
+namespace anki
+{
+
+static TBuiltInResource setGlslangLimits()
+{
+	TBuiltInResource c = {};
+
+	c.maxLights = 32;
+	c.maxClipPlanes = 6;
+	c.maxTextureUnits = 32;
+	c.maxTextureCoords = 32;
+	c.maxVertexAttribs = 64;
+	c.maxVertexUniformComponents = 4096;
+	c.maxVaryingFloats = 64;
+	c.maxVertexTextureImageUnits = 32;
+	c.maxCombinedTextureImageUnits = 80;
+	c.maxTextureImageUnits = 32;
+	c.maxFragmentUniformComponents = 4096;
+	c.maxDrawBuffers = 32;
+	c.maxVertexUniformVectors = 128;
+	c.maxVaryingVectors = 8;
+	c.maxFragmentUniformVectors = 16;
+	c.maxVertexOutputVectors = 16;
+	c.maxFragmentInputVectors = 15;
+	c.minProgramTexelOffset = -8;
+	c.maxProgramTexelOffset = 7;
+	c.maxClipDistances = 8;
+	c.maxComputeWorkGroupCountX = 65535;
+	c.maxComputeWorkGroupCountY = 65535;
+	c.maxComputeWorkGroupCountZ = 65535;
+	c.maxComputeWorkGroupSizeX = 1024;
+	c.maxComputeWorkGroupSizeY = 1024;
+	c.maxComputeWorkGroupSizeZ = 64;
+	c.maxComputeUniformComponents = 1024;
+	c.maxComputeTextureImageUnits = 16;
+	c.maxComputeImageUniforms = 8;
+	c.maxComputeAtomicCounters = 8;
+	c.maxComputeAtomicCounterBuffers = 1;
+	c.maxVaryingComponents = 60;
+	c.maxVertexOutputComponents = 64;
+	c.maxGeometryInputComponents = 64;
+	c.maxGeometryOutputComponents = 128;
+	c.maxFragmentInputComponents = 128;
+	c.maxImageUnits = 8;
+	c.maxCombinedImageUnitsAndFragmentOutputs = 8;
+	c.maxCombinedShaderOutputResources = 8;
+	c.maxImageSamples = 0;
+	c.maxVertexImageUniforms = 0;
+	c.maxTessControlImageUniforms = 0;
+	c.maxTessEvaluationImageUniforms = 0;
+	c.maxGeometryImageUniforms = 0;
+	c.maxFragmentImageUniforms = 8;
+	c.maxCombinedImageUniforms = 8;
+	c.maxGeometryTextureImageUnits = 16;
+	c.maxGeometryOutputVertices = 256;
+	c.maxGeometryTotalOutputComponents = 1024;
+	c.maxGeometryUniformComponents = 1024;
+	c.maxGeometryVaryingComponents = 64;
+	c.maxTessControlInputComponents = 128;
+	c.maxTessControlOutputComponents = 128;
+	c.maxTessControlTextureImageUnits = 16;
+	c.maxTessControlUniformComponents = 1024;
+	c.maxTessControlTotalOutputComponents = 4096;
+	c.maxTessEvaluationInputComponents = 128;
+	c.maxTessEvaluationOutputComponents = 128;
+	c.maxTessEvaluationTextureImageUnits = 16;
+	c.maxTessEvaluationUniformComponents = 1024;
+	c.maxTessPatchComponents = 120;
+	c.maxPatchVertices = 32;
+	c.maxTessGenLevel = 64;
+	c.maxViewports = 16;
+	c.maxVertexAtomicCounters = 0;
+	c.maxTessControlAtomicCounters = 0;
+	c.maxTessEvaluationAtomicCounters = 0;
+	c.maxGeometryAtomicCounters = 0;
+	c.maxFragmentAtomicCounters = 8;
+	c.maxCombinedAtomicCounters = 8;
+	c.maxAtomicCounterBindings = 1;
+	c.maxVertexAtomicCounterBuffers = 0;
+	c.maxTessControlAtomicCounterBuffers = 0;
+	c.maxTessEvaluationAtomicCounterBuffers = 0;
+	c.maxGeometryAtomicCounterBuffers = 0;
+	c.maxFragmentAtomicCounterBuffers = 1;
+	c.maxCombinedAtomicCounterBuffers = 1;
+	c.maxAtomicCounterBufferSize = 16384;
+	c.maxTransformFeedbackBuffers = 4;
+	c.maxTransformFeedbackInterleavedComponents = 64;
+	c.maxCullDistances = 8;
+	c.maxCombinedClipAndCullDistances = 8;
+	c.maxSamples = 4;
+
+	c.limits.nonInductiveForLoops = 1;
+	c.limits.whileLoops = 1;
+	c.limits.doWhileLoops = 1;
+	c.limits.generalUniformIndexing = 1;
+	c.limits.generalAttributeMatrixVectorIndexing = 1;
+	c.limits.generalVaryingIndexing = 1;
+	c.limits.generalSamplerIndexing = 1;
+	c.limits.generalVariableIndexing = 1;
+	c.limits.generalConstantMatrixVectorIndexing = 1;
+
+	return c;
+}
+
+TBuiltInResource GLSLANG_LIMITS = setGlslangLimits();
+
+EShLanguage ankiToGlslangShaderType(ShaderType shaderType)
+{
+	EShLanguage gslangShader;
+	switch(shaderType)
+	{
+	case ShaderType::VERTEX:
+		gslangShader = EShLangVertex;
+		break;
+	case ShaderType::FRAGMENT:
+		gslangShader = EShLangFragment;
+		break;
+	case ShaderType::TESSELLATION_EVALUATION:
+		gslangShader = EShLangTessEvaluation;
+		break;
+	case ShaderType::TESSELLATION_CONTROL:
+		gslangShader = EShLangTessControl;
+		break;
+	case ShaderType::GEOMETRY:
+		gslangShader = EShLangGeometry;
+		break;
+	case ShaderType::COMPUTE:
+		gslangShader = EShLangCompute;
+		break;
+	default:
+		ANKI_ASSERT(0);
+		gslangShader = EShLangCount;
+	};
+
+	return gslangShader;
+}
+
+} // end namespace anki

+ 29 - 0
src/anki/shader_compiler/Glslang.h

@@ -0,0 +1,29 @@
+// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/gr/Enums.h>
+
+#if ANKI_COMPILER_GCC_COMPATIBLE
+#	pragma GCC diagnostic push
+#	pragma GCC diagnostic ignored "-Wundef"
+#	pragma GCC diagnostic ignored "-Wconversion"
+#endif
+#include <glslang/Public/ShaderLang.h>
+#include <glslang/SPIRV/GlslangToSpv.h>
+#include <glslang/StandAlone/DirStackFileIncluder.h>
+#if ANKI_COMPILER_GCC_COMPATIBLE
+#	pragma GCC diagnostic pop
+#endif
+
+namespace anki
+{
+
+extern TBuiltInResource GLSLANG_LIMITS;
+
+EShLanguage ankiToGlslangShaderType(ShaderType shaderType);
+
+} // end namespace anki

+ 169 - 8
src/anki/shader_compiler/ShaderProgramParser.cpp

@@ -20,6 +20,54 @@ namespace anki
 static const Array<CString, U32(ShaderType::COUNT)> SHADER_STAGE_NAMES = {
 	{"VERTEX", "TESSELLATION_CONTROL", "TESSELLATION_EVALUATION", "GEOMETRY", "FRAGMENT", "COMPUTE"}};
 
+static const char* SHADER_HEADER = R"(#version 450 core
+#define ANKI_BACKEND_MINOR %u
+#define ANKI_BACKEND_MAJOR %u
+#define ANKI_VENDOR_%s 1
+
+#define gl_VertexID gl_VertexIndex
+#define gl_InstanceID gl_InstanceIndex
+
+#extension GL_EXT_control_flow_attributes : require
+#define ANKI_UNROLL [[unroll]]
+#define ANKI_LOOP [[dont_unroll]]
+#define ANKI_BRANCH [[branch]]
+#define ANKI_FLATTEN [[flatten]]
+
+#extension GL_KHR_shader_subgroup_vote : require
+#extension GL_KHR_shader_subgroup_ballot : require
+#extension GL_KHR_shader_subgroup_shuffle : require
+#extension GL_KHR_shader_subgroup_arithmetic : require
+
+#extension GL_EXT_samplerless_texture_functions : require
+#extension GL_EXT_shader_image_load_formatted : require
+#extension GL_EXT_nonuniform_qualifier : enable
+
+#define ANKI_MAX_BINDLESS_TEXTURES %u
+#define ANKI_MAX_BINDLESS_IMAGES %u
+
+#define F32 float
+#define Vec2 vec2
+#define Vec3 vec3
+#define Vec4 vec4
+
+#define U32 uint
+#define UVec2 uvec2
+#define UVec3 uvec3
+#define UVec4 uvec4
+
+#define I32 int
+#define IVec2 ivec2
+#define IVec3 ivec3
+#define IVec4 ivec4
+
+#define Mat3 mat3
+#define Mat4 mat4
+#define Mat3x4 mat3x4
+
+#define Bool bool
+)";
+
 static ANKI_USE_RESULT Error computeShaderVariableDataType(const CString& str, ShaderVariableDataType& out)
 {
 	Error err = Error::NONE;
@@ -105,6 +153,69 @@ static ANKI_USE_RESULT Error computeShaderVariableDataType(const CString& str, S
 	return err;
 }
 
+static U32 computeSpecConstantIdsRequired(ShaderVariableDataType type)
+{
+	U32 out;
+	if(type >= ShaderVariableDataType::NUMERIC_1_COMPONENT_FIRST
+		&& type <= ShaderVariableDataType::NUMERIC_1_COMPONENT_LAST)
+	{
+		out = 1;
+	}
+	else if(type >= ShaderVariableDataType::NUMERIC_2_COMPONENT_FIRST
+			&& type <= ShaderVariableDataType::NUMERIC_2_COMPONENT_LAST)
+	{
+		out = 2;
+	}
+	else if(type >= ShaderVariableDataType::NUMERIC_3_COMPONENT_FIRST
+			&& type <= ShaderVariableDataType::NUMERIC_3_COMPONENT_LAST)
+	{
+		out = 3;
+	}
+	else if(type >= ShaderVariableDataType::NUMERIC_4_COMPONENT_FIRST
+			&& type <= ShaderVariableDataType::NUMERIC_4_COMPONENT_LAST)
+	{
+		out = 4;
+	}
+	else
+	{
+		out = MAX_U32;
+	}
+
+	return out;
+}
+
+/// 0: is int, 1: is uint, 2: is float
+static U32 shaderVariableScalarType(ShaderVariableDataType type)
+{
+	U32 out;
+	switch(type)
+	{
+	case ShaderVariableDataType::INT:
+	case ShaderVariableDataType::IVEC2:
+	case ShaderVariableDataType::IVEC3:
+	case ShaderVariableDataType::IVEC4:
+		out = 0;
+		break;
+	case ShaderVariableDataType::UINT:
+	case ShaderVariableDataType::UVEC2:
+	case ShaderVariableDataType::UVEC3:
+	case ShaderVariableDataType::UVEC4:
+		out = 1;
+		break;
+	case ShaderVariableDataType::FLOAT:
+	case ShaderVariableDataType::VEC2:
+	case ShaderVariableDataType::VEC3:
+	case ShaderVariableDataType::VEC4:
+		out = 2;
+		break;
+	default:
+		ANKI_ASSERT(0);
+		out = MAX_U32;
+		break;
+	}
+	return out;
+}
+
 static ANKI_USE_RESULT Error preprocessCommon(CString in, StringAuto& out)
 {
 	glslang::TShader shader(EShLangVertex);
@@ -347,7 +458,7 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
 	const Bool isTexture = input.m_dataType >= ShaderVariableDataType::TEXTURE_FIRST
 						   && input.m_dataType <= ShaderVariableDataType::TEXTURE_LAST;
 
-	if(input.m_specConstId != MAX_U32)
+	if(isConst)
 	{
 		// Const
 
@@ -357,20 +468,58 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
 			ANKI_PP_ERROR_MALFORMED();
 		}
 
+		const U32 vecComponents = computeSpecConstantIdsRequired(input.m_dataType);
+		if(vecComponents == MAX_U32)
+		{
+			ANKI_PP_ERROR_MALFORMED_MSG("Type can't be const");
+		}
+
+		const U32 scalarType = shaderVariableScalarType(input.m_dataType);
+
 		// Add an tag for later pre-processing (when trying to see if the variable is present)
 		m_codeLines.pushBackSprintf("//_anki_input_pesent %s", input.m_name.cstr());
 
 		m_globalsLines.pushBackSprintf("#if _ANKI_ACTIVATE_INPUT_%s", input.m_name.cstr());
 		m_globalsLines.pushBackSprintf("#define %s_DEFINED 1", input.m_name.cstr());
 
-		// TODO add vector support
+		const Array<CString, 3> typeNames = {{"I32", "I32", "F32"}};
 
-		m_globalsLines.pushBackSprintf("layout(constant_id = %u) const %s %s = %s(0);",
-			input.m_specConstId,
-			dataTypeStr.cstr(),
-			input.m_name.cstr(),
-			dataTypeStr.cstr(),
-			input.m_name.cstr());
+		input.m_specConstId = m_specConstIdx;
+
+		StringAuto inputDeclaration(m_alloc);
+		for(U32 comp = 0; comp < vecComponents; ++comp)
+		{
+			m_globalsLines.pushBackSprintf("layout(constant_id = %u) const %s _anki_const_%s_%u = %s(0);",
+				m_specConstIdx,
+				typeNames[scalarType].cstr(),
+				input.m_name.cstr(),
+				comp,
+				typeNames[scalarType].cstr());
+
+			if(comp == 0)
+			{
+				inputDeclaration.sprintf("const %s = %s(_anki_const_%s_%u",
+					dataTypeStr.cstr(),
+					dataTypeStr.cstr(),
+					input.m_name.cstr(),
+					comp);
+			}
+			else
+			{
+				StringAuto tmp(m_alloc);
+				tmp.sprintf(", _anki_const_%s_%u", input.m_name.cstr(), comp);
+				inputDeclaration.append(tmp);
+			}
+
+			if(comp == vecComponents - 1)
+			{
+				inputDeclaration.append(");");
+			}
+
+			++m_specConstIdx;
+		}
+
+		m_globalsLines.pushBack(inputDeclaration);
 
 		m_globalsLines.pushBack("#else");
 		m_globalsLines.pushBackSprintf("#define %s_DEFINED 0", input.m_name.cstr());
@@ -915,11 +1064,22 @@ Error ShaderProgramParser::generateSource(
 			StringAuto(m_alloc).sprintf("#define %s %d\n", state.m_mutator->m_name.cstr(), state.m_value));
 	}
 
+	// Create the header
+	StringAuto header(m_alloc);
+	header.sprintf(SHADER_HEADER,
+		m_backendMinor,
+		m_backendMinor,
+		GPU_VENDOR_STR[m_gpuVendor].cstr(),
+		MAX_BINDLESS_TEXTURES,
+		MAX_BINDLESS_IMAGES);
+
 	// Find active vars by running the preprocessor
 	StringAuto activeInputs(m_alloc);
 	if(m_inputs.getSize() > 0)
 	{
 		StringAuto src(m_alloc);
+		src.append(header);
+		src.append("#define ANKI_VERTEX_SHADER 1\n"); // Something random to avoid compilation errors
 		src.append(mutatorDefines);
 		src.append(m_globalsSource);
 		ANKI_CHECK(findActiveInputVars(src, variant.m_activeInputVarsMask));
@@ -1071,6 +1231,7 @@ Error ShaderProgramParser::generateSource(
 
 		// Create the final source without the bindings
 		StringAuto finalSource(m_alloc);
+		finalSource.append(header);
 		finalSource.append(mutatorDefines);
 		finalSource.append(StringAuto(m_alloc).sprintf("#define ANKI_%s 1\n", SHADER_STAGE_NAMES[shaderType].cstr()));
 		finalSource.append(activeInputs);

+ 3 - 0
src/anki/shader_compiler/ShaderProgramParser.h

@@ -246,6 +246,9 @@ private:
 	U32 m_instancedMutatorIdx = MAX_U32;
 	U32 m_specConstIdx = 0;
 	const U32 m_pushConstSize = 0;
+	const U32 m_backendMinor = 1; // TODO
+	const U32 m_backendMajor = 1; // TODO
+	const GpuVendor m_gpuVendor = GpuVendor::AMD; // TODO
 	Bool m_foundAtLeastOneInstancedInput = false;
 
 	ANKI_USE_RESULT Error parseFile(CString fname, U32 depth);

+ 11 - 0
tests/shader_compiler/ShaderProgramParser.cpp

@@ -0,0 +1,11 @@
+// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <tests/framework/Framework.h>
+#include <anki/shader_compiler/ShaderProgramParser.h>
+
+ANKI_TEST(ShaderCompiler, ShaderCompilerParser)
+{
+}