Browse Source

Move some shader binding validation code out of the opengl backend

Alex Szpakowski 4 years ago
parent
commit
7eb3d4343a

+ 108 - 0
src/modules/graphics/Shader.cpp

@@ -726,6 +726,114 @@ bool Shader::validateInternal(ShaderStage *vertex, ShaderStage *pixel, std::stri
 	return true;
 	return true;
 }
 }
 
 
+bool Shader::validateTexture(const UniformInfo *info, Texture *tex, bool internalUpdate)
+{
+	const SamplerState &sampler = tex->getSamplerState();
+	if (!tex->isReadable())
+	{
+		if (internalUpdate)
+			return false;
+		else
+			throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader.");
+	}
+	else if (info->isDepthSampler != sampler.depthSampleMode.hasValue)
+	{
+		if (internalUpdate)
+			return false;
+		else if (info->isDepthSampler)
+			throw love::Exception("Depth comparison samplers in shaders can only be used with depth textures which have depth comparison set.");
+		else
+			throw love::Exception("Depth textures which have depth comparison set can only be used with depth/shadow samplers in shaders.");
+	}
+	else if (tex->getTextureType() != info->textureType)
+	{
+		if (internalUpdate)
+			return false;
+		else
+		{
+			const char *textypestr = "unknown";
+			const char *shadertextypestr = "unknown";
+			Texture::getConstant(tex->getTextureType(), textypestr);
+			Texture::getConstant(info->textureType, shadertextypestr);
+			throw love::Exception("Texture's type (%s) must match the type of %s (%s).", textypestr, info->name.c_str(), shadertextypestr);
+		}
+	}
+
+	return true;
+}
+
+static bool isTexelBufferTypeCompatible(DataBaseType a, DataBaseType b)
+{
+	if (a == DATA_BASETYPE_FLOAT || a == DATA_BASETYPE_UNORM || a == DATA_BASETYPE_SNORM)
+		return b == DATA_BASETYPE_FLOAT || b == DATA_BASETYPE_UNORM || b == DATA_BASETYPE_SNORM;
+
+	if (a == DATA_BASETYPE_INT && b == DATA_BASETYPE_INT)
+		return true;
+
+	if (a == DATA_BASETYPE_UINT && b == DATA_BASETYPE_UINT)
+		return true;
+
+	return false;
+}
+
+bool Shader::validateBuffer(const UniformInfo *info, Buffer *buffer, bool internalUpdate)
+{
+	uint32 requiredtypeflags = 0;
+
+	bool texelbinding = info->baseType == UNIFORM_TEXELBUFFER;
+	bool storagebinding = info->baseType == UNIFORM_STORAGEBUFFER;
+
+	if (texelbinding)
+		requiredtypeflags = BUFFERUSAGEFLAG_TEXEL;
+	else if (storagebinding)
+		requiredtypeflags = BUFFERUSAGEFLAG_SHADER_STORAGE;
+
+	if ((buffer->getUsageFlags() & requiredtypeflags) == 0)
+	{
+		if (internalUpdate)
+			return false;
+		else if (texelbinding)
+			throw love::Exception("Shader uniform '%s' is a texel buffer, but the given Buffer was not created with texel buffer capabilities.", info->name.c_str());
+		else if (storagebinding)
+			throw love::Exception("Shader uniform '%s' is a shader storage buffer block, but the given Buffer was not created with shader storage buffer capabilities.", info->name.c_str());
+		else
+			throw love::Exception("Shader uniform '%s' does not match the types supported by the given Buffer.", info->name.c_str());
+	}
+
+	if (texelbinding)
+	{
+		DataBaseType basetype = buffer->getDataMember(0).info.baseType;
+		if (!isTexelBufferTypeCompatible(basetype, info->texelBufferType))
+		{
+			if (internalUpdate)
+				return false;
+			else
+				throw love::Exception("Texel buffer's data format base type must match the variable declared in the shader.");
+		}
+	}
+	else if (storagebinding)
+	{
+		if (info->bufferStride != buffer->getArrayStride())
+		{
+			if (internalUpdate)
+				return false;
+			else
+				throw love::Exception("Shader storage block '%s' has an array stride of %d bytes, but the given Buffer has an array stride of %d bytes.",
+					info->name.c_str(), info->bufferStride, buffer->getArrayStride());
+		}
+		else if (info->bufferMemberCount != buffer->getDataMembers().size())
+		{
+			if (internalUpdate)
+				return false;
+			else
+				throw love::Exception("Shader storage block '%s' has a struct with %d fields, but the given Buffer has a format with %d members.",
+					info->name.c_str(), info->bufferMemberCount, buffer->getDataMembers().size());
+		}
+	}
+
+	return true;
+}
+
 bool Shader::initialize()
 bool Shader::initialize()
 {
 {
 	return glslang::InitializeProcess();
 	return glslang::InitializeProcess();

+ 3 - 0
src/modules/graphics/Shader.h

@@ -243,6 +243,9 @@ protected:
 
 
 	static bool validateInternal(ShaderStage* vertex, ShaderStage* pixel, std::string& err, ValidationReflection &reflection);
 	static bool validateInternal(ShaderStage* vertex, ShaderStage* pixel, std::string& err, ValidationReflection &reflection);
 
 
+	static bool validateTexture(const UniformInfo *info, Texture *tex, bool internalUpdate);
+	static bool validateBuffer(const UniformInfo *info, Buffer *buffer, bool internalUpdate);
+
 	StrongRef<ShaderStage> stages[ShaderStage::STAGE_MAX_ENUM];
 	StrongRef<ShaderStage> stages[ShaderStage::STAGE_MAX_ENUM];
 
 
 	ValidationReflection validationReflection;
 	ValidationReflection validationReflection;

+ 5 - 96
src/modules/graphics/opengl/Shader.cpp

@@ -722,37 +722,8 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
 
 
 		if (tex != nullptr)
 		if (tex != nullptr)
 		{
 		{
-			const SamplerState &sampler = tex->getSamplerState();
-			if (!tex->isReadable())
-			{
-				if (internalUpdate)
-					continue;
-				else
-					throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader.");
-			}
-			else if (info->isDepthSampler != sampler.depthSampleMode.hasValue)
-			{
-				if (internalUpdate)
-					continue;
-				else if (info->isDepthSampler)
-					throw love::Exception("Depth comparison samplers in shaders can only be used with depth textures which have depth comparison set.");
-				else
-					throw love::Exception("Depth textures which have depth comparison set can only be used with depth/shadow samplers in shaders.");
-			}
-			else if (tex->getTextureType() != info->textureType)
-			{
-				if (internalUpdate)
-					continue;
-				else
-				{
-					const char *textypestr = "unknown";
-					const char *shadertextypestr = "unknown";
-					Texture::getConstant(tex->getTextureType(), textypestr);
-					Texture::getConstant(info->textureType, shadertextypestr);
-					throw love::Exception("Texture's type (%s) must match the type of %s (%s).", textypestr, info->name.c_str(), shadertextypestr);
-				}
-			}
-
+			if (!validateTexture(info, tex, internalUpdate))
+				continue;
 			tex->retain();
 			tex->retain();
 		}
 		}
 
 
@@ -782,33 +753,12 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe
 	Shader::sendBuffers(info, buffers, count, false);
 	Shader::sendBuffers(info, buffers, count, false);
 }
 }
 
 
-static bool isTexelBufferTypeCompatible(DataBaseType a, DataBaseType b)
-{
-	if (a == DATA_BASETYPE_FLOAT || a == DATA_BASETYPE_UNORM || a == DATA_BASETYPE_SNORM)
-		return b == DATA_BASETYPE_FLOAT || b == DATA_BASETYPE_UNORM || b == DATA_BASETYPE_SNORM;
-
-	if (a == DATA_BASETYPE_INT && b == DATA_BASETYPE_INT)
-		return true;
-
-	if (a == DATA_BASETYPE_UINT && b == DATA_BASETYPE_UINT)
-		return true;
-
-	return false;
-}
-
 void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count, bool internalUpdate)
 void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count, bool internalUpdate)
 {
 {
-	uint32 requiredtypeflags = 0;
-
 	bool texelbinding = info->baseType == UNIFORM_TEXELBUFFER;
 	bool texelbinding = info->baseType == UNIFORM_TEXELBUFFER;
 	bool storagebinding = info->baseType == UNIFORM_STORAGEBUFFER;
 	bool storagebinding = info->baseType == UNIFORM_STORAGEBUFFER;
 
 
-	if (texelbinding)
-		requiredtypeflags = BUFFERUSAGEFLAG_TEXEL;
-	else if (storagebinding)
-		requiredtypeflags = BUFFERUSAGEFLAG_SHADER_STORAGE;
-
-	if (requiredtypeflags == 0)
+	if (!texelbinding && !storagebinding)
 		return;
 		return;
 
 
 	bool shaderactive = current == this;
 	bool shaderactive = current == this;
@@ -825,49 +775,8 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe
 
 
 		if (buffer != nullptr)
 		if (buffer != nullptr)
 		{
 		{
-			if ((buffer->getUsageFlags() & requiredtypeflags) == 0)
-			{
-				if (internalUpdate)
-					continue;
-				else if (texelbinding)
-					throw love::Exception("Shader uniform '%s' is a texel buffer, but the given Buffer was not created with texel buffer capabilities.", info->name.c_str());
-				else if (storagebinding)
-					throw love::Exception("Shader uniform '%s' is a shader storage buffer block, but the given Buffer was not created with shader storage buffer capabilities.", info->name.c_str());
-				else
-					throw love::Exception("Shader uniform '%s' does not match the types supported by the given Buffer.", info->name.c_str());
-			}
-
-			if (texelbinding)
-			{
-				DataBaseType basetype = buffer->getDataMember(0).info.baseType;
-				if (!isTexelBufferTypeCompatible(basetype, info->texelBufferType))
-				{
-					if (internalUpdate)
-						continue;
-					else
-						throw love::Exception("Texel buffer's data format base type must match the variable declared in the shader.");
-				}
-			}
-			else if (storagebinding)
-			{
-				if (info->bufferStride != buffer->getArrayStride())
-				{
-					if (internalUpdate)
-						continue;
-					else
-						throw love::Exception("Shader storage block '%s' has an array stride of %d bytes, but the given Buffer has an array stride of %d bytes.",
-							info->name.c_str(), info->bufferStride, buffer->getArrayStride());
-				}
-				else if (info->bufferMemberCount != buffer->getDataMembers().size())
-				{
-					if (internalUpdate)
-						continue;
-					else
-						throw love::Exception("Shader storage block '%s' has a struct with %d fields, but the given Buffer has a format with %d members.",
-							info->name.c_str(), info->bufferMemberCount, buffer->getDataMembers().size());
-				}
-			}
-
+			if (!validateBuffer(info, buffer, internalUpdate))
+				continue;
 			buffer->retain();
 			buffer->retain();
 		}
 		}