Browse Source

vulkan: uniforms in custom shaders

things like `uniform float time;` or `uniform sampler2D tex` now work
niki 3 years ago
parent
commit
bc0b5f81f5
2 changed files with 95 additions and 121 deletions
  1. 91 117
      src/modules/graphics/vulkan/Shader.cpp
  2. 4 4
      src/modules/graphics/vulkan/Shader.h

+ 91 - 117
src/modules/graphics/vulkan/Shader.cpp

@@ -322,6 +322,20 @@ int Shader::getVertexAttributeIndex(const std::string& name) {
 	return 0;
 }
 
+const Shader::UniformInfo* Shader::getUniformInfo(const std::string& name) const {
+	return &uniformInfos.at(name);
+}
+
+const Shader::UniformInfo* Shader::getUniformInfo(BuiltinUniform builtin) const {
+	return builtinUniformInfo[builtin];
+}
+
+void Shader::sendTextures(const UniformInfo* info, graphics::Texture** textures, int count) {
+	for (unsigned i = 0; i < count; i++) {
+		info->textures[i] = textures[i];
+	}
+}
+
 void Shader::calculateUniformBufferSizeAligned() {
 	gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
 	auto vgfx = (Graphics*)gfx;
@@ -341,7 +355,7 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross::
 
 	const auto& membertypes = type.member_types;
 
-	for (size_t uindex = 0; uindex < membertypes.size(); uindex) {
+	for (size_t uindex = 0; uindex < membertypes.size(); uindex++) {
 		const auto& memberType = comp.get_type(membertypes[uindex]);
 		size_t memberSize = comp.get_declared_struct_member_size(type, uindex);
 		size_t offset = baseoff + comp.type_struct_member_offset(type, uindex);
@@ -361,7 +375,7 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross::
 			continue;
 		}
 
-		UniformInfo u = {};
+		UniformInfo u{};
 		u.name = name;
 		u.dataSize = memberSize;
 		u.count = memberType.array.empty() ? 1 : memberType.array[0];
@@ -397,8 +411,6 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross::
 			}
 			builtinUniformInfo[builtin] = &uniformInfos[u.name];
 		}
-
-		// update uniform.
 	}
 }
 
@@ -509,129 +521,87 @@ void Shader::compileShaders() {
 		auto shaderResources = comp.get_shader_resources(active);
 		comp.set_enabled_interface_variables(std::move(active));
 
-		std::string builtinUniformName = "love_UniformsPerDraw";
-
 		for (const auto& resource : shaderResources.uniform_buffers) {
-			size_t uniformBufferObjectSize = comp.get_declared_struct_size(comp.get_type(resource.base_type_id));
-
-			const auto& resourceType = comp.get_type(resource.type_id);
-			unsigned memberCount = resourceType.member_types.size();
-			for (unsigned i = 0; i < memberCount; i++) {
-				auto& type = comp.get_type(resourceType.member_types[i]);
-				auto baseType = type.basetype;
-				const std::string& name = comp.get_member_name(resourceType.self, i);
+			if (resource.name == "gl_DefaultUniformBlock") {
+				const auto& type = comp.get_type(resource.base_type_id);
+				size_t uniformBufferObjectSize = comp.get_declared_struct_size(type);
+				auto defaultUniformBlockSize = comp.get_declared_struct_size(type);
+				localUniformStagingData.resize(defaultUniformBlockSize);
 
-				if (name == "gl_DefaultUniformBlock") {
-					auto defaultUniformBlockSize = comp.get_declared_struct_size(type);
-					localUniformStagingData.resize(defaultUniformBlockSize);
+				memset(localUniformStagingData.data(), 0, defaultUniformBlockSize);
 
-					std::string basename("");
-					buildLocalUniforms(comp, type, 0, basename);
-				}
-				else if (name == builtinUniformName) {
-					UniformInfo u{};
-					u.name = name;
-					u.dataSize = sizeof(BuiltinUniformData);
-
-					localUniformStagingData.resize(u.dataSize);
-					builtinUniformDataOffset = 0;
-
-					u.count = type.array.empty() ? 1 : type.array[0];
-					u.components = 1;
-					u.data = localUniformStagingData.data();
-
-					if (type.columns == 1) {
-						if (type.basetype == SPIRType::Int) {
-							u.baseType = UNIFORM_INT;
-						}
-						else if (type.basetype == SPIRType::UInt) {
-							u.baseType = UNIFORM_UINT;
-						}
-						else {
-							u.baseType = UNIFORM_FLOAT;
-						}
-						u.components = type.vecsize;
-					}
-					else {
-						u.baseType = UNIFORM_MATRIX;
-						u.matrix.rows = type.vecsize;
-						u.matrix.columns = type.columns;
-					}
-
-					uniformInfos[u.name] = u;
-
-					builtinUniformInfo[BUILTIN_UNIFORMS_PER_DRAW] = &uniformInfos[u.name];
-				}
-				else {
-					throw love::Exception("unimplemented: non default uniform blocks.");
-				}
+				std::string basename("");
+				buildLocalUniforms(comp, type, 0, basename);
 			}
+			else {
+				throw love::Exception("unimplemented: non default uniform blocks.");
+			}
+		}
 
-			for (const auto& r : shaderResources.sampled_images) {
-				const SPIRType& basetype = comp.get_type(r.base_type_id);
-				const SPIRType& type = comp.get_type(r.type_id);
-				const SPIRType& imagetype = comp.get_type(basetype.image.type);
-
-				graphics::Shader::UniformInfo info;
-				info.location = comp.get_decoration(r.id, spv::DecorationBinding);
-				info.baseType = UNIFORM_SAMPLER;
-				info.name = r.name;
-				info.count = type.array.empty() ? 1 : type.array[0];
-				info.isDepthSampler = type.image.depth;
-				info.components = 1;
-
-				switch (imagetype.basetype) {
-				case SPIRType::Float:
-					info.dataBaseType = DATA_BASETYPE_FLOAT;
-					break;
-				case SPIRType::Int:
-					info.dataBaseType = DATA_BASETYPE_INT;
-					break;
-				case SPIRType::UInt:
-					info.dataBaseType = DATA_BASETYPE_UINT;
-					break;
-				default:
-					break;
-				}
+		for (const auto& r : shaderResources.sampled_images) {
+			const SPIRType& basetype = comp.get_type(r.base_type_id);
+			const SPIRType& type = comp.get_type(r.type_id);
+			const SPIRType& imagetype = comp.get_type(basetype.image.type);
+
+			graphics::Shader::UniformInfo info;
+			info.location = comp.get_decoration(r.id, spv::DecorationBinding);
+			info.baseType = UNIFORM_SAMPLER;
+			info.name = r.name;
+			info.count = type.array.empty() ? 1 : type.array[0];
+			info.isDepthSampler = type.image.depth;
+			info.components = 1;
+
+			switch (imagetype.basetype) {
+			case SPIRType::Float:
+				info.dataBaseType = DATA_BASETYPE_FLOAT;
+				break;
+			case SPIRType::Int:
+				info.dataBaseType = DATA_BASETYPE_INT;
+				break;
+			case SPIRType::UInt:
+				info.dataBaseType = DATA_BASETYPE_UINT;
+				break;
+			default:
+				break;
+			}
 
-				switch (basetype.image.dim) {
-				case spv::Dim2D:
-					info.textureType = basetype.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D;
-					info.textures = new love::graphics::Texture * [info.count];
-					break;
-				case spv::Dim3D:
-					info.textureType = TEXTURE_VOLUME;
-					info.textures = new love::graphics::Texture * [info.count];
-					break;
-				case spv::DimCube:
-					if (basetype.image.arrayed) {
-						throw love::Exception("cubemap arrays are not currently supported");
-					}
-					info.textureType = TEXTURE_CUBE;
-					info.textures = new love::graphics::Texture * [info.count];
-					break;
-				case spv::DimBuffer:
-					throw love::Exception("dim buffers not implemented yet");
-				default:
-					throw love::Exception("unknown dim");
+			switch (basetype.image.dim) {
+			case spv::Dim2D:
+				info.textureType = basetype.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D;
+				info.textures = new love::graphics::Texture * [info.count];
+				break;
+			case spv::Dim3D:
+				info.textureType = TEXTURE_VOLUME;
+				info.textures = new love::graphics::Texture * [info.count];
+				break;
+			case spv::DimCube:
+				if (basetype.image.arrayed) {
+					throw love::Exception("cubemap arrays are not currently supported");
 				}
+				info.textureType = TEXTURE_CUBE;
+				info.textures = new love::graphics::Texture * [info.count];
+				break;
+			case spv::DimBuffer:
+				throw love::Exception("dim buffers not implemented yet");
+			default:
+				throw love::Exception("unknown dim");
+			}
 
-				if (info.baseType == UNIFORM_SAMPLER) {
-					auto tex = vgfx->getDefaultTexture();
-					for (int i = 0; i < info.count; i++) {
-						info.textures[i] = tex;
-					}
-				}
-				// fixme
-				else if (info.baseType == UNIFORM_TEXELBUFFER) {
-					throw love::Exception("texel buffers not supported yet");
+			if (info.baseType == UNIFORM_SAMPLER) {
+				auto tex = vgfx->getDefaultTexture();
+				for (int i = 0; i < info.count; i++) {
+					info.textures[i] = tex;
 				}
+			}
+			// fixme
+			else if (info.baseType == UNIFORM_TEXELBUFFER) {
+				throw love::Exception("texel buffers not supported yet");
+			}
 
-				uniformInfos[r.name] = info;
-				BuiltinUniform builtin;
-				if (getConstant(r.name.c_str(), builtin)) {
-					builtinUniformInfo[builtin] = &uniformInfos[info.name];
-				}
+			uniformInfos[r.name] = info;
+			BuiltinUniform builtin;
+			if (getConstant(r.name.c_str(), builtin)) {
+				builtinUniformInfo[builtin] = &uniformInfos[info.name];
 			}
 		}
 	}
@@ -704,6 +674,10 @@ void Shader::setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cb
 	}
 }
 
+bool Shader::hasUniform(const std::string& name) const {
+	return uniformInfos.find(name) != uniformInfos.end();
+}
+
 void Shader::setUniformData(BuiltinUniformData& data) {
 	char* ptr = (char*) builtinUniformInfo[BUILTIN_UNIFORMS_PER_DRAW]->data + builtinUniformDataOffset;
 	memcpy(ptr, &data, sizeof(BuiltinUniformData));

+ 4 - 4
src/modules/graphics/vulkan/Shader.h

@@ -39,18 +39,18 @@ public:
 
 	int getVertexAttributeIndex(const std::string& name) override;
 
-	const UniformInfo* getUniformInfo(const std::string& name) const override { return nullptr; }
-	const UniformInfo* getUniformInfo(BuiltinUniform builtin) const override { return nullptr;  }
+	const UniformInfo* getUniformInfo(const std::string& name) const override;
+	const UniformInfo* getUniformInfo(BuiltinUniform builtin) const override;
 
 	// Not needed right now, since the logic that links the values of the uniforms to the shader is done in cmdPushDescriptorSets
 	// which gets called from the vulkan::Graphics class whenever a draw call happens.
 	// I'll have to reevaluate the use of this function in the future though.
 	void updateUniform(const UniformInfo* info, int count) override {}
 
-	void sendTextures(const UniformInfo* info, graphics::Texture** textures, int count) override {}
+	void sendTextures(const UniformInfo* info, graphics::Texture** textures, int count) override;
 	void sendBuffers(const UniformInfo* info, love::graphics::Buffer** buffers, int count) override {}
 
-	bool hasUniform(const std::string& name) const override { return false; }
+	bool hasUniform(const std::string& name) const override;
 
 	void setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cbtexture, graphics::Texture* crtexture) override;