Browse Source

Additions to shader program resource. Fix a bug in GL. Make IS shaders a program

Panagiotis Christopoulos Charitos 8 years ago
parent
commit
2a214e92a7

+ 8 - 6
programs/FsFog.ankiprog

@@ -11,13 +11,14 @@ http://www.anki3d.org/LICENSE
 				<input name="mvp" type="mat4"/>
 			</inputs>
 
-			<source><![CDATA[#include "shaders/FsCommonVert.glsl"
+			<source><![CDATA[
+#include "shaders/FsCommonVert.glsl"
+
 void main() 
 {
 	ANKI_WRITE_POSITION(mvp * vec4(in_position, 1.0));
 }
-			]]>
-			</source>
+			]]></source>
 		</shader>
 
 		<shader type="frag">
@@ -26,13 +27,14 @@ void main()
 				<input name="fogScale" type="float" const="1"/>
 			</inputs>
 
-			<source><![CDATA[#include "shaders/FsCommonFrag.glsl"
+			<source><![CDATA[
+#include "shaders/FsCommonFrag.glsl"
+
 void main() 
 {
 	fog(fogColor, fogScale);
 }
-			]]>
-			</source>
+			]]></source>
 		</shader>
 	</shaders>
 </shaderProgram>

+ 56 - 13
shaders/Is.frag.glsl → programs/Is.ankiprog

@@ -1,8 +1,45 @@
-// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
+<!-- 
+Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+All rights reserved.
+Code licensed under the BSD License.
+http://www.anki3d.org/LICENSE
+-->
+<shaderProgram>
+	<inputs>
+		<input name="CLUSTER_COUNT_X" type="uint" const="1"/>
+		<input name="CLUSTER_COUNT_Y" type="uint" const="1"/>
+		<input name="CLUSTER_COUNT" type="uint" const="1"/>
+		<input name="IR_MIPMAP_COUNT" type="uint" const="1"/>
+	</inputs>
+
+	<shaders>
+		<shader type="vert">
+			<source><![CDATA[
+#include "shaders/Common.glsl"
+
+layout(location = 0) out vec2 out_uv;
+layout(location = 1) out vec2 out_clusterIJ;
+
+out gl_PerVertex
+{
+	vec4 gl_Position;
+};
+
+void main()
+{
+	const vec2 POSITIONS[3] = vec2[](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));
+
+	vec2 pos = POSITIONS[gl_VertexID];
+	out_uv = NDC_TO_UV(pos);
+	ANKI_WRITE_POSITION(vec4(pos, 0.0, 1.0));
 
+	out_clusterIJ = vec2(CLUSTER_COUNT_X, CLUSTER_COUNT_Y) * out_uv;
+}
+			]]></source>
+		</shader>
+
+		<shader type="frag">
+			<source><![CDATA[
 #include "shaders/Pack.glsl"
 #include "shaders/Clusterer.glsl"
 #include "shaders/Functions.glsl"
@@ -14,6 +51,7 @@
 #define LIGHT_LIGHTS
 #define LIGHT_INDIRECT
 #define LIGHT_DECALS
+#define LIGHT_COMMON_UNIS
 #include "shaders/ClusterLightCommon.glsl"
 
 layout(ANKI_TEX_BINDING(1, 0)) uniform sampler2D u_msRt0;
@@ -31,13 +69,13 @@ layout(location = 0) out vec3 out_color;
 const float SUBSURFACE_MIN = 0.05;
 
 // Common code for lighting
-#define LIGHTING_COMMON_BRDF()                                                                                         \
-	vec3 frag2Light = light.posRadius.xyz - fragPos;                                                                   \
-	vec3 l = normalize(frag2Light);                                                                                    \
-	float nol = max(0.0, dot(normal, l));                                                                              \
-	vec3 specC = computeSpecularColorBrdf(viewDir, l, normal, specCol, light.specularColorRadius.rgb, a2, nol);        \
-	vec3 diffC = computeDiffuseColor(diffCol, light.diffuseColorShadowmapId.rgb);                                      \
-	float att = computeAttenuationFactor(light.posRadius.w, frag2Light);                                               \
+#define LIGHTING_COMMON_BRDF() \
+	vec3 frag2Light = light.posRadius.xyz - fragPos; \
+	vec3 l = normalize(frag2Light); \
+	float nol = max(0.0, dot(normal, l)); \
+	vec3 specC = computeSpecularColorBrdf(viewDir, l, normal, specCol, light.specularColorRadius.rgb, a2, nol); \
+	vec3 diffC = computeDiffuseColor(diffCol, light.diffuseColorShadowmapId.rgb); \
+	float att = computeAttenuationFactor(light.posRadius.w, frag2Light); \
 	float lambert = nol;
 
 void debugIncorrectColor(inout vec3 c)
@@ -219,7 +257,7 @@ void main()
 		outC += (diffC + specC) * (att * spot * max(subsurface, lambert));
 	}
 
-#if INDIRECT_ENABLED
+	// Indirect
 	vec3 eye = -viewDir;
 
 	vec3 worldEye = u_invViewRotation * eye;
@@ -236,7 +274,6 @@ void main()
 	readIndirect(idxOffset, worldPos, worldR, worldNormal, reflLod, specIndirect, diffIndirect);
 
 	outC += specIndirect * specIndirectTerm + diffIndirect * diffCol;
-#endif
 
 	out_color = outC;
 #if 0
@@ -263,3 +300,9 @@ void main()
 	}
 #endif
 }
+			]]></source>
+		</shader>
+	</shaders>
+
+</shaderProgram>
+

+ 44 - 13
shaders/ClusterLightCommon.glsl

@@ -59,6 +59,13 @@ struct Decal
 	vec4 blendFactors;
 };
 
+//
+// Common uniforms
+//
+#if defined(LIGHT_COMMON_UNIS)
+
+const uint _NEXT_UBO_BINDING = LIGHT_UBO_BINDING + 1;
+
 layout(ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING), std140, row_major) uniform u0_
 {
 	LightingUniforms u_lightingUniforms;
@@ -95,44 +102,70 @@ layout(ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING), std140, row_major) unifor
 		readFirstInvocationARB(u_lightingUniforms.prevViewProjMat[2]),                                                 \
 		readFirstInvocationARB(u_lightingUniforms.prevViewProjMat[3]))
 
-#ifdef ANKI_FRAGMENT_SHADER
+#else
+const uint _NEXT_UBO_BINDING = LIGHT_UBO_BINDING;
+#endif
 
+//
+// Light uniforms
+//
 #if defined(LIGHT_LIGHTS)
-layout(ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING + 1), std140) uniform u1_
+const uint _NEXT_UBO_BINDING_2 = _NEXT_UBO_BINDING + 2;
+const uint _NEXT_TEX_BINDING_2 = LIGHT_TEX_BINDING + 2;
+
+layout(ANKI_UBO_BINDING(LIGHT_SET, _NEXT_UBO_BINDING), std140) uniform u1_
 {
 	PointLight u_pointLights[UBO_MAX_SIZE / (3 * 4 * 4)];
 };
 
-layout(ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING + 2), std140, row_major) uniform u2_
+layout(ANKI_UBO_BINDING(LIGHT_SET, _NEXT_UBO_BINDING + 1), std140, row_major) uniform u2_
 {
 	SpotLight u_spotLights[UBO_MAX_SIZE / (9 * 4 * 4)];
 };
 
-layout(ANKI_TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING)) uniform highp sampler2DArrayShadow u_spotMapArr;
+layout(ANKI_TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING + 0)) uniform highp sampler2DArrayShadow u_spotMapArr;
 layout(ANKI_TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING + 1)) uniform highp samplerCubeArrayShadow u_omniMapArr;
+#else
+const uint _NEXT_UBO_BINDING_2 = _NEXT_UBO_BINDING;
+const uint _NEXT_TEX_BINDING_2 = LIGHT_TEX_BINDING;
 #endif
 
+//
+// Indirect uniforms
+//
 #if defined(LIGHT_INDIRECT)
-layout(std140, row_major, ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING + 3)) uniform u3_
+const uint _NEXT_UBO_BINDING_3 = _NEXT_UBO_BINDING_2 + 1;
+const uint _NEXT_TEX_BINDING_3 = _NEXT_TEX_BINDING_2 + 3;
+
+layout(std140, row_major, ANKI_UBO_BINDING(LIGHT_SET, _NEXT_UBO_BINDING_2)) uniform u3_
 {
 	ReflectionProbe u_reflectionProbes[UBO_MAX_SIZE / (2 * 4 * 4)];
 };
 
-layout(ANKI_TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING + 2)) uniform samplerCubeArray u_reflectionsTex;
-layout(ANKI_TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING + 3)) uniform samplerCubeArray u_irradianceTex;
-layout(ANKI_TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING + 4)) uniform sampler2D u_integrationLut;
+layout(ANKI_TEX_BINDING(LIGHT_SET, _NEXT_TEX_BINDING_2 + 0)) uniform samplerCubeArray u_reflectionsTex;
+layout(ANKI_TEX_BINDING(LIGHT_SET, _NEXT_TEX_BINDING_2 + 1)) uniform samplerCubeArray u_irradianceTex;
+layout(ANKI_TEX_BINDING(LIGHT_SET, _NEXT_TEX_BINDING_2 + 2)) uniform sampler2D u_integrationLut;
+#else
+const uint _NEXT_UBO_BINDING_3 = _NEXT_UBO_BINDING_2;
+const uint _NEXT_TEX_BINDING_3 = _NEXT_TEX_BINDING_2;
 #endif
 
+//
+// Decal uniforms
+//
 #if defined(LIGHT_DECALS)
-layout(std140, row_major, ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING + 4)) uniform u4_
+layout(std140, row_major, ANKI_UBO_BINDING(LIGHT_SET, _NEXT_UBO_BINDING_3)) uniform u4_
 {
 	Decal u_decals[UBO_MAX_SIZE / ((4 + 16) * 4)];
 };
 
-layout(ANKI_TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING + 5)) uniform sampler2D u_diffDecalTex;
-layout(ANKI_TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING + 6)) uniform sampler2D u_normalRoughnessDecalTex;
+layout(ANKI_TEX_BINDING(LIGHT_SET, _NEXT_TEX_BINDING_3 + 0)) uniform sampler2D u_diffDecalTex;
+layout(ANKI_TEX_BINDING(LIGHT_SET, _NEXT_TEX_BINDING_3 + 1)) uniform sampler2D u_normalRoughnessDecalTex;
 #endif
 
+//
+// Cluster uniforms
+//
 layout(ANKI_SS_BINDING(LIGHT_SET, LIGHT_SS_BINDING + 0), std430) readonly buffer s0_
 {
 	uint u_clusters[];
@@ -143,6 +176,4 @@ layout(std430, ANKI_SS_BINDING(LIGHT_SET, LIGHT_SS_BINDING + 1)) readonly buffer
 	uint u_lightIndices[];
 };
 
-#endif // ANKI_FRAGMENT_SHADER
-
 #endif

+ 1 - 0
shaders/FsCommonFrag.glsl

@@ -19,6 +19,7 @@ layout(ANKI_TEX_BINDING(1, 0)) uniform sampler2D anki_msDepthRt;
 #define LIGHT_SS_BINDING 0
 #define LIGHT_TEX_BINDING 1
 #define LIGHT_LIGHTS
+#define LIGHT_COMMON_UNIS
 #include "shaders/ClusterLightCommon.glsl"
 
 #define anki_u_time u_time

+ 0 - 25
shaders/Is.vert.glsl

@@ -1,25 +0,0 @@
-// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "shaders/Common.glsl"
-
-layout(location = 0) out vec2 out_uv;
-layout(location = 1) out vec2 out_clusterIJ;
-
-out gl_PerVertex
-{
-	vec4 gl_Position;
-};
-
-void main()
-{
-	const vec2 POSITIONS[3] = vec2[](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));
-
-	vec2 pos = POSITIONS[gl_VertexID];
-	out_uv = NDC_TO_UV(pos);
-	ANKI_WRITE_POSITION(vec4(pos, 0.0, 1.0));
-
-	out_clusterIJ = vec2(CLUSTER_COUNT_X, CLUSTER_COUNT_Y) * out_uv;
-}

+ 1 - 0
shaders/Volumetric.frag.glsl

@@ -12,6 +12,7 @@
 #define LIGHT_SS_BINDING 0
 #define LIGHT_SET 0
 #define LIGHT_LIGHTS
+#define LIGHT_COMMON_UNIS
 #include "shaders/ClusterLightCommon.glsl"
 
 layout(location = 0) in vec2 in_uv;

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

@@ -267,9 +267,17 @@ ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderTypeBit, inline)
 enum class ShaderVariableDataType : U8
 {
 	NONE,
+	INT,
+	UINT,
 	FLOAT,
+	IVEC2,
+	UVEC2,
 	VEC2,
+	IVEC3,
+	UVEC3,
 	VEC3,
+	IVEC4,
+	UVEC4,
 	VEC4,
 	MAT3,
 	MAT4,
@@ -278,7 +286,7 @@ enum class ShaderVariableDataType : U8
 	SAMPLER_2D_ARRAY,
 	SAMPLER_CUBE,
 
-	NUMERICS_FIRST = FLOAT,
+	NUMERICS_FIRST = INT,
 	NUMERICS_LAST = MAT4,
 
 	MATRIX_FIRST = MAT3,

+ 24 - 0
src/anki/gr/Shader.cpp

@@ -94,15 +94,39 @@ void writeShaderBlockMemory(ShaderVariableDataType type,
 {
 	switch(type)
 	{
+	case ShaderVariableDataType::INT:
+		writeShaderBlockMemorySimple<I32>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
+		break;
+	case ShaderVariableDataType::UINT:
+		writeShaderBlockMemorySimple<U32>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
+		break;
 	case ShaderVariableDataType::FLOAT:
 		writeShaderBlockMemorySimple<F32>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
 		break;
+	case ShaderVariableDataType::IVEC2:
+		writeShaderBlockMemorySimple<IVec2>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
+		break;
+	case ShaderVariableDataType::UVEC2:
+		writeShaderBlockMemorySimple<UVec2>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
+		break;
 	case ShaderVariableDataType::VEC2:
 		writeShaderBlockMemorySimple<Vec2>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
 		break;
+	case ShaderVariableDataType::IVEC3:
+		writeShaderBlockMemorySimple<IVec3>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
+		break;
+	case ShaderVariableDataType::UVEC3:
+		writeShaderBlockMemorySimple<UVec3>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
+		break;
 	case ShaderVariableDataType::VEC3:
 		writeShaderBlockMemorySimple<Vec3>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
 		break;
+	case ShaderVariableDataType::IVEC4:
+		writeShaderBlockMemorySimple<IVec4>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
+		break;
+	case ShaderVariableDataType::UVEC4:
+		writeShaderBlockMemorySimple<UVec4>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
+		break;
 	case ShaderVariableDataType::VEC4:
 		writeShaderBlockMemorySimple<Vec4>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
 		break;

+ 8 - 0
src/anki/gr/Shader.h

@@ -25,6 +25,14 @@ ShaderVariableDataType getShaderVariableTypeFromTypename();
 		return ShaderVariableDataType::type_;                                                                          \
 	}
 
+ANKI_SPECIALIZE_SHADER_VAR_TYPE_GET(I32, INT)
+ANKI_SPECIALIZE_SHADER_VAR_TYPE_GET(IVec2, IVEC2)
+ANKI_SPECIALIZE_SHADER_VAR_TYPE_GET(IVec3, IVEC3)
+ANKI_SPECIALIZE_SHADER_VAR_TYPE_GET(IVec4, IVEC4)
+ANKI_SPECIALIZE_SHADER_VAR_TYPE_GET(U32, UINT)
+ANKI_SPECIALIZE_SHADER_VAR_TYPE_GET(UVec2, UVEC2)
+ANKI_SPECIALIZE_SHADER_VAR_TYPE_GET(UVec3, UVEC3)
+ANKI_SPECIALIZE_SHADER_VAR_TYPE_GET(UVec4, UVEC4)
 ANKI_SPECIALIZE_SHADER_VAR_TYPE_GET(F32, FLOAT)
 ANKI_SPECIALIZE_SHADER_VAR_TYPE_GET(Vec2, VEC2)
 ANKI_SPECIALIZE_SHADER_VAR_TYPE_GET(Vec3, VEC3)

+ 2 - 2
src/anki/gr/gl/CommandBufferImpl.cpp

@@ -320,11 +320,11 @@ void CommandBufferImpl::flushDrawcall(CommandBuffer& cmdb)
 		{
 			if(m_state.m_colorAtt[i].m_enableBlend)
 			{
-				blendEnableMask = 1 << i;
+				blendEnableMask |= 1 << i;
 			}
 			else
 			{
-				blendDisableMask = 1 << i;
+				blendDisableMask |= 1 << i;
 			}
 		}
 	}

+ 2 - 0
src/anki/renderer/Common.h

@@ -41,6 +41,8 @@ class Taa;
 class RenderingContext;
 class DebugDrawer;
 
+class ShaderProgramResourceVariant;
+
 /// @addtogroup renderer
 /// @{
 

+ 8 - 24
src/anki/renderer/Is.cpp

@@ -94,31 +94,15 @@ Error Is::initInternal(const ConfigSet& config)
 	//
 	// Load shaders and programs
 	//
-	StringAuto pps(getAllocator());
-
-	pps.sprintf("#define CLUSTER_COUNT_X %u\n"
-				"#define CLUSTER_COUNT_Y %u\n"
-				"#define CLUSTER_COUNT %u\n"
-				"#define RENDERER_WIDTH %u\n"
-				"#define RENDERER_HEIGHT %u\n"
-				"#define MAX_LIGHT_INDICES %u\n"
-				"#define POISSON %u\n"
-				"#define INDIRECT_ENABLED %u\n"
-				"#define IR_MIPMAP_COUNT %u\n",
-		m_clusterCounts[0],
-		m_clusterCounts[1],
-		m_clusterCount,
-		m_r->getWidth(),
-		m_r->getHeight(),
-		m_maxLightIds,
-		m_r->getSm().m_poissonEnabled,
-		1,
-		m_r->getIr().getReflectionTextureMipmapCount());
+	ANKI_CHECK(getResourceManager().loadResource("programs/Is.ankiprog", m_prog));
 
-	ANKI_CHECK(m_r->createShader("shaders/Is.vert.glsl", m_lightVert, &pps[0]));
-	ANKI_CHECK(m_r->createShader("shaders/Is.frag.glsl", m_lightFrag, &pps[0]));
+	ShaderProgramResourceConstantValues<5> consts(m_prog);
+	consts.add("CLUSTER_COUNT_X", U32(m_clusterCounts[0]))
+		.add("CLUSTER_COUNT_Y", U32(m_clusterCounts[1]))
+		.add("CLUSTER_COUNT", U32(m_clusterCount))
+		.add("IR_MIPMAP_COUNT", U32(m_r->getIr().getReflectionTextureMipmapCount()));
 
-	m_lightProg = getGrManager().newInstance<ShaderProgram>(m_lightVert->getGrShader(), m_lightFrag->getGrShader());
+	m_prog->getOrCreateVariant(consts.m_constantValues, m_progVariant);
 
 	//
 	// Create framebuffer
@@ -170,7 +154,7 @@ void Is::run(RenderingContext& ctx)
 
 	cmdb->beginRenderPass(m_fb);
 	cmdb->setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
-	cmdb->bindShaderProgram(m_lightProg);
+	cmdb->bindShaderProgram(m_progVariant->getProgram());
 
 	cmdb->bindTexture(1, 0, m_r->getMs().m_rt0);
 	cmdb->bindTexture(1, 1, m_r->getMs().m_rt1);

+ 3 - 3
src/anki/renderer/Is.h

@@ -8,6 +8,7 @@
 #include <anki/renderer/RenderingPass.h>
 #include <anki/resource/TextureResource.h>
 #include <anki/resource/ShaderResource.h>
+#include <anki/resource/ShaderProgramResource.h>
 
 namespace anki
 {
@@ -56,9 +57,8 @@ private:
 	FramebufferPtr m_fb;
 
 	// Light shaders
-	ShaderResourcePtr m_lightVert;
-	ShaderResourcePtr m_lightFrag;
-	ShaderProgramPtr m_lightProg;
+	ShaderProgramResourcePtr m_prog;
+	const ShaderProgramResourceVariant* m_progVariant = nullptr;
 
 	LightBin* m_lightBin = nullptr;
 

+ 2 - 2
src/anki/renderer/Ssao.cpp

@@ -140,7 +140,7 @@ Error SsaoHBlur::init(const ConfigSet& config)
 		"#define HPASS\n"
 		"#define COL_R\n"
 		"#define TEXTURE_SIZE vec2(%f, %f)\n"
-		"#define KERNEL_SIZE 5\n",
+		"#define KERNEL_SIZE 9\n",
 		F32(m_ssao->m_width),
 		F32(m_ssao->m_height)));
 
@@ -182,7 +182,7 @@ Error SsaoVBlur::init(const ConfigSet& config)
 		"#define VPASS\n"
 		"#define COL_R\n"
 		"#define TEXTURE_SIZE vec2(%f, %f)\n"
-		"#define KERNEL_SIZE 5\n",
+		"#define KERNEL_SIZE 9\n",
 		F32(m_ssao->m_width),
 		F32(m_ssao->m_height)));
 

+ 48 - 0
src/anki/resource/Material.cpp

@@ -295,6 +295,30 @@ Error Material::parseInputs(XmlElement inputsEl)
 
 			switch(foundVar->getShaderVariableDataType())
 			{
+			case ShaderVariableDataType::INT:
+				ANKI_CHECK(inputEl.getAttributeNumber("value", constVal.m_int));
+				break;
+			case ShaderVariableDataType::IVEC2:
+				ANKI_CHECK(inputEl.getAttributeVector("value", constVal.m_ivec2));
+				break;
+			case ShaderVariableDataType::IVEC3:
+				ANKI_CHECK(inputEl.getAttributeVector("value", constVal.m_ivec3));
+				break;
+			case ShaderVariableDataType::IVEC4:
+				ANKI_CHECK(inputEl.getAttributeVector("value", constVal.m_ivec4));
+				break;
+			case ShaderVariableDataType::UINT:
+				ANKI_CHECK(inputEl.getAttributeNumber("value", constVal.m_uint));
+				break;
+			case ShaderVariableDataType::UVEC2:
+				ANKI_CHECK(inputEl.getAttributeVector("value", constVal.m_uvec2));
+				break;
+			case ShaderVariableDataType::UVEC3:
+				ANKI_CHECK(inputEl.getAttributeVector("value", constVal.m_uvec3));
+				break;
+			case ShaderVariableDataType::UVEC4:
+				ANKI_CHECK(inputEl.getAttributeVector("value", constVal.m_uvec4));
+				break;
 			case ShaderVariableDataType::FLOAT:
 				ANKI_CHECK(inputEl.getAttributeNumber("value", constVal.m_float));
 				break;
@@ -371,6 +395,30 @@ Error Material::parseInputs(XmlElement inputsEl)
 
 				switch(foundVar->getShaderVariableDataType())
 				{
+				case ShaderVariableDataType::INT:
+					ANKI_CHECK(inputEl.getAttributeNumber("value", mtlVar.m_int));
+					break;
+				case ShaderVariableDataType::IVEC2:
+					ANKI_CHECK(inputEl.getAttributeVector("value", mtlVar.m_ivec2));
+					break;
+				case ShaderVariableDataType::IVEC3:
+					ANKI_CHECK(inputEl.getAttributeVector("value", mtlVar.m_ivec3));
+					break;
+				case ShaderVariableDataType::IVEC4:
+					ANKI_CHECK(inputEl.getAttributeVector("value", mtlVar.m_ivec4));
+					break;
+				case ShaderVariableDataType::UINT:
+					ANKI_CHECK(inputEl.getAttributeNumber("value", mtlVar.m_uint));
+					break;
+				case ShaderVariableDataType::UVEC2:
+					ANKI_CHECK(inputEl.getAttributeVector("value", mtlVar.m_uvec2));
+					break;
+				case ShaderVariableDataType::UVEC3:
+					ANKI_CHECK(inputEl.getAttributeVector("value", mtlVar.m_uvec3));
+					break;
+				case ShaderVariableDataType::UVEC4:
+					ANKI_CHECK(inputEl.getAttributeVector("value", mtlVar.m_uvec4));
+					break;
 				case ShaderVariableDataType::FLOAT:
 					ANKI_CHECK(inputEl.getAttributeNumber("value", mtlVar.m_float));
 					break;

+ 16 - 0
src/anki/resource/Material.h

@@ -71,6 +71,14 @@ protected:
 
 	union
 	{
+		I32 m_int;
+		IVec2 m_ivec2;
+		IVec3 m_ivec3;
+		IVec4 m_ivec4;
+		U32 m_uint;
+		UVec2 m_uvec2;
+		UVec3 m_uvec3;
+		UVec4 m_uvec4;
 		F32 m_float;
 		Vec2 m_vec2;
 		Vec3 m_vec3;
@@ -95,6 +103,14 @@ protected:
 		return var_;                                                                                                   \
 	}
 
+ANKI_SPECIALIZE_GET_VALUE(I32, m_int, INT)
+ANKI_SPECIALIZE_GET_VALUE(IVec2, m_ivec2, IVEC2)
+ANKI_SPECIALIZE_GET_VALUE(IVec3, m_ivec3, IVEC3)
+ANKI_SPECIALIZE_GET_VALUE(IVec4, m_ivec4, IVEC4)
+ANKI_SPECIALIZE_GET_VALUE(U32, m_uint, UINT)
+ANKI_SPECIALIZE_GET_VALUE(UVec2, m_uvec2, UVEC2)
+ANKI_SPECIALIZE_GET_VALUE(UVec3, m_uvec3, UVEC3)
+ANKI_SPECIALIZE_GET_VALUE(UVec4, m_uvec4, UVEC4)
 ANKI_SPECIALIZE_GET_VALUE(F32, m_float, FLOAT)
 ANKI_SPECIALIZE_GET_VALUE(Vec2, m_vec2, VEC2)
 ANKI_SPECIALIZE_GET_VALUE(Vec3, m_vec3, VEC3)

+ 85 - 5
src/anki/resource/ShaderProgramResource.cpp

@@ -15,7 +15,39 @@ static ANKI_USE_RESULT Error computeShaderVariableDataType(const CString& str, S
 {
 	Error err = ErrorCode::NONE;
 
-	if(str == "float")
+	if(str == "int")
+	{
+		out = ShaderVariableDataType::INT;
+	}
+	else if(str == "ivec2")
+	{
+		out = ShaderVariableDataType::IVEC2;
+	}
+	else if(str == "ivec3")
+	{
+		out = ShaderVariableDataType::IVEC3;
+	}
+	else if(str == "ivec4")
+	{
+		out = ShaderVariableDataType::IVEC4;
+	}
+	if(str == "uint")
+	{
+		out = ShaderVariableDataType::UINT;
+	}
+	else if(str == "uvec2")
+	{
+		out = ShaderVariableDataType::UVEC2;
+	}
+	else if(str == "uvec3")
+	{
+		out = ShaderVariableDataType::UVEC3;
+	}
+	else if(str == "uvec4")
+	{
+		out = ShaderVariableDataType::UVEC4;
+	}
+	else if(str == "float")
 	{
 		out = ShaderVariableDataType::FLOAT;
 	}
@@ -808,7 +840,8 @@ void ShaderProgramResource::initVariant(WeakArray<const ShaderProgramResourceMut
 			blockInfo.m_offset = variant.m_uniBlockSize;
 			blockInfo.m_arraySize = (in.m_instanced) ? instanceCount : 1;
 
-			if(in.m_dataType == ShaderVariableDataType::FLOAT)
+			if(in.m_dataType == ShaderVariableDataType::FLOAT || in.m_dataType == ShaderVariableDataType::INT
+				|| in.m_dataType == ShaderVariableDataType::UINT)
 			{
 				blockInfo.m_arrayStride = sizeof(Vec4);
 
@@ -823,7 +856,8 @@ void ShaderProgramResource::initVariant(WeakArray<const ShaderProgramResourceMut
 					variant.m_uniBlockSize += sizeof(Vec4) * blockInfo.m_arraySize;
 				}
 			}
-			else if(in.m_dataType == ShaderVariableDataType::VEC2)
+			else if(in.m_dataType == ShaderVariableDataType::VEC2 || in.m_dataType == ShaderVariableDataType::IVEC2
+				|| in.m_dataType == ShaderVariableDataType::UVEC2)
 			{
 				blockInfo.m_arrayStride = sizeof(Vec4);
 
@@ -838,7 +872,8 @@ void ShaderProgramResource::initVariant(WeakArray<const ShaderProgramResourceMut
 					variant.m_uniBlockSize = blockInfo.m_offset + sizeof(Vec4) * blockInfo.m_arraySize;
 				}
 			}
-			else if(in.m_dataType == ShaderVariableDataType::VEC3)
+			else if(in.m_dataType == ShaderVariableDataType::VEC3 || in.m_dataType == ShaderVariableDataType::IVEC3
+				|| in.m_dataType == ShaderVariableDataType::UVEC3)
 			{
 				alignRoundUp(sizeof(Vec4), blockInfo.m_offset);
 				blockInfo.m_arrayStride = sizeof(Vec4);
@@ -852,7 +887,8 @@ void ShaderProgramResource::initVariant(WeakArray<const ShaderProgramResourceMut
 					variant.m_uniBlockSize = blockInfo.m_offset + sizeof(Vec4) * blockInfo.m_arraySize;
 				}
 			}
-			else if(in.m_dataType == ShaderVariableDataType::VEC4)
+			else if(in.m_dataType == ShaderVariableDataType::VEC4 || in.m_dataType == ShaderVariableDataType::IVEC4
+				|| in.m_dataType == ShaderVariableDataType::UVEC4)
 			{
 				blockInfo.m_arrayStride = sizeof(Vec4);
 				alignRoundUp(sizeof(Vec4), blockInfo.m_offset);
@@ -895,6 +931,50 @@ void ShaderProgramResource::initVariant(WeakArray<const ShaderProgramResourceMut
 
 			switch(in.m_dataType)
 			{
+			case ShaderVariableDataType::INT:
+				headerSrc.pushBackSprintf("#define %s_CONSTVAL %d\n", &in.m_name[0], constVal->m_int);
+				break;
+			case ShaderVariableDataType::IVEC2:
+				headerSrc.pushBackSprintf(
+					"#define %s_CONSTVAL %d, %d\n", &in.m_name[0], constVal->m_ivec2.x(), constVal->m_ivec2.y());
+				break;
+			case ShaderVariableDataType::IVEC3:
+				headerSrc.pushBackSprintf("#define %s_CONSTVAL %d, %d, %d\n",
+					&in.m_name[0],
+					constVal->m_ivec3.x(),
+					constVal->m_ivec3.y(),
+					constVal->m_ivec3.z());
+				break;
+			case ShaderVariableDataType::IVEC4:
+				headerSrc.pushBackSprintf("#define %s_CONSTVAL %d, %d, %d, %d\n",
+					&in.m_name[0],
+					constVal->m_ivec4.x(),
+					constVal->m_ivec4.y(),
+					constVal->m_ivec4.z(),
+					constVal->m_ivec4.w());
+				break;
+			case ShaderVariableDataType::UINT:
+				headerSrc.pushBackSprintf("#define %s_CONSTVAL %u\n", &in.m_name[0], constVal->m_uint);
+				break;
+			case ShaderVariableDataType::UVEC2:
+				headerSrc.pushBackSprintf(
+					"#define %s_CONSTVAL %u, %u\n", &in.m_name[0], constVal->m_uvec2.x(), constVal->m_uvec2.y());
+				break;
+			case ShaderVariableDataType::UVEC3:
+				headerSrc.pushBackSprintf("#define %s_CONSTVAL %u, %u, %u\n",
+					&in.m_name[0],
+					constVal->m_uvec3.x(),
+					constVal->m_uvec3.y(),
+					constVal->m_uvec3.z());
+				break;
+			case ShaderVariableDataType::UVEC4:
+				headerSrc.pushBackSprintf("#define %s_CONSTVAL %u, %u, %u, %u\n",
+					&in.m_name[0],
+					constVal->m_uvec4.x(),
+					constVal->m_uvec4.y(),
+					constVal->m_uvec4.z(),
+					constVal->m_uvec4.w());
+				break;
 			case ShaderVariableDataType::FLOAT:
 				headerSrc.pushBackSprintf("#define %s_CONSTVAL %f\n", &in.m_name[0], constVal->m_float);
 				break;

+ 50 - 2
src/anki/resource/ShaderProgramResource.h

@@ -242,6 +242,16 @@ class ShaderProgramResourceConstantValue
 public:
 	union
 	{
+		I32 m_int;
+		IVec2 m_ivec2;
+		IVec3 m_ivec3;
+		IVec4 m_ivec4;
+
+		U32 m_uint;
+		UVec2 m_uvec2;
+		UVec3 m_uvec3;
+		UVec4 m_uvec4;
+
 		F32 m_float;
 		Vec2 m_vec2;
 		Vec3 m_vec3;
@@ -269,7 +279,7 @@ static_assert(sizeof(ShaderProgramResourceConstantValue) == sizeof(Vec4) * 2, "N
 /// 	</mutators>]
 ///
 ///		[<inputs> (3)
-///			<input name="str" type="float | vec2 | vec3 | vec4 | mat3 | mat4 | samplerXXX"
+///			<input name="str" type="uint | int | float | vec2 | vec3 | vec4 | mat3 | mat4 | samplerXXX"
 ///				[instanceCount="mutator name"] [const="0 | 1"]>
 ///				[<mutators> (2)
 ///					<mutator name="variant_name" values="array of ints"/>
@@ -281,7 +291,7 @@ static_assert(sizeof(ShaderProgramResourceConstantValue) == sizeof(Vec4) * 2, "N
 ///			<shader type="vert | frag | tese | tesc"/>
 ///
 ///				[<inputs>
-///					<input name="str" type="float | vec2 | vec3 | vec4 | mat3 | mat4 | samplerXXX"
+///					<input name="str" type="uint | int | float | vec2 | vec3 | vec4 | mat3 | mat4 | samplerXXX"
 /// 					[instanceCount="mutator name"] [const="0 | 1"]>
 /// 					[<mutators> (2)
 /// 						<mutator name="variant_name" values="array of ints"/>
@@ -350,6 +360,14 @@ public:
 		WeakArray<const ShaderProgramResourceConstantValue> constants,
 		const ShaderProgramResourceVariant*& variant) const;
 
+	/// Get or create a graphics shader program variant.
+	/// @note It's thread-safe.
+	void getOrCreateVariant(WeakArray<const ShaderProgramResourceConstantValue> constants,
+		const ShaderProgramResourceVariant*& variant) const
+	{
+		getOrCreateVariant(WeakArray<const ShaderProgramResourceMutation>(), constants, variant);
+	}
+
 	Bool hasTessellation() const
 	{
 		return m_tessellation;
@@ -389,6 +407,36 @@ private:
 
 	void compInputVarDefineString(const ShaderProgramResourceInputVariable& var, StringListAuto& list);
 };
+
+/// Smart initializer of multiple ShaderProgramResourceConstantValue.
+template<U count>
+class ShaderProgramResourceConstantValues
+{
+public:
+	Array<ShaderProgramResourceConstantValue, count> m_constantValues;
+
+	ShaderProgramResourceConstantValues(ShaderProgramResourcePtr ptr)
+		: m_ptr(ptr)
+	{
+	}
+
+	template<typename T>
+	ShaderProgramResourceConstantValues& add(CString name, const T& t)
+	{
+		const ShaderProgramResourceInputVariable* in = m_ptr->tryFindInputVariable(name);
+		ANKI_ASSERT(in);
+		ANKI_ASSERT(in->isConstant());
+		ANKI_ASSERT(in->getShaderVariableDataType() == getShaderVariableTypeFromTypename<T>());
+		m_constantValues[m_count].m_variable = in;
+		memcpy(&m_constantValues[m_count].m_int, &t, sizeof(T));
+		++m_count;
+		return *this;
+	}
+
+private:
+	ShaderProgramResourcePtr m_ptr;
+	U m_count = 0;
+};
 /// @}
 
 } // end namespace anki

+ 1 - 1
tools/count_lines.sh

@@ -1 +1 @@
-wc -l `find ./src ./tests ./sandbox ./tools ./shaders ./samples -name '*.h' -o -name '*.hpp' -o -name '*.c' -o -name '*.cpp' -o -name '*.glsl' -o -name '*.py'`
+wc -l `find ./src ./tests ./sandbox ./tools ./shaders ./samples -name '*.h' -o -name '*.hpp' -o -name '*.c' -o -name '*.cpp' -o -name '*.glsl' -o -name '*.py' -o -name '*.ankiprog'`