diff options
Diffstat (limited to 'sc')
| -rw-r--r-- | sc/sc.cpp | 219 | 
1 files changed, 176 insertions, 43 deletions
@@ -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;  |