diff options
| -rw-r--r-- | c2.cpp | 32 | ||||
| -rw-r--r-- | convmodel.c | 3 | ||||
| -rw-r--r-- | intermediate/surface.glsl | 51 | ||||
| -rw-r--r-- | model.cpp | 28 | ||||
| -rw-r--r-- | model.hpp | 2 | ||||
| -rw-r--r-- | pipeline.cpp | 13 | ||||
| -rw-r--r-- | sc/sc.cpp | 219 | ||||
| -rw-r--r-- | video.cpp | 173 | ||||
| -rw-r--r-- | video.hpp | 8 | 
9 files changed, 400 insertions, 129 deletions
| @@ -60,33 +60,6 @@ static Buffer_Id upload_verts(Device* dev) {  	return vbo;  } -Texture_Id make_default_texture(Device* dev) { -	unsigned* mem; -	Texture_Id tex; -	Buffer_Id buf = dev->create_buffer( -		"default texture stage", -		4, -		Buffer_Flags::copy_src | -		Buffer_Flags::cpu_readwrite -	); -	mem = (unsigned*)dev->map_buffer(buf, 0, 4); -	mem[0] = 0xffffffff; -	dev->unmap_buffer(buf); -	tex = dev->create_texture( -		"default PBR texture", -		texture_format_rgba8i, -		Texture_Flags::sampleable | Texture_Flags::copy_dst, -		1, -		1, -		1, -		1, -		1, -		buf -	); -	dev->destroy_bufferi(buf); -	return tex; -} -  static Sampler_Id create_clamped_linear(Device* dev) {  	Sampler_State s{};  	s.min = Filter_Mode::linear; @@ -642,7 +615,6 @@ struct C2 : public App {  	Collider* box_col, * floor_col;  	Texture* texture;  	Texture* texture2; -	Texture_Id default_texture;  	Entity_Id monkey, monkey2, box, floor;  	Model_Scene scene;  	Renderer renderer; @@ -694,11 +666,10 @@ struct C2 : public App {  		);  		assets.init(&asset_arena, "pack", 128);  		dev = Device::create(&video_arena, this);  -		default_texture = make_default_texture(dev);  		make_hdr_target();  		make_ui_texture();  		model_loader.init(dev, &assets); -		mat_loader.init(&assets, default_texture); +		mat_loader.init(&assets);  		register_asset_loader("MODL", &model_loader);  		register_asset_loader("MTRL", &mat_loader);  		shader = (Shader*)assets.load("triangle.csh"); @@ -1035,7 +1006,6 @@ struct C2 : public App {  		ui->destroy();  		deinit_editor();  		assets.destroy(); -		dev->destroy_texture(default_texture);  		dev->destroy_texture(hdr_target);  		dev->destroy_texture(hdr_resolved);  		dev->destroy_texture(ms_depth); diff --git a/convmodel.c b/convmodel.c index 31a062d..89f65c8 100644 --- a/convmodel.c +++ b/convmodel.c @@ -332,7 +332,7 @@ Shader_Attrib* parse_shader_attribs(const char* fname) {  	FILE* f;  	char magic[4];  	int type, i; -	int binding_count, target_count, desc_count; +	int binding_count, target_count, desc_count, opt_count;  	char* fpath = arena_alloc(  		&arena,  		string_len(fname) + @@ -362,6 +362,7 @@ Shader_Attrib* parse_shader_attribs(const char* fname) {  	fread(&binding_count, 4, 1, f);  	fread(&target_count, 4, 1, f);  	fread(&desc_count, 4, 1, f); +	fread(&opt_count, 4, 1, f);  	assert(binding_count);  	for (i = 0; i < binding_count; i++) {  		char name[24]; diff --git a/intermediate/surface.glsl b/intermediate/surface.glsl index ce80259..cc287e4 100644 --- a/intermediate/surface.glsl +++ b/intermediate/surface.glsl @@ -9,6 +9,22 @@ fragment: main  #ifdef DESC +[option] +name: albedomap +stage: fragment +[option] +name: aomap +stage: fragment +[option] +name: metalmap +stage: fragment +[option] +name: roughmap +stage: fragment +[option] +name: normalmap +stage: fragment +  [binding]  name: mesh  rate: vertex @@ -142,8 +158,8 @@ void main() {  #define pi 3.14159265358979323846 -vec3 diffuse_brdf(vec2 uv) { -	vec3 a = material.albedo * texture(albedo, uv).rgb; +vec3 diffuse_brdf(vec2 uv, vec3 base) { +	vec3 a = base;  	return a / pi;  } @@ -157,7 +173,11 @@ float specular_G1(float a, vec3 v, vec3 n) {  float specular_brdf(vec2 uv, vec3 ref, vec3 l, vec3 v, vec3 n) {  	float ndl = max(dot(n, l), 0.0);  	float ndv = max(dot(n, v), 0.0); +#if OPT_roughmap  	float a = texture(rough, uv).r * material.roughness; +#else +	float a = material.roughness; +#endif  	float a2 = a * a;  	float ndr = max(dot(n, ref), 0.0);  	float b = ((ndr * ndr) * (a2 - 1) + 1); @@ -244,26 +264,41 @@ void main() {  	vec2 uv = interpolator.uv;  	vec3 p = interpolator.position.xyz; +#if OPT_normalmap  	vec3 nrmsample = texture(normal, uv).rgb;  	vec2 nrmxy = nrmsample.xy * 2.0 - 1.0;  	vec3 nrm = normalize(vec3(nrmxy, 1.0)); -	if (nrmsample.b == 1.0) /* default texture */ -		nrm = normalize(interpolator.tbn[2]); -	else -		nrm = normalize(interpolator.tbn * nrm); +	nrm = normalize(interpolator.tbn * nrm); +#else +	vec3 nrm = normalize(interpolator.tbn[2]); +#endif +#if OPT_albedomap  	vec3 col = texture(albedo, uv).rgb * material.albedo; -	vec3 view_dir = normalize(globals.camera_pos - p); +#else +	vec3 col = material.albedo; +#endif + +#if OPT_metalmap  	float met = texture(metal, uv).r * material.metalness; +#else +	float met = material.metalness; +#endif + +	vec3 view_dir = normalize(globals.camera_pos - p);  	vec3 ref = reflect(-view_dir, nrm);  	vec3 ref_col = texture(env_cube, ref, material.roughness * 8.0).rgb;  	vec3 spec_col = mix(ref_col, ref_col * col, met);  	vec3 amb_col = min(textureLod(env_cube, nrm, 8.0).rgb, 0.05); +#if OPT_aomap  	vec3 ambient =  		amb_col *  		texture(ao, uv).r * material.ao; +#else +	vec3 ambient = amb_col * material.ao; +#endif -	vec3 base_diffuse = diffuse_brdf(uv) * (1.0 - met); +	vec3 base_diffuse = diffuse_brdf(uv, col) * (1.0 - met);  	vec3 light = 0.0.xxx;  	e = globals.sun_irange.y; @@ -32,20 +32,26 @@ void Material::use(  	Sampler_Id sampler,  	Shader& shader  ) { -	auto bind = [&shader, &pb, sampler]( +	int opt = 0; +	auto bind = [&shader, &pb, &opt, sampler](  		const char* name, +		const char* optname,  		Texture_Id t  	) {  		int loc = shader.descriptor_binding(name);  		if (loc >= 0) { -			pb.texture(loc, t, sampler); +			if (t) { +				pb.texture(loc, t, sampler); +				opt |= shader.opt_mask(shader_type_fragment, optname); +			}  		}  	}; -	bind("albedo", tex.albedo); -	bind("ao",     tex.ao); -	bind("metal",  tex.metal); -	bind("rough",  tex.rough); -	bind("normal", tex.normal); +	bind("albedo", "albedomap", tex.albedo); +	bind("ao",     "aomap",     tex.ao); +	bind("metal",  "metalmap",  tex.metal); +	bind("rough",  "roughmap",  tex.rough); +	bind("normal", "normalmap", tex.normal); +	pb.option(shader_type_fragment, opt);  }  void Model_Loader::init(Device* device, Asset_Arena* shader_arena) { @@ -214,10 +220,8 @@ void Model::update_transforms() {  }  void Material_Loader::init( -	Asset_Arena* texture_arena, -	Texture_Id dt +	Asset_Arena* texture_arena  ) { -	default_tex = dt;  	textures = texture_arena;  } @@ -235,11 +239,11 @@ Asset* Material_Loader::load(  		return r;  	};  	auto read_tex = [&](int len) { -		if (!len) return default_tex; +		if (!len) return Texture_Id(0);  		const char* name = read_name(len);  		auto t = (Texture*)textures->load(name);  		if (!t) -			return default_tex; +			return Texture_Id(0);  		return t->id;  	};  	(void)filename; @@ -85,7 +85,7 @@ struct Model_Loader : public Asset_Loader {  struct Material_Loader : public Asset_Loader {  	Asset_Arena* textures;  	Texture_Id default_tex; -	void init(Asset_Arena* texture_arena, Texture_Id dt); +	void init(Asset_Arena* texture_arena);  	Asset* load(  		Arena* a,  		Arena* s, diff --git a/pipeline.cpp b/pipeline.cpp index 374dad8..4d34ebd 100644 --- a/pipeline.cpp +++ b/pipeline.cpp @@ -254,6 +254,14 @@ Pipeline_Builder& Pipeline_Builder::shader(Shader_Id s) {  	return *this;  } +Pipeline_Builder& Pipeline_Builder::option( +	Shader_Type type, +	int mask +) { +	pip->shader_masks[type] = mask; +	return *this; +} +  Pipeline_Builder& Pipeline_Builder::texture(  	int binding,  	Texture_Id t, @@ -321,6 +329,7 @@ Pipeline& Pipeline_Builder::build() {  }  void Pipeline::hash() { +	int i;  #define h(n, v) \  	n = fnv1a64_2(n, (uint8_t*)&v, sizeof v)  	pipeline_hash = fnv1a64(0, 0); @@ -347,8 +356,10 @@ void Pipeline::hash() {  	h(pipeline_hash, blend_src_alpha);  	h(pipeline_hash, blend_dst_alpha);  	h(pipeline_hash, cull_mode); +	for (i = 0; i < shader_type_count; i++) +		h(pipeline_hash, shader_masks[i]);  	{ -		int i, e = descriptor_count; +		int e = descriptor_count;  		descriptor_resource_hash = fnv1a64(0, 0);  		for (i = 0; i < e; i++) {  			Descriptor* d = &descriptors[i]; @@ -225,6 +225,10 @@ struct Desc {  		int stage;  		std::string strct;  	}; +	struct Option { +		int stage; +		int mask; +	};  	int type;  	std::vector<Binding> bindings;  	std::vector<Variable> trgts; @@ -233,8 +237,10 @@ struct Desc {  	std::unordered_map<std::string, Texture> textures;  	std::unordered_map<std::string, CBuffer> cbuffers;  	std::unordered_map<std::string, SBuffer> sbuffers; +	std::unordered_map<std::string, Option> options;  	std::vector<Descriptor> descriptors;  	std::string entrypoints[shader_type_count]; +	int copts[shader_type_count];  	void read_var(Variable& d, cfg_Object* desc) {  		const char* sname = find_string_default(desc, "name", 0);  		if (!sname) { @@ -397,10 +403,40 @@ struct Desc {  		buf.stage |= 1 << stage_from_string(sstage);  	} +	void read_opt(cfg_Object* desc) { +		const char* sname = find_string_default(desc, "name", 0); +		if (!sname) { +			print_err("%s must have a name.\n", desc->name); +			pbreak(1001); +		} +		const char* sstage = find_string_default(desc, "stage", 0); +		if (!sstage) { +			print_err("%s must define a stage.\n", sname); +			pbreak(1002); +		} +		std::string n(sname); +		if (n.size() > 23) { +			print_err("Option name %s is too long (max 23 chars).\n", sname); +			pbreak(1003); +		} +		if (!options.contains(n)) { +			Option& o = options[n]; +			o.mask = 0; +			o.stage = 0; +		} +		int stage = stage_from_string(sstage); +		Option& opt = options[n]; +		opt.stage |= 1 << stage; +		opt.mask = copts[stage]; +		copts[stage] <<= 1; +	} +  	void build(cfg_Object* desc) {  		int i;  		Binding* cur_binding = 0;  		type = get_program_type(desc); +		for (i = 0; i < shader_type_count; i++) +			copts[i] = 1;  		if (type != sprogram_type_graphics) {  			assert(0); /* todo */  			return; @@ -450,6 +486,8 @@ struct Desc {  			} else if (!strcmp(desc->name, "struct")) {  				desc = read_struct(desc);  				continue; +			} else if (!strcmp(desc->name, "option")) { +				read_opt(desc);  			}  			desc = desc->next;  		} @@ -628,22 +666,35 @@ std::vector<uint32_t> compile_shader(  	const char* src,  	const char* define,  	int stage, +	int opt,  	EShLanguage lang  ) {  	std::string vars = d.build_vs(); -	const char* srcs[] = { +	std::vector<const char*> srcs = {  		glsl_version_s, "\n",  		"#define ", define, "\n",  		builtin_src, -		presrc, -		src +		presrc  	}; -	const char* src_names[] = { +	std::vector<const char*> src_names = {  		sname, sname,  		sname, sname, sname, -		sname, sname, sname +		sname, sname  	}; -	static_assert(sizeof srcs == sizeof src_names); +	for (const auto& p : d.options) { +		const auto& o = p.second; +		std::string def = "#define OPT_" + p.first + " "; +		if (opt & o.mask) +			def += "1\n"; +		else +			def += "0\n"; +		/* memory leak lol */ +		srcs.push_back(strdup(def.c_str())); +		src_names.push_back(sname); +	} +	srcs.push_back(src); +	src_names.push_back(sname); +	assert(src_names.size() == srcs.size());  	glslang::TShader shader(lang);  	glslang::TProgram program;  	glslang::TIntermediate* ir; @@ -663,10 +714,10 @@ std::vector<uint32_t> compile_shader(  #endif  	EShMessages msg = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);  	shader.setStringsWithLengthsAndNames( -		srcs, +		&srcs[0],  		0, -		src_names, -		sizeof srcs / sizeof *srcs +		&src_names[0], +		src_names.size()  	);  	shader.setEnvClient(glslang::EShClientVulkan, client_version);  	shader.setEnvTarget(glslang::EShTargetSpv, target_version); @@ -736,10 +787,23 @@ void configure(  	}  } +struct H_Variant { +	int o = -1, s; +	int mask; +	int pad = 0; +}; +struct H_Option { +	char name[24] = { 0 }; +	int mask; +	int stage; +}; +static_assert(sizeof(H_Variant) == 16); +using Variant_Map = std::unordered_map<int, std::vector<uint32_t>>; +  void compile_shaders(  	const char* sname,  	const char* fname, -	std::vector<uint32_t>* spv, +	Variant_Map* spv,  	const char* src,  	Desc& d  ) { @@ -747,19 +811,40 @@ void compile_shaders(  	EShLanguage lang;  	int i;  	for (i = 0; i < shader_type_count; i++) { +		int sm = 1 << i;  		if (!d.entrypoints[i].empty()) {  			std::string ps; +			int opt = 0, j;  			configure(d, i, define, lang, ps); -			spv[i] = compile_shader( -				d, -				sname, -				fname, -				ps.c_str(), -				src, -				define, -				i, -				lang -			); +			for (const auto& p : d.options) { +				if (~p.second.stage & sm) continue; +				opt |= p.second.mask; +			} +			for (j = 0; j <= opt; j++) { +				spv[i][j] = compile_shader( +					d, +					sname, +					fname, +					ps.c_str(), +					src, +					define, +					i, +					j, +					lang +				); +			} +			if (!opt) +				spv[i][0] = compile_shader( +					d, +					sname, +					fname, +					ps.c_str(), +					src, +					define, +					i, +					0, +					lang +				);  		}  	}  } @@ -767,10 +852,14 @@ void compile_shaders(  void write_csh(  	const char* fname,  	const Desc& d, -	const std::vector<uint32_t>* stages +	Variant_Map* stages  ) { -	int hsize = 20, i, coff; +	int hsize = 24, i, coff;  	FILE* f = fopen(fname, "wb"); +	H_Variant* variants[shader_type_count]; +	H_Option* hopts = 0; +	int vc[shader_type_count]; +	std::vector<const std::vector<uint32_t>*> order;  	if (!f) {  		print_err("Failed to open %s\n", fname);  		pbreak(500); @@ -781,6 +870,7 @@ void write_csh(  	c = d.bindings.size(); fwrite(&c, 4, 1, f);  	c = d.trgts.size(); fwrite(&c, 4, 1, f);  	c = d.descriptors.size(); fwrite(&c, 4, 1, f); +	c = d.options.size(); fwrite(&c, 4, 1, f);  	for (const auto& b : d.bindings) {  		char buf[24];  		int count = b.attrs.size(); @@ -816,36 +906,79 @@ void write_csh(  		fwrite(&d.stage, 4, 1, f);  		hsize += 32;  	} -	hsize += shader_type_count * 32; -	for (i = 0, coff = 0; i < shader_type_count; i++) { -		int o = 0; -		char buf[24]; -		memset(buf, 0, sizeof buf); -		if (d.entrypoints[i].empty()) { -			fwrite(&o, 4, 1, f); -			fwrite(&o, 4, 1, f); -		} else { -			int size = stages[i].size() * sizeof(uint32_t); -			strcpy(buf, d.entrypoints[i].c_str()); -			o = hsize + coff; -			fwrite(&o, 4, 1, f); -			fwrite(&size, 4, 1, f); -			coff += size; +	if (d.options.size()) +		hopts = new H_Option[d.options.size()]; +	for (const auto& p : d.options) { +		const auto& name = p.first; +		const auto& o = p.second; +		int count = d.options.size(); +		int j, bucket = (int)( +			hash_string(name.c_str()) % +			count +		); +		for (j = 0; j < count; j++) { +			auto& ho = hopts[j]; +			if (!ho.name[0]) { +				strcpy(ho.name, name.c_str()); +				ho.mask = o.mask; +				ho.stage = o.stage; +				goto oklmao; +			} +			bucket = (bucket + 1) % count;  		} -		fwrite(buf, 1, sizeof buf, f); +		assert(0); +		oklmao: +		hsize += 32;  	} -	for (i = 0; i < shader_type_count; i++) -		if (!d.entrypoints[i].empty()) { -			auto& stage = stages[i]; -			fwrite(&stage[0], sizeof(uint32_t), stage.size(), f); +	fwrite(hopts, sizeof *hopts, d.options.size(), f); +	delete[] hopts; +	for (i = 0; i < shader_type_count; i++) { +		vc[i] = stages[i].size(); +		hsize += vc[i] * 16 + 4; +		variants[i] = new H_Variant[vc[i]]; +	} +	for (i = 0, coff = 0; i < shader_type_count; i++) { +		fwrite(&vc[i], 4, 1, f); +		for (const auto& p : stages[i]) { +			int mask = p.first, j; +			int bucket = (int)( +				fnv1a64((uint8_t*)&mask, sizeof mask) % +				vc[i] +			); +			for (j = 0; j < vc[i]; j++) { +				H_Variant& v = variants[i][bucket]; +				if (v.o == -1) { +					auto& arr = p.second; +					v.o = coff + hsize; +					v.s = arr.size() * sizeof(uint32_t); +					v.mask = mask; +					coff += v.s; +					order.push_back(&arr); +					goto done; +				} +				bucket = (bucket +  1) % vc[i]; +			} +			assert(0); +			done:;  		} +		fwrite(variants[i], sizeof(H_Variant), vc[i], f); +		delete[] variants[i]; +	} +	for (auto bytecode : order) { +		fwrite( +			&(*bytecode)[0], +			sizeof(uint32_t), +			bytecode->size(), +			f +		); +	}  }  int main(int argc, const char** argv) {  	char* src;  	size_t src_size;  	std::string desc_src; -	std::vector<uint32_t> spv[shader_type_count]; +	Variant_Map spv[shader_type_count];  	cfg_Object* cdesc;  	void* dp_mem;  	Desc desc; @@ -430,6 +430,12 @@ enum {  	context_state_init  = 1 << 1  }; + +struct Shader_Module { +	int mask; +	VkShaderModule mod; +}; +  struct Shader_Vk : public Shader, public Late_Terminated {  	struct Attribute {  		char name[28]; @@ -464,23 +470,31 @@ struct Shader_Vk : public Shader, public Late_Terminated {  		int stage;  	}; +	struct Option { +		char name[24]; +		int mask; +		int stage; +	}; +  	SProgram_Type type; -	VkShaderModule modules[shader_type_count]; -	char entrypoints[shader_type_count][24];  	Vertex_Format vfd;  	Desc* descs; -	int desc_count; +	Shader_Module* modules[shader_type_count]; +	Option* options; +	int desc_count, opt_count; +	int module_count[shader_type_count]; -	bool init(Device_Vk* dev, Pack_File* f); -	bool init_module( +	bool init(Device_Vk* dev, Arena* a, Pack_File* f); +	VkShaderModule make_module(  		Device_Vk* dev, -		int stage,  		char* buf,  		int size  	);  	void destroy(Device_Vk* dev) override;  	int find_descriptor(const char* name); +	int find_module(Shader_Type type, int mask); +	int find_opt(Shader_Type, const char* name);  	static VkShaderStageFlagBits stage(Shader_Type type) {  		switch (type) { @@ -2811,12 +2825,24 @@ void Pipeline_Vk::init_stages(  	zero(sis, sizeof *sis * count);  	for (i = 0, count = 0; i < shader_type_count; i++) {  		if (shader.modules[i]) { +			int idx = shader.find_module( +				(Shader_Type)i, +				desc.shader_masks[i] +			); +			VkShaderModule mod; +			if (idx < 0) { +				mod = shader.modules[i][0].mod; +				print_war("Shader variant not found; using the default >~<\n"); +				print("  ^ mask was 0x%x\n", desc.shader_masks[i]); +			} else +				mod = shader.modules[i][idx].mod; +			assert(idx >= 0);  			auto& si = sis[i];  			si.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;  			si.flags = 0;  			si.stage = Shader_Vk::stage((Shader_Type)i); -			si.module = shader.modules[i]; -			si.pName = shader.entrypoints[i]; +			si.module = mod; +			si.pName = "main";  			count++;  		}  	} @@ -3396,9 +3422,8 @@ void Vertex_Format_Vk::optimise(const Vertex_Format_Vk* shadervf) {  	}  } -bool Shader_Vk::init_module( +VkShaderModule Shader_Vk::make_module(  	Device_Vk* dev, -	int stage,  	char* buf,  	int size  ) { @@ -3409,8 +3434,9 @@ bool Shader_Vk::init_module(  	mi.codeSize = size;  	mi.pCode = (uint32_t*)buf;  	r = vkCreateShaderModule(dev->dev, &mi, &dev->ac, &m); -	modules[stage] = m; -	return r == VK_SUCCESS; +	if (r == VK_SUCCESS) +		return m; +	return 0;  }  int Shader_Vk::Vertex_Format::find_binding(const char* name) { @@ -3522,8 +3548,11 @@ void Shader_Vk::Vertex_Format::destroy(Device_Vk* dev) {  void Shader_Vk::destroy(Device_Vk* dev) {  	int i;  	for (i = 0; i < shader_type_count; i++) -		if (modules[i]) -			vkDestroyShaderModule(dev->dev, modules[i], &dev->ac); +		if (modules[i]) { +			int j, e = module_count[i]; +			for (j = 0; j < e; j++) +				vkDestroyShaderModule(dev->dev, modules[i][j].mod, &dev->ac); +		}  	vfd.destroy(dev);  	heap_free(dev->heap, descs);  	dev->destroy_vertex_format(vf); @@ -3554,6 +3583,11 @@ int Shader::descriptor_binding(const char* name) {  	return sh->descs[idx].slot;  } +int Shader::opt_mask(Shader_Type type, const char* name) { +	Shader_Vk* sh = (Shader_Vk*)this; +	return sh->find_opt(type, name); +} +  int Shader::descriptor_stage(int slot) {  	Shader_Vk* sh = (Shader_Vk*)this;  	int i; @@ -3909,11 +3943,10 @@ Asset* Shader_Loader::load(  	Shader_Vk* shader;  	Shader_Id id;  	(void)s; -	(void)a;  	(void)filename;  	id = dev->alloc_shader();  	shader = (Shader_Vk*)&dev->get_shader(id); -	if (!shader->init(dev, f)) { +	if (!shader->init(dev, a, f)) {  		dev->shaders.remove(id);  		return 0;  	} @@ -3939,7 +3972,46 @@ int Shader_Vk::find_descriptor(const char* name) {  	return -1;  } -bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) { +int Shader_Vk::find_module( +	Shader_Type type, +	int mask +) { +	int i; +	int count = module_count[type]; +	Shader_Module* arr = modules[type]; +	int bucket = (int)( +		fnv1a64((uint8_t*)&mask, sizeof mask) % +		count +	); +	for (i = 0; i < count; i++) { +		Shader_Module& mod = arr[bucket]; +		if (mod.mask == mask) +			return bucket; +		bucket = (bucket + 1) % count; +	} +	return -1; +} + +int Shader_Vk::find_opt( +	Shader_Type type, +	const char* name +) { +	int count = module_count[type], i; +	int bucket = (int)( +		hash_string(name) % +		count +	); +	int stage = 1 << type; +	for (i = 0; i < count; i++) { +		Option& o = options[bucket]; +		if (string_equal(name, o.name) && (o.stage & stage)) +			return o.mask; +		bucket = (bucket + 1) % count; +	} +	return 0; +} + +bool Shader_Vk::init(Device_Vk* dev, Arena* a, Pack_File* f) {  	char magic[4];  	int binding_count, target_count, i;  	pack_read(f, magic, 4); @@ -3953,6 +4025,7 @@ bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) {  	pack_read(f, &binding_count, 4);  	pack_read(f, &target_count, 4);  	pack_read(f, &desc_count, 4); +	pack_read(f, &opt_count, 4);  	assert(binding_count);  	vfd.binding_count = binding_count;  	if (!vfd.init(dev, f)) @@ -4000,24 +4073,60 @@ bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) {  		desc_count * sizeof *descs  	);  	pack_read(f, descs, desc_count * sizeof *descs); +	options = (Option*)arena_alloc( +		a, +		opt_count * sizeof *options +	); +	pack_read(f, options, opt_count * sizeof *options);  	for (i = 0; i < shader_type_count; i++) { -		int o, s; -		pack_read(f, &o, 4); -		pack_read(f, &s, 4); -		if (o) { -			bool r; -			int before = pack_tell(f); -			char* buf = (char*)heap_alloc(dev->heap, s); -			pack_seek(f, o, seek_rel_start); -			pack_read(f, buf, s); -			r = init_module(dev, i, buf, s); -			heap_free(dev->heap, buf); -			pack_seek(f, before, seek_rel_start); -			if (!r) return false; +		int c; +		pack_read(f, &c, 4); +		module_count[i] = c; +		if (c) { +			int o, s, mask; +			int bucket, j; +			Shader_Module* m = (Shader_Module*)arena_alloc( +				a, +				c * sizeof *m +			); +			for (j = 0; j < c; j++) { +				m[j].mask = -1; +			} +			for (j = 0; j < c; j++) { +				int k; +				pack_read(f, &o,    4); /* H_Variant */ +				pack_read(f, &s,    4); +				pack_read(f, &mask, 4); +				pack_seek(f, 4, seek_rel_cur); +				bucket = (int)( +					fnv1a64((uint8_t*)&m, sizeof m) % +					c +				); +				for (k = 0; k < c; k++) { +					Shader_Module& mod = m[bucket]; +					if (mod.mask == -1) +						goto found; +					bucket = (bucket + 1) % c; +				} +				assert(0); +				{ +					found: +					char* buf = (char*)heap_alloc(dev->heap, s); +					VkShaderModule r; +					int before = pack_tell(f); +					pack_seek(f, o, seek_rel_start); +					pack_read(f, buf, s); +					r = make_module(dev, buf, s); +					heap_free(dev->heap, buf); +					pack_seek(f, before, seek_rel_start); +					if (!r) return false; +					m[bucket] = Shader_Module { mask, r }; +				} +			} +			modules[i] = m;  		} else { -			modules[i] = VK_NULL_HANDLE; +			modules[i] = 0;  		} -		pack_read(f, entrypoints[i], 24);  	}  	return true;  } @@ -134,12 +134,18 @@ struct Pipeline {  	Vertex_Format_Id vertex_format;  	Shader_Id shader;  	int samples; +	int shader_masks[shader_type_count];  	Descriptor descriptors[pipeline_max_descriptors];  	int descriptor_count;  	void hash();  	bool pipeline_eq(const Pipeline& other) const { +		int i; +		for (i = 0; i < shader_type_count; i++) { +			if (other.shader_masks[i] != shader_masks[i]) +				return false; +		}  		return  			shader == other.shader &&  			vertex_format == other.vertex_format && @@ -333,6 +339,7 @@ struct Pipeline_Builder {  	);  	PB& cull(Cull_Mode mode);  	PB& shader(Shader_Id s); +	PB& option(Shader_Type type, int mask);  	PB& vertex_format(Vertex_Format_Id vf);  	PB& texture(int binding, Texture_Id t, Sampler_Id s);  	PB& cbuffer( @@ -588,6 +595,7 @@ struct Shader : public Asset {  	int attribute_index(const char* name);  	int target_index(const char* name);  	int descriptor_binding(const char* name); +	int opt_mask(Shader_Type type, const char* name);  	int descriptor_stage(int slot);  }; |