From 9974b95e123c0d2673a37820896edfb06cf4085d Mon Sep 17 00:00:00 2001 From: DH Date: Mon, 16 Nov 2015 19:57:49 +0200 Subject: [PATCH] Added draft projects Most features is broken/unstable/unimplemented/disabled --- rsx_decompiler/cache.h | 38 + rsx_decompiler/pch.cpp | 1 + rsx_decompiler/pch.h | 2 + rsx_decompiler/rsx_decompiler.cpp | 865 ++++++++++++++++++ rsx_decompiler/rsx_decompiler.h | 117 +++ rsx_decompiler/rsx_decompiler.vcxproj | 257 ++++++ rsx_decompiler/rsx_decompiler.vcxproj.filters | 21 + rsx_decompiler/rsx_fp_ucode.cpp | 49 + rsx_decompiler/rsx_fp_ucode.h | 212 +++++ rsx_program_decompiler.sln | 35 +- .../rsx_program_decompiler.cpp | 11 +- .../rsx_program_decompiler.vcxproj | 24 +- .../rsx_program_decompiler_lib.vcxproj | 36 +- shader_code/builder.cpp | 30 + shader_code/builder.h | 78 ++ shader_code/clike_builder.h | 337 +++++++ shader_code/clike_language.cpp | 15 + shader_code/clike_language.h | 579 ++++++++++++ shader_code/glsl_builder.h | 24 + shader_code/glsl_language.h | 268 ++++++ shader_code/pch.cpp | 1 + shader_code/pch.h | 1 + shader_code/shader_code.vcxproj | 170 ++++ shader_code/shader_code.vcxproj.filters | 42 + 24 files changed, 3164 insertions(+), 49 deletions(-) create mode 100644 rsx_decompiler/cache.h create mode 100644 rsx_decompiler/pch.cpp create mode 100644 rsx_decompiler/pch.h create mode 100644 rsx_decompiler/rsx_decompiler.cpp create mode 100644 rsx_decompiler/rsx_decompiler.h create mode 100644 rsx_decompiler/rsx_decompiler.vcxproj create mode 100644 rsx_decompiler/rsx_decompiler.vcxproj.filters create mode 100644 rsx_decompiler/rsx_fp_ucode.cpp create mode 100644 rsx_decompiler/rsx_fp_ucode.h create mode 100644 shader_code/builder.cpp create mode 100644 shader_code/builder.h create mode 100644 shader_code/clike_builder.h create mode 100644 shader_code/clike_language.cpp create mode 100644 shader_code/clike_language.h create mode 100644 shader_code/glsl_builder.h create mode 100644 shader_code/glsl_language.h create mode 100644 shader_code/pch.cpp create mode 100644 shader_code/pch.h create mode 100644 shader_code/shader_code.vcxproj create mode 100644 shader_code/shader_code.vcxproj.filters diff --git a/rsx_decompiler/cache.h b/rsx_decompiler/cache.h new file mode 100644 index 0000000..3ecbd11 --- /dev/null +++ b/rsx_decompiler/cache.h @@ -0,0 +1,38 @@ +#pragma once +#include + +template> +class cache_t +{ + std::unordered_map m_entries; + +public: + bool invalidate(const InfoType& key) + { + if (auto found = m_entries.find(key)) + { + m_entries.erase(found); + return true; + } + + return false; + } + + DataType& entry(const InfoType& key) + { + return m_entries[key]; + } + + const DataType& entry(const InfoType& key) const + { + return m_entries.at(key); + } + + void each(std::function)> function) + { + for (auto &entry : m_entries) + { + function(entry); + } + } +}; \ No newline at end of file diff --git a/rsx_decompiler/pch.cpp b/rsx_decompiler/pch.cpp new file mode 100644 index 0000000..bcb5590 --- /dev/null +++ b/rsx_decompiler/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/rsx_decompiler/pch.h b/rsx_decompiler/pch.h new file mode 100644 index 0000000..079a383 --- /dev/null +++ b/rsx_decompiler/pch.h @@ -0,0 +1,2 @@ +#pragma once + diff --git a/rsx_decompiler/rsx_decompiler.cpp b/rsx_decompiler/rsx_decompiler.cpp new file mode 100644 index 0000000..7621975 --- /dev/null +++ b/rsx_decompiler/rsx_decompiler.cpp @@ -0,0 +1,865 @@ +#include "pch.h" +#include "clike_builder.h" +#include +#include +#include +#include + +namespace rsx +{ + static const std::string index_to_channel[4] = { "x", "y", "z", "w" }; + static const std::unordered_map channel_to_index = { { 'x', 0 },{ 'y', 1 },{ 'z', 2 },{ 'w', 3 } }; + + template + struct decompiler_base : shader_code::clike_builder + { + template + static writer_t move_if(const expression_from> &cond, const std::string& operation, expression_t dst, const expression_t &src) + { + writer_t result; + + int dst_to_cond_swizzle[DstCount]; + + for (int i = 0; i < DstCount; ++i) + { + dst_to_cond_swizzle[i] = -1; + } + + for (int i = 0; i < DstCount; ++i) + { + int dst_mask = channel_to_index.at(dst.swizzle(i).mask[0]); + int cond_mask = channel_to_index.at(cond.swizzle(i).mask[0]); + + if (dst_to_cond_swizzle[dst_mask] != -1) + { + if (dst_to_cond_swizzle[dst_mask] != cond_mask) + { + std::cerr << "Bad conditional move swizzle! (old = " << dst_mask << ", new = " << cond_mask << ")" << std::endl; + } + } + else + { + dst_to_cond_swizzle[dst_mask] = cond_mask; + } + } + + for (int cond_index = 0; cond_index < 4; ++cond_index) + { + std::string dst_swizzle_text; + std::string src_swizzle_text; + + for (int dst_index = 0; dst_index < DstCount; ++dst_index) + { + if (dst_to_cond_swizzle[dst_index] == cond_index) + { + if (dst_index >= SrcCount) + { + //std::cerr << "Bad conditional move destination swizzle! (dst_index = " << dst_index << ") << std::endl; + continue; + } + + dst_swizzle_text += dst.swizzle(dst_index).mask; + src_swizzle_text += src.swizzle(dst_index).mask; + } + } + + if (dst_swizzle_text.empty()) + continue; + + if (dst_swizzle_text == "xyzw") + dst_swizzle_text.clear(); + + if (src_swizzle_text == "xyzw") + src_swizzle_text.clear(); + + expression_from> cond_expr(cond.text, index_to_channel[cond_index], false, cond.base_count); + expression_from> dst_expr(dst.text, dst_swizzle_text, false, dst.base_count); + expression_from> src_expr(src.text, src_swizzle_text, src.is_single, src.base_count); + static const expression_from> condition_value{ 0.0 }; + + result += if_(cond_expr.call_operator>(operation, condition_value), dst_expr = src_expr); + } + + return result; + } + + template + static writer_t move(expression_t dst, const expression_t &src) + { + writer_t result; + std::string src_swizzle_text; + + for (int i = 0; i < DstCount; ++i) + { + int dst_index = channel_to_index.at(dst.swizzle(i).mask[0]); + src_swizzle_text += src.swizzle(dst_index).mask[0]; + } + + if (src_swizzle_text == "xyzw") + src_swizzle_text.clear(); + + expression_from> dst_expr(dst.text, dst_swizzle_text, false, false); + expression_from> src_expr(src.text, src_swizzle_text, src.is_single, false); + static const expression_from> condition_value{ 0.0 }; + + result += if_(cond_expr.call_operator>(operation, condition_value), dst_expr = src_expr); + return result; + } + }; +} + +#include "glsl_language.h" +#include "rsx_fp_ucode.h" + +namespace rsx +{ + namespace fragment_program + { + class decompiler : public decompiler_base + { + enum class variable_modifier + { + none, + in, + out, + constant + }; + + struct context_t + { + struct variable_info + { + std::string type; + std::string name; + }; + + u32 offset; + + std::vector constants_offsets; + std::unordered_map variables; + + template> + expression_from variable(const std::string& name, variable_modifier modifier = variable_modifier::none) + { + variables[modifier] = { Type::name(), name }; + + return{ name }; + } + + expression_from> constant() + { + return variable("fc" + std::to_string(offset + sizeof(instruction_t))); + } + + expression_from> temp(int index) + { + return variable("tmp" + std::to_string(index)); + } + + expression_from> input(int index) + { + return variable(input_attrib_map[index]); + } + }; + + struct instruction_t + { + ucode_instr data; + + struct src_t + { + src_reg_type_t reg_type; + u32 tmp_index; + + u32 swizzle_x; + u32 swizzle_y; + u32 swizzle_z; + u32 swizzle_w; + + bool fp16; + bool neg; + bool abs; + }; + + template + static src_t unpack_src(const SrcType& src) + { + src_t result; + + result.reg_type = src.reg_type; + result.tmp_index = src.tmp_reg_index; + + result.swizzle_x = src.swizzle_x; + result.swizzle_y = src.swizzle_y; + result.swizzle_z = src.swizzle_z; + result.swizzle_w = src.swizzle_w; + + result.fp16 = src.fp16; + result.abs = src.abs; + result.neg = src.neg; + + return result; + } + + expression_from> src(context_t& context, int index) const + { + src_t src; + + switch (index) + { + case 0: src = unpack_src(data.src0); break; + case 1: src = unpack_src(data.src1); break; + case 2: src = unpack_src(data.src2); break; + } + + auto get_variable = [&](const src_t& src) + { + switch (src.reg_type) + { + case src_reg_type_t::temporary: return context.temp(src.tmp_index); + case src_reg_type_t::input: return context.input(data.dst.src_attr_reg_num); + case src_reg_type_t::constant: return context.constant(); + } + }; + + expression_from> result = get_variable(src); + + if (src.abs) + { + result.assign(abs(result)); + } + + if (src.neg) + { + result.assign(-result); + } + + return result.swizzle(src.swizzle_x, src.swizzle_y, src.swizzle_z, src.swizzle_w); + } + + + expression_from> output(context_t& context) const + { + } + + expression_from> dst(context_t& context) const + { + } + }; + + static_assert(sizeof(instruction_t) == 16, "Bad instruction_t implementation"); + + public: + instruction_t* instruction; + context_t context; + writer_t writer; + + expression_from> src(int index) + { + return instruction->src(context, index); + } + + expression_from> modify_condition() + { + return{ "" }; + } + + expression_from> execution_condition() + { + return{ "" }; + } + + expression_from tex() + { + return{ "" }; + } + + template + expression_from conditional(const ExprType& expr) + { + bool need_condition = false; + + if (need_condition) + { + return if_(any(execution_condition()), expr); + } + + return expr; + } + + //template + writer_t set_dst(const expression_t& arg) + { + writer_t result; + + auto modify_cond = modify_condition(); + auto dest = instruction->dst(context); + + if (!instruction->data.src0.exec_if_eq || !instruction->data.src0.exec_if_gr || !instruction->data.src0.exec_if_lt) + { + std::string cond_mask; + cond_mask += index_to_channel[instruction->data.src0.cond_swizzle_x]; + cond_mask += index_to_channel[instruction->data.src0.cond_swizzle_y]; + cond_mask += index_to_channel[instruction->data.src0.cond_swizzle_z]; + cond_mask += index_to_channel[instruction->data.src0.cond_swizzle_w]; + + auto cond = execution_condition(); + + std::string operation; + + if (instruction->data.src0.exec_if_gr && instruction->data.src0.exec_if_lt) + { + operation = "!="; + } + else if (!instruction->data.src0.exec_if_gr && !instruction->data.src0.exec_if_lt) + { + operation = "=="; + } + else + { + if (instruction->data.src0.exec_if_gr) + operation += ">"; + else if (instruction->data.src0.exec_if_lt) + operation += "<"; + + if (instruction->data.src0.exec_if_eq) + operation += "="; + } + + auto set_channel = [&](int index) + { + if (instruction->data.dst.set_cond) + { + if (instruction->data.dst.no_dest) + { + result += if_(cond.swizzle(index).call_operator>(operation, 0.0f), modify_cond.swizzle(index) = boolean_t<1>::ctor(arg.swizzle(index))); + } + else + { + result += if_(cond.swizzle(index).call_operator(operation, 0.0f), modify_cond.swizzle(index) = boolean_t<1>::ctor(dest.swizzle(index) = arg.swizzle(index))); + } + } + else + { + if (instruction->data.dst.no_dest) + { + result += if_(cond.swizzle(index).call_operator(operation, 0.0f), arg.swizzle(index)); + } + else + { + result += if_(cond.swizzle(index).call_operator(operation, 0.0f), dest.swizzle(index) = arg.swizzle(index)); + } + } + }; + + if (instruction->data.dst.mask_x) set_channel(0); + if (instruction->data.dst.mask_y) set_channel(1); + if (instruction->data.dst.mask_z) set_channel(2); + if (instruction->data.dst.mask_w) set_channel(3); + } + + return result; + } + + writer_t comment(const std::string& lines) + { + writer_t result; + + result += "//" + lines; + + return result; + } + + writer_t unimplemented(const std::string& lines) + { + return comment(lines); + } + + expression_base_t decode_instruction() + { + switch (instruction->data.dst.opcode) + { + case opcode::NOP: return comment("nop"); + case opcode::MOV: return set_dst(src(0)); + case opcode::MUL: return set_dst(src(0) * src(1)); + case opcode::ADD: return set_dst(src(0) + src(1)); + case opcode::MAD: return set_dst(src(0) * src(1) + src(2)); + case opcode::DP3: return set_dst(float_point_t<4>::ctor(dot(src(0).xyz(), src(1).xyz()))); + case opcode::DP4: return set_dst(float_point_t<4>::ctor(dot(src(0), src(1)))); + case opcode::DST: + { + auto src_0 = src(0); + auto src_1 = src(1); + + return set_dst(float_point_t<4>::ctor(1.0f, src_0.y() * src_1.y(), src_0.z(), src_1.w())); + } + case opcode::MIN: return set_dst(min(src(0), src(1))); + case opcode::MAX: return set_dst(max(src(0), src(1))); + case opcode::SLT: return set_dst(float_point_t<4>::ctor(less(src(0), src(1)))); + case opcode::SGE: return set_dst(float_point_t<4>::ctor(greater_equal(src(0), src(1)))); + case opcode::SLE: return set_dst(float_point_t<4>::ctor(less_equal(src(0), src(1)))); + case opcode::SGT: return set_dst(float_point_t<4>::ctor(greater(src(0), src(1)))); + case opcode::SNE: return set_dst(float_point_t<4>::ctor(not_equal(src(0), src(1)))); + case opcode::SEQ: return set_dst(float_point_t<4>::ctor(equal(src(0), src(1)))); + case opcode::FRC: return set_dst(fract(src(0))); + case opcode::FLR: return set_dst(floor(src(0))); + case opcode::KIL: return conditional(expression_from("discard")); + case opcode::PK4: return unimplemented("PK4"); + case opcode::UP4: return unimplemented("UP4"); + case opcode::DDX: return set_dst(ddx(src(0))); + case opcode::DDY: return set_dst(ddy(src(0))); + case opcode::TEX: return set_dst(texture(tex(), src(0).xy())); + case opcode::TXP: return set_dst(texture(tex(), src(0).xy() / src(0).w())); + case opcode::TXD: return set_dst(texture_grad(tex(), src(0).xy(), src(1).xy(), src(2).xy())); + case opcode::RCP: return set_dst(float_point_t<1>::ctor(1.0f) / src(0)); + case opcode::RSQ: return set_dst(rsqrt(src(0))); + case opcode::EX2: return set_dst(exp2(src(0))); + case opcode::LG2: return set_dst(log2(src(0))); + case opcode::LIT: return unimplemented("LIT"); + case opcode::LRP: return unimplemented("LRP"); + case opcode::STR: return set_dst(float_point_t<4>::ctor(1.0f)); + case opcode::SFL: return set_dst(float_point_t<4>::ctor(0.0f)); + case opcode::COS: return set_dst(cos(src(0))); + case opcode::SIN: return set_dst(sin(src(0))); + case opcode::PK2: return unimplemented("PK2"); + case opcode::UP2: return unimplemented("UP2"); + case opcode::POW: return set_dst(pow(src(0), src(1))); + case opcode::PKB: return unimplemented("PKB"); + case opcode::UPB: return unimplemented("UPB"); + case opcode::PK16: return unimplemented("PK16"); + case opcode::UP16: return unimplemented("UP16"); + case opcode::BEM: return unimplemented("BEM"); + case opcode::PKG: return unimplemented("PKG"); + case opcode::UPG: return unimplemented("UPG"); + case opcode::DP2A: + { + auto src_0 = src(0); + auto src_1 = src(1); + + return set_dst(float_point_t<4>::ctor(src_0.x() * src_1.x() + src_0.y() * src_1.y() + src(2).z())); + } + case opcode::TXL: return set_dst(texture_lod(tex(), src(0).xy(), src(1).x())); + case opcode::TXB: return set_dst(texture_bias(tex(), src(0).xy(), src(1).x())); + case opcode::TEXBEM: return unimplemented("TEXBEM"); + case opcode::TXPBEM: return unimplemented("TXPBEM"); + case opcode::BEMLUM: return unimplemented("BEMLUM"); + case opcode::REFL: return unimplemented("REFL"); + case opcode::TIMESWTEX: return unimplemented("TIMESWTEX"); + case opcode::DP2: return set_dst(float_point_t<4>::ctor(dot(src(0).xy(), src(1).xy()))); + case opcode::NRM: return set_dst(normalize(src(0).xyz()).xyzx()); + case opcode::DIV: return set_dst(src(0) / src(1)); + case opcode::DIVSQ: return set_dst(src(0) / sqrt(src(1))); + case opcode::LIF: return unimplemented("LIF"); + case opcode::FENCT: return comment("fenct"); + case opcode::FENCB: return comment("fencb"); + case opcode::BRK: return conditional(expression_from("break")); + case opcode::CAL: return unimplemented("CAL"); + case opcode::IFE: return unimplemented("IFE"); + case opcode::LOOP: return unimplemented("LOOP"); + case opcode::REP: return unimplemented("REP"); + case opcode::RET: return conditional(expression_from("return")); + } + } + + void decompile(std::size_t offset, instruction_t* instructions) + { + for (std::size_t index = offset; index < 512; ++index, writer.next()) + { + instruction = instructions + index; + + writer += decode_instruction(); + + if (instruction->data.dst.end) + break; + } + } + + void test() + { + expression_from> C{ "C", "wwww" }; + expression_from> A{ "A" }; + expression_from> B{ "B" }; + + expression_from tex = { "tex0" }; + + std::cout << move_if(C.xyz(), "!=", -A.xyz(), texture(tex, A.xy() / B.zw() + C.xw()).xyz()).build(); + } + }; + } +} + +/* +struct vp_shader : shader_code::clike_builder +{ + writer_t writer; + + struct variable_info + { + std::string type; + std::string name; + + bool operator ==(const variable_info& rhs) const + { + return type == rhs.type && name == rhs.name; + } + + struct hash + { + std::size_t operator()(const variable_info& arg) const + { + return + std::hash()(arg.type) ^ + (std::hash()(arg.name) - 1); + } + }; + }; + + std::unordered_set uniforms; + + template + expression_from make_uniform(const std::string& name, expression_from initializer) + { + return{ name }; + } + + template + expression_from make_uniform(const std::string& name) + { + return{ name }; + } + + struct else_t : expression_base_t + { + + }; + + struct if_t : expression_from + { + if_t(expression_from> condition, std::function body = nullptr) + : expression_t("if (" + condition.to_string() + ")") + { + } + + std::string finalize() const override + { + return to_string(); + } + }; + + vp_shader() + { + auto A = make_uniform>("A", boolean_t<4>::ctor(true)); + auto B = make_uniform>("B", float_point_t<4>::ctor(0.f)); + auto C = make_uniform>("C"); + auto K = make_uniform>("K"); + auto D = make_uniform("D"); + + writer.lines( + texture(D).xyzw(), + float_point_t<4>::ctor(1), + float_point_t<1>::ctor(1.f) / float_point_t<1>::ctor(), + if_t(A.x()), + A.x() = !(K.xy().y() != C.x()), + K.xy(), + A.y() = B.x() != C.x() + ); + } +}; + +#include + +struct rsx_fragment_shader +{ + std::vector data; + + struct hash_t + { + std::size_t operator ()(const rsx_fragment_shader& arg) const + { + return 0; + //return arg.hash; + } + }; + + bool operator ==(const rsx_fragment_shader& rhs) const + { + if (data.size() != rhs.data.size()) + return false; + + for (std::size_t i = 0; i < data.size(); ++i) + { + if (data[i] != rhs.data[i]) + return false; + } + + return true; + } +}; + +struct decompiled_rsx_fragment_shader +{ + std::vector constant_offsets; + std::vector uniforms; + int input_attributes; + int output_attributes; + + std::string code; +}; + +struct glsl_shader_t +{ + int id; +}; + +template +struct finalized_rsx_fragment_shader +{ + int input_attributes; + int output_attributes; + int control; + + std::string code; + CompiledType shader; +}; + +template +struct rsx_program +{ + std::shared_ptr> fragment_shader; + std::shared_ptr> vertex_shader; +}; + +/* + +namespace fmt +{ + bool mask_test(const std::string &source, const std::string &mask, std::size_t source_offset = 0, std::size_t mask_offset = 0) + { + while (char sym = mask[mask_offset]) + { + if (source[source_offset] == '\0') + return false; + + switch (sym) + { + case '*': + while (source[source_offset]) + { + if (mask_test(source, mask, source_offset, mask_offset + 1)) + return true; + + ++source_offset; + } + + return false; + + case '\\': + sym = mask[++mask_offset]; + + default: + if (sym != source[source_offset]) + return false; + + case '?': + ++source_offset; ++mask_offset; + break; + } + } + + return source[source_offset] == '\0'; + } +} + +#include +#include +#include + +namespace fs = std::tr2::sys; + +void _load_fragment_cache_file(const fs::path& data_path, const fs::path &source_path) +{ + rsx_fragment_shader shader; + { + std::ifstream data_f(data_path, std::ios::ate | std::ios::binary); + if (!data_f) + return; + + shader.data.resize(data_f.tellg() / sizeof(rsx_fragment_shader::data[0])); + data_f.seekg(0, data_f.beg); + + data_f.read((char*)shader.data.data(), shader.data.size() * sizeof(rsx_fragment_shader::data[0])); + } + + cache_t cache; + + decompiled_rsx_fragment_shader &decompiled_shader = cache.entry(shader); + + { + std::ifstream data_f(data_path, std::ios::ate); + if (!data_f) + return; + + data_f + >> decompiled_shader.input_attributes + >> decompiled_shader.output_attributes; + + + int constants_count; + data_f >> constants_count; + + if (constants_count) + { + decompiled_shader.constant_offsets.resize(constants_count); + + for (auto &offset : decompiled_shader.constant_offsets) + { + data_f >> offset; + } + } + + int uniforms_count; + data_f >> uniforms_count; + + if (uniforms_count) + { + decompiled_shader.uniforms.resize(uniforms_count); + + for (auto &uniform : decompiled_shader.uniforms) + { + data_f >> uniform; + } + } + + auto from_pos = data_f.tellg(); + data_f.seekg(0, data_f.end); + auto end_pos = data_f.tellg(); + + decompiled_shader.code.resize(end_pos - from_pos); + data_f.seekg(from_pos); + data_f.read((char*)decompiled_shader.code.data(), decompiled_shader.code.size()); + } +} + +void _save_fragment_cache_file(const fs::path& data_path, const fs::path &source_path, std::pair data) +{ + rsx_fragment_shader shader; + { + std::ifstream data_f(data_path, std::ios::ate | std::ios::binary); + if (!data_f) + return; + + shader.data.resize(data_f.tellg() / sizeof(rsx_fragment_shader::data[0])); + data_f.seekg(0, data_f.beg); + + data_f.read((char*)shader.data.data(), shader.data.size() * sizeof(rsx_fragment_shader::data[0])); + } + + cache_t cache; + + decompiled_rsx_fragment_shader &decompiled_shader = cache.entry(shader); + + { + std::ifstream data_f(data_path, std::ios::ate); + if (!data_f) + return; + + data_f + >> decompiled_shader.input_attributes + >> decompiled_shader.output_attributes; + + + int constants_count; + data_f >> constants_count; + + if (constants_count) + { + decompiled_shader.constant_offsets.resize(constants_count); + + for (auto &offset : decompiled_shader.constant_offsets) + { + data_f >> offset; + } + } + + int uniforms_count; + data_f >> uniforms_count; + + if (uniforms_count) + { + decompiled_shader.uniforms.resize(uniforms_count); + + for (auto &uniform : decompiled_shader.uniforms) + { + data_f >> uniform; + } + } + + auto from_pos = data_f.tellg(); + data_f.seekg(0, data_f.end); + auto end_pos = data_f.tellg(); + + decompiled_shader.code.resize(end_pos - from_pos); + data_f.seekg(from_pos); + data_f.read((char*)decompiled_shader.code.data(), decompiled_shader.code.size()); + } +} + + +void _load_shader_cache(const std::string &cache_path) +{ + if (!fs::exists(cache_path)) + { + if (!fs::create_directories(cache_path)) + return; + } + + for (auto entry : fs::directory_iterator{ fs::path(cache_path).parent_path() }) + { + if (entry.status().type() != fs::file_type::regular) + { + continue; + } + + if (fmt::mask_test(entry.path().filename().string(), "*.vp.data")) + { + fs::path(entry.path()).replace_extension("glsl"); + } + + if (fmt::mask_test(entry.path().filename().string(), "*.fp.data")) + { + _load_fragment_cache_file(entry.path(), fs::path(entry.path()).replace_extension("glsl").string()); + } + } +} + +void load_shader_cache(const std::string &game_id) +{ + _load_shader_cache("./data/cache/rsx/"); + + if (!game_id.empty()) + _load_shader_cache("./data/" + game_id + "/cache/rsx/"); + + cache_t cache; + cache.each([](std::pair elem) + { + elem.first.data; + }); +} +*/ +#include + +namespace vs +{ + int main() + { + //load_shader_cache("SUPER12321"); + //vp_shader a{}; + + //for (auto& line : a.writer.code) + // std::cout << line.second << std::endl; + + rsx::fragment_program::decompiler{}.test(); + std::cin.get(); + return 0; + } +} \ No newline at end of file diff --git a/rsx_decompiler/rsx_decompiler.h b/rsx_decompiler/rsx_decompiler.h new file mode 100644 index 0000000..5ca8404 --- /dev/null +++ b/rsx_decompiler/rsx_decompiler.h @@ -0,0 +1,117 @@ +#pragma once +#include + +struct rsx_vertex_shader +{ + std::vector data; + + struct hash_t + { + std::size_t operator ()(const rsx_vertex_shader& arg) const + { + return 0; + //return arg.hash; + } + }; + + bool operator ==(const rsx_vertex_shader& rhs) const + { + if (data.size() != rhs.data.size()) + return false; + + for (std::size_t i = 0; i < data.size(); ++i) + { + if (data[i] != rhs.data[i]) + return false; + } + + return true; + } +}; + +struct rsx_fragment_shader +{ + std::vector data; + + struct hash_t + { + std::size_t operator ()(const rsx_fragment_shader& arg) const + { + return 0; + //return arg.hash; + } + }; + + bool operator ==(const rsx_fragment_shader& rhs) const + { + if (data.size() != rhs.data.size()) + return false; + + for (std::size_t i = 0; i < data.size(); ++i) + { + if (data[i] != rhs.data[i]) + return false; + } + + return true; + } +}; + +struct decompiled_rsx_shader +{ + std::vector constant_offsets; + std::vector uniforms; + int input_attributes; + int output_attributes; + + std::string code; +}; + +struct finalized_rsx_vertex_shader +{ + int input_attributes; + + std::string code; + + struct hash_t + { + std::size_t operator ()(const finalized_rsx_vertex_shader& arg) const + { + return 0; + //return arg.hash; + } + }; + + bool operator ==(const finalized_rsx_vertex_shader& rhs) const + { + return + input_attributes == rhs.input_attributes && + code == rhs.code; + } +}; + + +struct finalized_rsx_fragment_shader +{ + int output_attributes; + int control; + + std::string code; + + struct hash_t + { + std::size_t operator ()(const finalized_rsx_fragment_shader& arg) const + { + return 0; + //return arg.hash; + } + }; + + bool operator ==(const finalized_rsx_fragment_shader& rhs) const + { + return + output_attributes == rhs.output_attributes && + control == rhs.control && + code == rhs.code; + } +}; \ No newline at end of file diff --git a/rsx_decompiler/rsx_decompiler.vcxproj b/rsx_decompiler/rsx_decompiler.vcxproj new file mode 100644 index 0000000..3c623f6 --- /dev/null +++ b/rsx_decompiler/rsx_decompiler.vcxproj @@ -0,0 +1,257 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {7d73447b-3d2d-4dfe-bf62-57e644c1d09f} + StaticLibrary + rsx_decompiler + rsx_decompiler + en-US + 14.0 + true + Windows Store + 10.0.10240.0 + 10.0.10240.0 + 10.0 + + + + StaticLibrary + true + v140 + + + StaticLibrary + true + v140 + + + StaticLibrary + true + v140 + + + StaticLibrary + false + true + v140 + + + StaticLibrary + false + true + v140 + + + StaticLibrary + false + true + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + $(SolutionDir)shader_code\;$(IncludePath) + $(SolutionDir)lib\$(Platform)-$(Configuration);$(LibraryPath) + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + + + false + $(SolutionDir)shader_code\;$(IncludePath) + $(SolutionDir)lib\$(Platform)-$(Configuration);$(LibraryPath) + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + + + false + $(SolutionDir)shader_code\;$(IncludePath) + $(SolutionDir)lib\$(Platform)-$(Configuration);$(LibraryPath) + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + + + false + $(SolutionDir)shader_code\;$(IncludePath) + $(SolutionDir)lib\$(Platform)-$(Configuration);$(LibraryPath) + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + + + false + $(SolutionDir)shader_code\;$(IncludePath) + $(SolutionDir)lib\$(Platform)-$(Configuration);$(LibraryPath) + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + + + false + $(SolutionDir)shader_code\;$(IncludePath) + $(SolutionDir)lib\$(Platform)-$(Configuration);$(LibraryPath) + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + + + + Use + false + true + + + Console + false + false + + + shader_code.lib + + + + + Use + false + true + + + Console + false + false + + + shader_code.lib + + + + + Use + false + true + + + Console + false + false + + + shader_code.lib + + + + + Use + false + true + + + Console + false + false + + + shader_code.lib + + + + + Use + false + true + + + Console + false + false + + + shader_code.lib + + + + + Use + false + true + + + Console + false + false + + + shader_code.lib + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + CppCode + + + + + + \ No newline at end of file diff --git a/rsx_decompiler/rsx_decompiler.vcxproj.filters b/rsx_decompiler/rsx_decompiler.vcxproj.filters new file mode 100644 index 0000000..d0688d4 --- /dev/null +++ b/rsx_decompiler/rsx_decompiler.vcxproj.filters @@ -0,0 +1,21 @@ + + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rsx_decompiler/rsx_fp_ucode.cpp b/rsx_decompiler/rsx_fp_ucode.cpp new file mode 100644 index 0000000..016d42a --- /dev/null +++ b/rsx_decompiler/rsx_fp_ucode.cpp @@ -0,0 +1,49 @@ +#include "pch.h" +#include "rsx_fp_ucode.h" + +namespace rsx +{ + namespace fragment_program + { + const std::string input_attrib_map[16] = + { + "in_wpos", //0 + "in_col0", //1 + "in_col1", //2 + "in_fogc", //3 + "in_tex0", //4 + "in_tex1", //5 + "in_tex2", //6 + "in_tex3", //7 + "in_tex4", //8 + "in_tex5", //9 + "in_tex6", //10 + "in_tex7", //11 + "in_tex8", //12 + "in_tex9", //13 + "in_ssa", //14 + "in_unk" //15 + }; + + const std::string input_attr_regs[16] = + { + "WPOS", "COL0", "COL1", "FOGC", "TEX0", + "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", + "TEX6", "TEX7", "TEX8", "TEX9", "SSA" + }; + + const std::string instructions_names[128] = + { + "NOP", "MOV", "MUL", "ADD", "MAD", "DP3", "DP4", + "DST", "MIN", "MAX", "SLT", "SGE", "SLE", "SGT", + "SNE", "SEQ", "FRC", "FLR", "KIL", "PK4", "UP4", + "DDX", "DDY", "TEX", "TXP", "TXD", "RCP", "RSQ", + "EX2", "LG2", "LIT", "LRP", "STR", "SFL", "COS", + "SIN", "PK2", "UP2", "POW", "PKB", "UPB", "PK16", + "UP16", "BEM", "PKG", "UPG", "DP2A", "TXL", "NULL", + "TXB", "NULL", "TEXBEM", "TXPBEM", "BEMLUM", "REFL", "TIMESWTEX", + "DP2", "NRM", "DIV", "DIVSQ", "LIF", "FENCT", "FENCB", + "NULL", "BRK", "CAL", "IFE", "LOOP", "REP", "RET" + }; + } +} \ No newline at end of file diff --git a/rsx_decompiler/rsx_fp_ucode.h b/rsx_decompiler/rsx_fp_ucode.h new file mode 100644 index 0000000..578c754 --- /dev/null +++ b/rsx_decompiler/rsx_fp_ucode.h @@ -0,0 +1,212 @@ +#pragma once +#include + +namespace rsx +{ + using u32 = unsigned int; + + namespace fragment_program + { + enum class opcode : u32 + { + NOP = 0x00, // No-Operation + MOV = 0x01, // Move + MUL = 0x02, // Multiply + ADD = 0x03, // Add + MAD = 0x04, // Multiply-Add + DP3 = 0x05, // 3-component Dot Product + DP4 = 0x06, // 4-component Dot Product + DST = 0x07, // Distance + MIN = 0x08, // Minimum + MAX = 0x09, // Maximum + SLT = 0x0A, // Set-If-LessThan + SGE = 0x0B, // Set-If-GreaterEqual + SLE = 0x0C, // Set-If-LessEqual + SGT = 0x0D, // Set-If-GreaterThan + SNE = 0x0E, // Set-If-NotEqual + SEQ = 0x0F, // Set-If-Equal + FRC = 0x10, // Fraction (fract) + FLR = 0x11, // Floor + KIL = 0x12, // Kill fragment + PK4 = 0x13, // Pack four signed 8-bit values + UP4 = 0x14, // Unpack four signed 8-bit values + DDX = 0x15, // Partial-derivative in x (Screen space derivative w.r.t. x) + DDY = 0x16, // Partial-derivative in y (Screen space derivative w.r.t. y) + TEX = 0x17, // Texture lookup + TXP = 0x18, // Texture sample with projection (Projective texture lookup) + TXD = 0x19, // Texture sample with partial differentiation (Texture lookup with derivatives) + RCP = 0x1A, // Reciprocal + RSQ = 0x1B, // Reciprocal Square Root + EX2 = 0x1C, // Exponentiation base 2 + LG2 = 0x1D, // Log base 2 + LIT = 0x1E, // Lighting coefficients + LRP = 0x1F, // Linear Interpolation + STR = 0x20, // Set-If-True + SFL = 0x21, // Set-If-False + COS = 0x22, // Cosine + SIN = 0x23, // Sine + PK2 = 0x24, // Pack two 16-bit floats + UP2 = 0x25, // Unpack two 16-bit floats + POW = 0x26, // Power + PKB = 0x27, // Pack bytes + UPB = 0x28, // Unpack bytes + PK16 = 0x29, // Pack 16 bits + UP16 = 0x2A, // Unpack 16 + BEM = 0x2B, // Bump-environment map (a.k.a. 2D coordinate transform) + PKG = 0x2C, // Pack with sRGB transformation + UPG = 0x2D, // Unpack gamma + DP2A = 0x2E, // 2-component dot product with scalar addition + TXL = 0x2F, // Texture sample with explicit LOD + TXB = 0x31, // Texture sample with bias + TEXBEM = 0x33, + TXPBEM = 0x34, + BEMLUM = 0x35, + REFL = 0x36, // Reflection vector + TIMESWTEX = 0x37, + DP2 = 0x38, // 2-component dot product + NRM = 0x39, // Normalize + DIV = 0x3A, // Division + DIVSQ = 0x3B, // Divide by Square Root + LIF = 0x3C, // Final part of LIT + FENCT = 0x3D, // Fence T? + FENCB = 0x3E, // Fence B? + BRK = 0x40, // Break + CAL = 0x41, // Subroutine call + IFE = 0x42, // If + LOOP = 0x43, // Loop + REP = 0x44, // Repeat + RET = 0x45 // Return + }; + + enum class src_reg_type_t : u32 + { + temporary, + input, + constant + }; + + union alignas(4) OPDEST + { + u32 _u32; + + struct + { + u32 end : 1; // Set to 1 if this is the last instruction + u32 dest_reg : 6; // Destination register index + u32 fp16 : 1; // Destination is a half register (H0 to H47) + u32 set_cond : 1; // Condition Code Registers (CC0 and CC1) are updated + u32 mask_x : 1; + u32 mask_y : 1; + u32 mask_z : 1; + u32 mask_w : 1; + u32 src_attr_reg_num : 4; + u32 tex_num : 4; + u32 exp_tex : 1; // _bx2 + u32 prec : 2; + opcode opcode : 6; + u32 no_dest : 1; + u32 saturate : 1; // _sat + }; + }; + + union alignas(4) SRC0 + { + u32 _u32; + + struct + { + src_reg_type_t reg_type : 2; + u32 tmp_reg_index : 6; + u32 fp16 : 1; + u32 swizzle_x : 2; + u32 swizzle_y : 2; + u32 swizzle_z : 2; + u32 swizzle_w : 2; + u32 neg : 1; + u32 exec_if_lt : 1; + u32 exec_if_eq : 1; + u32 exec_if_gr : 1; + u32 cond_swizzle_x : 2; + u32 cond_swizzle_y : 2; + u32 cond_swizzle_z : 2; + u32 cond_swizzle_w : 2; + u32 abs : 1; + u32 cond_mod_reg_index : 1; + u32 cond_reg_index : 1; + }; + }; + + union alignas(4) SRC1 + { + u32 _u32; + + struct + { + src_reg_type_t reg_type : 2; + u32 tmp_reg_index : 6; + u32 fp16 : 1; + u32 swizzle_x : 2; + u32 swizzle_y : 2; + u32 swizzle_z : 2; + u32 swizzle_w : 2; + u32 neg : 1; + u32 abs : 1; + u32 input_mod_src0 : 3; + u32: 6; + u32 scale : 3; + u32 opcode_is_branch : 1; + }; + + struct + { + u32 else_offset : 31; + u32: 1; + }; + + // LOOP, REP + struct + { + u32: 2; + u32 end_counter : 8; // End counter value for LOOP or rep count for REP + u32 init_counter : 8; // Initial counter value for LOOP + u32: 1; + u32 increment : 8; // Increment value for LOOP + }; + }; + + union alignas(4) SRC2 + { + u32 _u32; + + u32 end_offset; + + struct + { + src_reg_type_t reg_type : 2; + u32 tmp_reg_index : 6; + u32 fp16 : 1; + u32 swizzle_x : 2; + u32 swizzle_y : 2; + u32 swizzle_z : 2; + u32 swizzle_w : 2; + u32 neg : 1; + u32 abs : 1; + u32 addr_reg : 11; + u32 use_index_reg : 1; + u32 perspective_corr : 1; + }; + }; + + struct alignas(16) ucode_instr + { + OPDEST dst; + SRC0 src0; + SRC1 src1; + SRC2 src2; + }; + + extern const std::string input_attr_regs[16]; + extern const std::string instructions_names[128]; + extern const std::string input_attrib_map[16]; + } +} diff --git a/rsx_program_decompiler.sln b/rsx_program_decompiler.sln index b20d4a0..14af4d4 100644 --- a/rsx_program_decompiler.sln +++ b/rsx_program_decompiler.sln @@ -8,40 +8,39 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rsx_program_decompiler", "rsx_program_decompiler\rsx_program_decompiler.vcxproj", "{9DAF4DF3-0E31-4C55-B367-6992C35F89CE}" ProjectSection(ProjectDependencies) = postProject {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE} = {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE} + {97E17077-A21F-45EF-9C3A-73A0BC092D7E} = {97E17077-A21F-45EF-9C3A-73A0BC092D7E} + {7D73447B-3D2D-4DFE-BF62-57E644C1D09F} = {7D73447B-3D2D-4DFE-BF62-57E644C1D09F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shader_code", "shader_code\shader_code.vcxproj", "{97E17077-A21F-45EF-9C3A-73A0BC092D7E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rsx_decompiler", "rsx_decompiler\rsx_decompiler.vcxproj", "{7D73447B-3D2D-4DFE-BF62-57E644C1D09F}" + ProjectSection(ProjectDependencies) = postProject + {97E17077-A21F-45EF-9C3A-73A0BC092D7E} = {97E17077-A21F-45EF-9C3A-73A0BC092D7E} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|ARM = Debug|ARM Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|ARM = Release|ARM Release|x64 = Release|x64 - Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Debug|ARM.ActiveCfg = Debug|ARM - {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Debug|ARM.Build.0 = Debug|ARM {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Debug|x64.ActiveCfg = Debug|x64 {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Debug|x64.Build.0 = Debug|x64 - {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Debug|x86.ActiveCfg = Debug|Win32 - {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Debug|x86.Build.0 = Debug|Win32 - {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|ARM.ActiveCfg = Release|ARM - {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|ARM.Build.0 = Release|ARM {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|x64.ActiveCfg = Release|x64 {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|x64.Build.0 = Release|x64 - {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|x86.ActiveCfg = Release|Win32 - {F7AAD20D-BCFA-4B17-A178-BD8606B4E1FE}.Release|x86.Build.0 = Release|Win32 - {9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Debug|ARM.ActiveCfg = Debug|Win32 {9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Debug|x64.ActiveCfg = Debug|x64 {9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Debug|x64.Build.0 = Debug|x64 - {9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Debug|x86.ActiveCfg = Debug|Win32 - {9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Debug|x86.Build.0 = Debug|Win32 - {9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Release|ARM.ActiveCfg = Release|Win32 {9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Release|x64.ActiveCfg = Release|x64 {9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Release|x64.Build.0 = Release|x64 - {9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Release|x86.ActiveCfg = Release|Win32 - {9DAF4DF3-0E31-4C55-B367-6992C35F89CE}.Release|x86.Build.0 = Release|Win32 + {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug|x64.ActiveCfg = Debug|x64 + {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug|x64.Build.0 = Debug|x64 + {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release|x64.ActiveCfg = Release|x64 + {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release|x64.Build.0 = Release|x64 + {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug|x64.ActiveCfg = Debug|x64 + {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug|x64.Build.0 = Debug|x64 + {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release|x64.ActiveCfg = Release|x64 + {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/rsx_program_decompiler/rsx_program_decompiler.cpp b/rsx_program_decompiler/rsx_program_decompiler.cpp index 711f73c..4b2e55b 100644 --- a/rsx_program_decompiler/rsx_program_decompiler.cpp +++ b/rsx_program_decompiler/rsx_program_decompiler.cpp @@ -1,3 +1,4 @@ +/* #include #include #include @@ -7,6 +8,7 @@ #include "elf64.h" #include + template int process_ucode(const std::string& ipath, const std::string& opath) { @@ -163,10 +165,17 @@ void help() std::cout << profile.first << " "; } std::cout << std::endl; +}*/ + +namespace vs +{ + int main(); } int main(int argc, char** argv) { + return vs::main(); + /* if (argc != 4) { help(); @@ -190,5 +199,5 @@ int main(int argc, char** argv) std::cerr << ex.what() << std::endl; return -5; } + */ } - diff --git a/rsx_program_decompiler/rsx_program_decompiler.vcxproj b/rsx_program_decompiler/rsx_program_decompiler.vcxproj index edbc17c..1913836 100644 --- a/rsx_program_decompiler/rsx_program_decompiler.vcxproj +++ b/rsx_program_decompiler/rsx_program_decompiler.vcxproj @@ -74,20 +74,20 @@ true - $(SolutionDir)lib\;$(LibraryPath) + $(SolutionDir)lib\$(Platform)-$(Configuration)\;$(LibraryPath) $(SolutionDir)rsx_program_decompiler_lib\;$(IncludePath) $(SolutionDir)bin\ $(ProjectName)-$(Platform)-$(Configuration) - tmp\$(Platform)\$(Configuration)\ + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ AllRules.ruleset false true - $(SolutionDir)lib\;$(LibraryPath) + $(SolutionDir)lib\$(Platform)-$(Configuration)\;$(LibraryPath) $(SolutionDir)bin\ $(ProjectName)-$(Platform)-$(Configuration) - tmp\$(Platform)\$(Configuration)\ + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ $(SolutionDir)rsx_program_decompiler_lib\;$(IncludePath) AllRules.ruleset false @@ -95,9 +95,9 @@ false $(ProjectName)-$(Platform)-$(Configuration) - tmp\$(Platform)\$(Configuration)\ + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ $(SolutionDir)bin\ - $(SolutionDir)lib\;$(LibraryPath) + $(SolutionDir)lib\$(Platform)-$(Configuration)\;$(LibraryPath) $(SolutionDir)rsx_program_decompiler_lib\;$(IncludePath) AllRules.ruleset false @@ -106,8 +106,8 @@ false $(ProjectName)-$(Platform)-$(Configuration) $(SolutionDir)bin\ - tmp\$(Platform)\$(Configuration)\ - $(SolutionDir)lib\;$(LibraryPath) + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + $(SolutionDir)lib\$(Platform)-$(Configuration)\;$(LibraryPath) $(SolutionDir)rsx_program_decompiler_lib\;$(IncludePath) AllRules.ruleset false @@ -123,7 +123,7 @@ Console true - rsx_program_decompiler-$(Platform)-$(Configuration).lib;%(AdditionalDependencies) + rsx_decompiler.lib;%(AdditionalDependencies) @@ -137,7 +137,7 @@ Console true - rsx_program_decompiler-$(Platform)-$(Configuration).lib;%(AdditionalDependencies) + rsx_decompiler.lib;%(AdditionalDependencies) @@ -155,7 +155,7 @@ true true true - rsx_program_decompiler-$(Platform)-$(Configuration).lib;%(AdditionalDependencies) + rsx_decompiler.lib;%(AdditionalDependencies) @@ -173,7 +173,7 @@ true true true - rsx_program_decompiler-$(Platform)-$(Configuration).lib;%(AdditionalDependencies) + rsx_decompiler.lib;%(AdditionalDependencies) diff --git a/rsx_program_decompiler_lib/rsx_program_decompiler_lib.vcxproj b/rsx_program_decompiler_lib/rsx_program_decompiler_lib.vcxproj index a40f461..db0c3bd 100644 --- a/rsx_program_decompiler_lib/rsx_program_decompiler_lib.vcxproj +++ b/rsx_program_decompiler_lib/rsx_program_decompiler_lib.vcxproj @@ -102,39 +102,39 @@ false AllRules.ruleset false - $(SolutionDir)lib\ - tmp\$(Platform)\$(Configuration)\ - rsx_program_decompiler-$(Platform)-$(Configuration) + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + rsx_program_decompiler false - $(SolutionDir)lib\ - tmp\$(Platform)\$(Configuration)\ - rsx_program_decompiler-$(Platform)-$(Configuration) + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + rsx_program_decompiler false - $(SolutionDir)lib\ - rsx_program_decompiler-$(Platform)-$(Configuration) - tmp\$(Platform)\$(Configuration)\ + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + rsx_program_decompiler + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ false - $(SolutionDir)lib\ - rsx_program_decompiler-$(Platform)-$(Configuration) - tmp\$(Platform)\$(Configuration)\ + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + rsx_program_decompiler + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ false - $(SolutionDir)lib\ - rsx_program_decompiler-$(Platform)-$(Configuration) - tmp\$(Platform)\$(Configuration)\ + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + rsx_program_decompiler + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ false - $(SolutionDir)lib\ - rsx_program_decompiler-$(Platform)-$(Configuration) - tmp\$(Platform)\$(Configuration)\ + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + rsx_program_decompiler + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ diff --git a/shader_code/builder.cpp b/shader_code/builder.cpp new file mode 100644 index 0000000..3cb84a6 --- /dev/null +++ b/shader_code/builder.cpp @@ -0,0 +1,30 @@ +#include "pch.h" +#include "builder.h" + +namespace shader_code +{ + builder::expression_base_t::expression_base_t(const std::string& text) + : text(text) + { + } + + std::string builder::expression_base_t::to_string() const + { + return text; + } + + std::string builder::expression_base_t::finalize(bool put_end) const + { + return to_string(); + } + + builder::writer_t::writer_to builder::writer_t::operator()(std::size_t position) + { + return{ &code[position] }; + } + + void builder::writer_t::next() + { + ++position; + } +} \ No newline at end of file diff --git a/shader_code/builder.h b/shader_code/builder.h new file mode 100644 index 0000000..f1a8227 --- /dev/null +++ b/shader_code/builder.h @@ -0,0 +1,78 @@ +#pragma once +#include +#include + +namespace shader_code +{ + struct builder + { + template + struct type_t + { + static constexpr TypeType type = Type; + static constexpr int count = Count; + }; + + struct expression_base_t + { + std::string text; + + expression_base_t() = default; + expression_base_t(const std::string& text); + virtual std::string to_string() const; + virtual std::string finalize(bool put_end) const; + }; + + struct writer_t : expression_base_t + { + std::unordered_map code; + std::size_t position = 0; + + struct writer_to + { + std::string *code; + }; + + writer_to operator()(std::size_t position); + + template + void lines(const T&... exprs) + { + for (auto& expr : { exprs.finalize(true)... }) + { + code[position] += expr + "\n"; + } + } + + void lines(const std::string& string) + { + code[position] += string + "\n"; + } + + void next(); + + template + writer_t& operator +=(const T& expr) + { + lines(expr); + return *this; + } + + std::string build() + { + for (auto entry : code) + { + text += entry.second; + } + + code.clear(); + return text; + } + + std::string to_string() const override + { + return const_cast(this)->build(); + } + }; + }; +} \ No newline at end of file diff --git a/shader_code/clike_builder.h b/shader_code/clike_builder.h new file mode 100644 index 0000000..73cff44 --- /dev/null +++ b/shader_code/clike_builder.h @@ -0,0 +1,337 @@ +#pragma once +#include "builder.h" +#include "clike_language.h" + +namespace shader_code +{ + template + struct clike_builder : clike_language, builder + { + using language = Language; + + template + struct type_helper_t : clike_language::type_t + { + protected: + template + using expression_t = typename clike_language::expression_t; + + public: + static expression_t<> ctor() + { + return invoke(); + } + + static expression_t<> ctor(typename native_type_t::type value) + { + return invoke(expression_t(native_type_t::to_string(value))); + } + + template + static expression_t<> ctor(expression_t expr) + { + return invoke(expr); + } + + constexpr static const char* name() + { + return language::type_name_t::name; + } + + protected: + template + static expression_t<> invoke(T... exprs) + { + return function_t, language::type_name_t>::invoke(exprs...); + } + }; + + template + struct type_t; + + template + struct type_t : type_helper_t + { + using type_helper_t::ctor; + }; + + template + struct type_t : type_helper_t + { + using type_helper_t::ctor; + + template + static expression_t<> ctor(expression_t expr) + { + return invoke(expr); + } + + static expression_t<> ctor(expression_t a, expression_t b) + { + return invoke(a, b); + } + }; + + template + struct type_t : type_helper_t + { + using type_helper_t::ctor; + + template + static expression_t<> ctor(expression_t expr) + { + return invoke(expr); + } + + static expression_t<> ctor(expression_t a, expression_t b) + { + return invoke(a, b); + } + + static expression_t<> ctor(expression_t a, expression_t b) + { + return invoke(a, b); + } + + static expression_t<> ctor(expression_t a, expression_t b, expression_t c) + { + return invoke(a, b, c); + } + }; + + template + struct type_t : type_helper_t + { + using type_helper_t::ctor; + + template + static expression_t<> ctor(expression_t expr) + { + return invoke(expr); + } + + static expression_t<> ctor(expression_t a, expression_t b) + { + return invoke(a, b); + } + static expression_t<> ctor(expression_t a, expression_t b) + { + return invoke(a, b); + } + static expression_t<> ctor(expression_t a, expression_t b) + { + return invoke(a, b); + } + static expression_t<> ctor(expression_t a, expression_t b, expression_t c, expression_t d) + { + return invoke(a, b, c, d); + } + static expression_t<> ctor(expression_t a, expression_t b, expression_t c) + { + return invoke(a, b, c); + } + static expression_t<> ctor(expression_t a, expression_t b, expression_t c) + { + return invoke(a, b, c); + } + static expression_t<> ctor(expression_t a, expression_t b, expression_t c) + { + return invoke(a, b, c); + } + }; + + using sampler1D_t = typename type_t; + using sampler2D_t = typename type_t; + using sampler3D_t = typename type_t; + + template + using boolean_t = typename type_t; + + template + using integer_t = typename type_t; + + template + using float_point_t = typename type_t; + + static expression_from> texture(const expression_from& texture, const expression_from>& coord) + { + return function_t, language::function_name_t>::invoke(texture, coord); + } + + static expression_from> texture(const expression_from& texture, const expression_from>& coord) + { + return function_t, language::function_name_t>::invoke(texture, coord); + } + + static expression_from> texture_lod(const expression_from& texture, const expression_from>& coord, const expression_from>& lod) + { + return function_t, language::function_name_t>::invoke(texture, coord, lod); + } + + static expression_from> texture_bias(const expression_from& texture, const expression_from>& coord, const expression_from>& bias) + { + return function_t, language::function_name_t>::invoke(texture, coord, bias); + } + + static expression_from> texture_grad(const expression_from& texture, const expression_from>& coord, const expression_from>& ddx, const expression_from>& ddy) + { + return function_t, language::function_name_t>::invoke(texture, coord, ddx, ddy); + } + + static expression_from> texture(const expression_from& texture, const expression_from>& coord) + { + return function_t, language::function_name_t>::invoke(texture, coord); + } + + template + static expression_from> normalize(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + + template + static expression_from> abs(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + + template + static expression_from> abs(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + + template + static expression_from> normalize(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + + template + static expression_from> any(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + + template 1)>> + static expression_from> all(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + + template 1)>> + static expression_from> dot(const expression_t& a, const expression_t& b) + { + return function_t, language::function_name_t>::invoke(a, b); + } + + template + static expression_t min(const expression_t& a, const expression_t& b) + { + return function_t, language::function_name_t>::invoke(a, b); + } + + template + static expression_t max(const expression_t& a, const expression_t& b) + { + return function_t, language::function_name_t>::invoke(a, b); + } + + template 1)>> + static expression_from> greater(const expression_t& a, const expression_t& b) + { + return function_t, language::function_name_t>::invoke(a, b); + } + + template 1)>> + static expression_from> less(const expression_t& a, const expression_t& b) + { + return function_t, language::function_name_t>::invoke(a, b); + } + + template 1)>> + static expression_from> equal(const expression_t& a, const expression_t& b) + { + return function_t, language::function_name_t>::invoke(a, b); + } + + template 1)>> + static expression_from> greater_equal(const expression_t& a, const expression_t& b) + { + return function_t, language::function_name_t>::invoke(a, b); + } + + template 1)>> + static expression_from> less_equal(const expression_t& a, const expression_t& b) + { + return function_t, language::function_name_t>::invoke(a, b); + } + + template 1)>> + static expression_from> not_equal(const expression_t& a, const expression_t& b) + { + return function_t, language::function_name_t>::invoke(a, b); + } + + template + static expression_from> fract(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + template + static expression_from> floor(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + template + static expression_from> sin(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + template + static expression_from> cos(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + template + static expression_from> clamp(const expression_t& a, const expression_t& b, const expression_t& c) + { + return function_t, language::function_name_t>::invoke(a, b, c); + } + template + static expression_from> sqrt(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + template + static expression_from> rsqrt(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + template + static expression_from> pow(const expression_t& a, const expression_t& b) + { + return function_t, language::function_name_t>::invoke(a, b); + } + template + static expression_from> exp2(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + template + static expression_from> log2(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + template + static expression_from> ddx(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + template + static expression_from> ddy(const expression_t& arg) + { + return function_t, language::function_name_t>::invoke(arg); + } + }; +} \ No newline at end of file diff --git a/shader_code/clike_language.cpp b/shader_code/clike_language.cpp new file mode 100644 index 0000000..8565a8e --- /dev/null +++ b/shader_code/clike_language.cpp @@ -0,0 +1,15 @@ +#include "pch.h" +#include "clike_language.h" + +namespace shader_code +{ + clike_language::expression_from clike_language::begin_block() + { + return expression("\n{\n"); + } + + clike_language::expression_from clike_language::end_block() + { + return expression("\n}\n"); + } +} \ No newline at end of file diff --git a/shader_code/clike_language.h b/shader_code/clike_language.h new file mode 100644 index 0000000..28b0b47 --- /dev/null +++ b/shader_code/clike_language.h @@ -0,0 +1,579 @@ +#pragma once +#include "builder.h" + +namespace shader_code +{ + struct clike_language + { + enum class type_class_t + { + type_void, + type_bool, + type_int, + type_float, + type_sampler1D, + type_sampler2D, + type_sampler3D + }; + + template + struct native_type_base_t + { + using type = Type; + + static std::string to_string(Type value) + { + return std::to_string(value); + } + }; + + template + struct native_type_t; + + template<> + struct native_type_t + { + using type = bool; + + static std::string to_string(type value) + { + return value ? "true" : "false"; + } + }; + + template<> + struct native_type_t : native_type_base_t + { + }; + + template<> + struct native_type_t : native_type_base_t + { + }; + + template<> + struct native_type_t : native_type_base_t + { + }; + + template<> + struct native_type_t : native_type_base_t + { + }; + + template<> + struct native_type_t : native_type_base_t + { + }; + + template + using type_t = builder::type_t; + + template + using boolean_t = typename type_t; + + template + using integer_t = typename type_t; + + template + using float_point_t = typename type_t; + + using sampler1D_t = type_t; + using sampler2D_t = type_t; + using sampler3D_t = type_t; + using void_t = type_t; + + enum function_class_t + { + function_abs, + function_fract, + function_floor, + function_exp2, + function_log2, + function_pow, + function_texture, + function_texture_lod, + function_texture_bias, + function_texture_grad, + function_normalize, + function_any, + function_all, + function_dot, + function_min, + function_max, + function_greater, + function_less, + function_equal, + function_greater_equal, + function_less_equal, + function_not_equal, + function_sin, + function_cos, + function_clamp, + function_sqrt, + function_rsqrt, + function_ddx, + function_ddy + }; + + template + struct expression_t; + + template + using expression_from = expression_t; + + template + struct expression_helper_t : builder::expression_base_t + { + using type = type_t; + + std::string mask; + bool is_single; + int base_count = Count; + + expression_helper_t(const std::string& text, bool is_single = true) + : expression_base_t{ text } + , is_single(is_single) + , mask{ std::string("xyzw").substr(0, Count) } + { + } + + expression_helper_t(const std::string& text, const std::string& mask, bool is_single = true, int base_count = Count) + : expression_base_t{ text } + , is_single(is_single) + , mask(mask) + , base_count(base_count) + { + } + + template + expression_helper_t(const std::string& text, const char (&mask)[N], bool is_single = true, int base_count = Count) + : expression_helper_t{ text, std::string(mask), is_single, base_count } + { + static_assert(N == Count + 1, "Bad swizzle!"); + } + + void assign(const expression_helper_t& rhs) + { + text = rhs.text; + mask = rhs.mask; + is_single = rhs.is_single; + } + + template + auto swizzle(Channels... channels) const -> expression_t + { + static_assert(sizeof...(channels) <= 4 && sizeof...(channels) > 0, "bad swizzle"); + + std::string new_mask; + + using sw = std::string[]; sw{ (new_mask += mask.substr(channels, 1))... }; + + return{ !is_single ? "(" + text + ")" : text, new_mask, is_single, base_count }; + } + + std::string to_string() const override + { + if (mask.empty() || mask == std::string("xyzw").substr(0, base_count)) + { + if (!is_single) + { + return "(" + text + ")"; + } + + return text; + } + + if (!is_single) + { + return "(" + text + ")." + mask; + } + + return text + "." + mask; + } + + std::string finalize(bool put_end) const override + { + if (mask.empty() || mask == std::string("xyzw").substr(0, base_count)) + { + return text + (put_end ? ";" : ""); + } + + return text + "." + mask + (put_end ? ";" : ""); + } + + expression_t scope() const + { + return{ to_string() }; + } + + //protected: + template + expression_t call_operator(const std::string& opname, const ArgType& rhs) const + { + return{ to_string() + " " + opname + " " + rhs.to_string(), false }; + } + + template + expression_t call_operator(const std::string& opname) const + { + return{ opname + to_string(), true }; + } + }; + + template + struct expression_ctors_t : expression_helper_t + { + using expression_helper_t::expression_helper_t; + }; + + template + struct expression_ctors_t : expression_helper_t + { + expression_ctors_t(typename native_type_t::type value) + : expression_helper_t(native_type_t::to_string(value)) + { + } + + using expression_helper_t::expression_helper_t; + }; + +#define _SWIZZLE_MASK(pos) mask.substr(pos, 1) +#define _SWIZZLE_FUNC(Count, Name, ...) expression_t Name() const { return swizzle(__VA_ARGS__); } + +#define SWIZZLE1(Xn, Xv) _SWIZZLE_FUNC(1, Xn, (Xv)) +#define SWIZZLE2(Xn, Xv, Yn, Yv) _SWIZZLE_FUNC(2, Xn##Yn, Xv, Yv) +#define SWIZZLE3(Xn, Xv, Yn, Yv, Zn, Zv) _SWIZZLE_FUNC(3, Xn##Yn##Zn, Xv, Yv, Zv) +#define SWIZZLE4(Xn, Xv, Yn, Yv, Zn, Zv, Wn, Wv) _SWIZZLE_FUNC(4, Xn##Yn##Zn##Wn, Xv, Yv, Zv, Wv) + + +#define SWIZZLE4_2_1(Xn, Xv) \ + SWIZZLE2(Xn, Xv, x, 0) \ + SWIZZLE2(Xn, Xv, y, 1) \ + SWIZZLE2(Xn, Xv, z, 2) \ + SWIZZLE2(Xn, Xv, w, 3) \ + +#define SWIZZLE3_2_1(Xn, Xv) \ + SWIZZLE2(Xn, Xv, x, 0) \ + SWIZZLE2(Xn, Xv, y, 1) \ + SWIZZLE2(Xn, Xv, z, 2) \ + +#define SWIZZLE2_2_1(Xn, Xv) \ + SWIZZLE2(Xn, Xv, x, 0) \ + SWIZZLE2(Xn, Xv, y, 1) \ + +#define SWIZZLE4_3_2(Xn, Xv, Yn, Yv) \ + SWIZZLE3(Xn, Xv, Yn, Yv, x, 0) \ + SWIZZLE3(Xn, Xv, Yn, Yv, y, 1) \ + SWIZZLE3(Xn, Xv, Yn, Yv, z, 2) \ + SWIZZLE3(Xn, Xv, Yn, Yv, w, 3) \ + +#define SWIZZLE3_3_2(Xn, Xv, Yn, Yv) \ + SWIZZLE3(Xn, Xv, Yn, Yv, x, 0) \ + SWIZZLE3(Xn, Xv, Yn, Yv, y, 1) \ + SWIZZLE3(Xn, Xv, Yn, Yv, z, 2) \ + +#define SWIZZLE2_3_2(Xn, Xv, Yn, Yv) \ + SWIZZLE3(Xn, Xv, Yn, Yv, x, 0) \ + SWIZZLE3(Xn, Xv, Yn, Yv, y, 1) \ + +#define SWIZZLE4_3_1(Xn, Xv) \ + SWIZZLE4_3_2(Xn, Xv, x, 0) \ + SWIZZLE4_3_2(Xn, Xv, y, 1) \ + SWIZZLE4_3_2(Xn, Xv, z, 2) \ + SWIZZLE4_3_2(Xn, Xv, w, 3) \ + +#define SWIZZLE3_3_1(Xn, Xv) \ + SWIZZLE3_3_2(Xn, Xv, x, 0) \ + SWIZZLE3_3_2(Xn, Xv, y, 1) \ + SWIZZLE3_3_2(Xn, Xv, z, 2) \ + +#define SWIZZLE2_3_1(Xn, Xv) \ + SWIZZLE2_3_2(Xn, Xv, x, 0) \ + SWIZZLE2_3_2(Xn, Xv, y, 1) \ + + +#define SWIZZLE4_4_3(Xn, Xv, Yn, Yv, Zn, Zv) \ + SWIZZLE4(Xn, Xv, Yn, Yv, Zn, Zv, x, 0) \ + SWIZZLE4(Xn, Xv, Yn, Yv, Zn, Zv, y, 1) \ + SWIZZLE4(Xn, Xv, Yn, Yv, Zn, Zv, z, 2) \ + SWIZZLE4(Xn, Xv, Yn, Yv, Zn, Zv, w, 3) \ + +#define SWIZZLE3_4_3(Xn, Xv, Yn, Yv, Zn, Zv) \ + SWIZZLE4(Xn, Xv, Yn, Yv, Zn, Zv, x, 0) \ + SWIZZLE4(Xn, Xv, Yn, Yv, Zn, Zv, y, 1) \ + SWIZZLE4(Xn, Xv, Yn, Yv, Zn, Zv, z, 2) \ + +#define SWIZZLE2_4_3(Xn, Xv, Yn, Yv, Zn, Zv) \ + SWIZZLE4(Xn, Xv, Yn, Yv, Zn, Zv, x, 0) \ + SWIZZLE4(Xn, Xv, Yn, Yv, Zn, Zv, y, 1) \ + +#define SWIZZLE4_4_2(Xn, Xv, Yn, Yv) \ + SWIZZLE4_4_3(Xn, Xv, Yn, Yv, x, 0) \ + SWIZZLE4_4_3(Xn, Xv, Yn, Yv, y, 1) \ + SWIZZLE4_4_3(Xn, Xv, Yn, Yv, z, 2) \ + SWIZZLE4_4_3(Xn, Xv, Yn, Yv, w, 3) \ + +#define SWIZZLE3_4_2(Xn, Xv, Yn, Yv) \ + SWIZZLE3_4_3(Xn, Xv, Yn, Yv, x, 0) \ + SWIZZLE3_4_3(Xn, Xv, Yn, Yv, y, 1) \ + SWIZZLE3_4_3(Xn, Xv, Yn, Yv, z, 2) \ + +#define SWIZZLE2_4_2(Xn, Xv, Yn, Yv) \ + SWIZZLE2_4_3(Xn, Xv, Yn, Yv, x, 0) \ + SWIZZLE2_4_3(Xn, Xv, Yn, Yv, y, 1) \ + +#define SWIZZLE4_4_1(Xn, Xv) \ + SWIZZLE4_4_2(Xn, Xv, x, 0) \ + SWIZZLE4_4_2(Xn, Xv, y, 1) \ + SWIZZLE4_4_2(Xn, Xv, z, 2) \ + SWIZZLE4_4_2(Xn, Xv, w, 3) \ + +#define SWIZZLE3_4_1(Xn, Xv) \ + SWIZZLE3_4_2(Xn, Xv, x, 0) \ + SWIZZLE3_4_2(Xn, Xv, y, 1) \ + SWIZZLE3_4_2(Xn, Xv, z, 2) \ + +#define SWIZZLE2_4_1(Xn, Xv) \ + SWIZZLE2_4_2(Xn, Xv, x, 0) \ + SWIZZLE2_4_2(Xn, Xv, y, 1) \ + + + template + struct expression_swizzle_t : expression_ctors_t + { + using expression_ctors_t::expression_ctors_t; + }; + + template + struct expression_swizzle_t : expression_ctors_t + { + using expression_ctors_t::expression_ctors_t; + + SWIZZLE1(x, 0) + SWIZZLE1(y, 1) + + SWIZZLE2_2_1(x, 0) + SWIZZLE2_2_1(y, 1) + + SWIZZLE2_3_1(x, 0) + SWIZZLE2_3_1(y, 1) + + SWIZZLE2_4_1(x, 0) + SWIZZLE2_4_1(y, 1) + }; + + template + struct expression_swizzle_t : expression_ctors_t + { + using expression_ctors_t::expression_ctors_t; + + SWIZZLE1(x, 0) + SWIZZLE1(y, 1) + SWIZZLE1(z, 2) + + SWIZZLE3_2_1(x, 0) + SWIZZLE3_2_1(y, 1) + SWIZZLE3_2_1(z, 2) + + SWIZZLE3_3_1(x, 0) + SWIZZLE3_3_1(y, 1) + SWIZZLE3_3_1(z, 2) + + SWIZZLE3_4_1(x, 0) + SWIZZLE3_4_1(y, 1) + SWIZZLE3_4_1(z, 2) + }; + + template + struct expression_swizzle_t : expression_ctors_t + { + using expression_ctors_t::expression_ctors_t; + + SWIZZLE1(x, 0) + SWIZZLE1(y, 1) + SWIZZLE1(z, 2) + SWIZZLE1(w, 3) + + SWIZZLE4_2_1(x, 0) + SWIZZLE4_2_1(y, 1) + SWIZZLE4_2_1(z, 2) + SWIZZLE4_2_1(w, 3) + + SWIZZLE4_3_1(x, 0) + SWIZZLE4_3_1(y, 1) + SWIZZLE4_3_1(z, 2) + SWIZZLE4_3_1(w, 3) + + SWIZZLE4_4_1(x, 0) + SWIZZLE4_4_1(y, 1) + SWIZZLE4_4_1(z, 2) + SWIZZLE4_4_1(w, 3) + }; + + template + struct expression_t : expression_swizzle_t + { + using expression_swizzle_t::expression_swizzle_t; + + const expression_t operator -() + { + if (is_single && text[0] == '-') + return expression_t{ text.substr(1), mask }; + + return call_operator("-"); + } + + const expression_t operator-(const expression_t& rhs) const + { + if (rhs.is_single && rhs.text[0] == '-') + return call_operator("+", expression_t{ rhs.text.substr(1), rhs.mask }); + + return call_operator("-", rhs); + } + const expression_t operator+(const expression_t& rhs) const + { + if (rhs.is_single && rhs.text[0] == '-') + return call_operator("-", expression_t{ rhs.text.substr(1), rhs.mask }); + + return call_operator("+", rhs); + } + const expression_t operator/(const expression_t& rhs) const { return call_operator("/", rhs); } + const expression_t operator*(const expression_t& rhs) const { return call_operator("*", rhs); } + + expression_t operator-=(const expression_t& rhs) { return call_operator("-=", rhs); } + expression_t operator+=(const expression_t& rhs) { return call_operator("+=", rhs); } + expression_t operator/=(const expression_t& rhs) { return call_operator("/=", rhs); } + expression_t operator*=(const expression_t& rhs) { return call_operator("*=", rhs); } + + expression_t operator=(const expression_t& rhs) { return call_operator("=", rhs); } + + const expression_t operator-(const expression_t& rhs) const { return call_operator("-", rhs); } + const expression_t operator+(const expression_t& rhs) const { return call_operator("+", rhs); } + const expression_t operator/(const expression_t& rhs) const { return call_operator("/", rhs); } + const expression_t operator*(const expression_t& rhs) const { return call_operator("*", rhs); } + + expression_t operator-=(const expression_t& rhs) { return call_operator("-=", rhs); } + expression_t operator+=(const expression_t& rhs) { return call_operator("+=", rhs); } + expression_t operator/=(const expression_t& rhs) { return call_operator("/=", rhs); } + expression_t operator*=(const expression_t& rhs) { return call_operator("*=", rhs); } + }; + + template<> + struct expression_t : expression_swizzle_t + { + using expression_swizzle_t::expression_swizzle_t; + + expression_t operator=(const expression_t& rhs) { return call_operator("=", rhs); } + + const expression_from> operator!() const { return call_operator>("!"); } + const expression_from> operator==(const expression_t& rhs) const { return call_operator>("==", rhs); } + const expression_from> operator!=(const expression_t& rhs) const { return call_operator>("!=", rhs); } + }; + + template + struct expression_t : expression_swizzle_t + { + using expression_swizzle_t::expression_swizzle_t; + + expression_t operator=(const expression_t& rhs) { return call_operator("=", rhs); } + }; + + template + struct expression_t : expression_swizzle_t + { + using expression_swizzle_t::expression_swizzle_t; + + const expression_t operator -() + { + if (is_single && text[0] == '-') + return expression_t{ text.substr(1), mask }; + + return call_operator("-"); + } + + const expression_t operator-(const expression_t& rhs) const + { + if (rhs.is_single && rhs.text[0] == '-') + return call_operator("+", expression_t{ rhs.text.substr(1), rhs.mask }); + + return call_operator("-", rhs); + } + const expression_t operator+(const expression_t& rhs) const + { + if (rhs.is_single && rhs.text[0] == '-') + return call_operator("-", expression_t{ rhs.text.substr(1), rhs.mask }); + + return call_operator("+", rhs); + } + template const expression_t operator/(const expression_t& rhs) const { return call_operator>("/", rhs); } + template const expression_t operator*(const expression_t& rhs) const { return call_operator>("*", rhs); } + + expression_t operator=(const expression_t& rhs) { return call_operator("=", rhs); } + + expression_t operator-=(const expression_t& rhs) { return call_operator("-=", rhs); } + expression_t operator+=(const expression_t& rhs) { return call_operator("+=", rhs); } + expression_t operator/=(const expression_t& rhs) { return call_operator("/=", rhs); } + expression_t operator*=(const expression_t& rhs) { return call_operator("*=", rhs); } + + const expression_from> operator >(const expression_t& rhs) const { return call_operator>(">", rhs); } + const expression_from> operator >=(const expression_t& rhs) const { return call_operator>(">=", rhs); } + const expression_from> operator <(const expression_t& rhs) const { return call_operator>("<", rhs); } + const expression_from> operator <=(const expression_t& rhs) const { return call_operator>("<=", rhs); } + const expression_from> operator==(const expression_t& rhs) const { return call_operator>("==", rhs); } + const expression_from> operator!=(const expression_t& rhs) const { return call_operator>("!=", rhs); } + }; + + template + static expression_t<(type_class_t)Type::type, Type::count> expression(const std::string& text, bool is_single = true) + { + return{ text, is_single }; + } + + template + struct function_t + { + using return_type = Type; + + template + static expression_t<(type_class_t)return_type::type, return_type::count> invoke(const ArgsType&... args) + { + std::string result; + + using sw = std::string[]; sw{ (result += (result.empty() ? "" : ", ") + args.finalize(false))..., "" }; + + return{ std::string(NameType::name) + "(" + result + ")" }; + } + }; + + template + struct function_t + { + using return_type = ReturnType; + + static expression_from invoke(const expression_from&... args) + { + std::string result = std::string(NameType::name) + "("; + + using sw = std::string[]; sw{ (result += args.to_string())..., "" }; + + return{ result + ")" }; + } + }; + + template + static expression_from if_(expression_from> condition, expression_t then) + { + return expression("if (" + condition.finalize(false) + ") " + then.finalize(false)); + } + + template + static expression_from if_(expression_from> condition, expression_t then, expression_t else_) + { + return expression("if (" + condition.finalize(false) + ") " + then.finalize() + " else " + else_.finalize(false)); + } + + static expression_from begin_block(); + static expression_from end_block(); + }; +} \ No newline at end of file diff --git a/shader_code/glsl_builder.h b/shader_code/glsl_builder.h new file mode 100644 index 0000000..52715ab --- /dev/null +++ b/shader_code/glsl_builder.h @@ -0,0 +1,24 @@ +#pragma once +#include "clike_builder.h" +#include "glsl_language.h" + +namespace shader_code +{ + struct glsl_builder : clike_builder + { + using bool_t = boolean_t<1>; + using bvec2_t = boolean_t<2>; + using bvec3_t = boolean_t<3>; + using bvec4_t = boolean_t<4>; + + using int_t = integer_t<1>; + using ivec2_t = integer_t<2>; + using ivec3_t = integer_t<3>; + using ivec4_t = integer_t<4>; + + using float_t = float_point_t<1>; + using vec2_t = float_point_t<2>; + using vec3_t = float_point_t<3>; + using vec4_t = float_point_t<4>; + }; +} \ No newline at end of file diff --git a/shader_code/glsl_language.h b/shader_code/glsl_language.h new file mode 100644 index 0000000..6639f22 --- /dev/null +++ b/shader_code/glsl_language.h @@ -0,0 +1,268 @@ +#pragma once +#include "clike_language.h" + +namespace shader_code +{ + struct glsl_language + { + template + struct type_name_t; + + template<> + struct type_name_t + { + static constexpr char *name = "bool"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "bvec2"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "bvec3"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "bvec4"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "int"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "ivec2"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "ivec3"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "ivec4"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "float"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "vec2"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "vec3"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "vec4"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "sampler1D"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "sampler2D"; + }; + + template<> + struct type_name_t + { + static constexpr char *name = "sampler3D"; + }; + + + + template + struct function_name_t; + + template<> + struct function_name_t + { + static constexpr char *name = "abs"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "normalize"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "floor"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "fract"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "pow"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "texture"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "normalize"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "any"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "all"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "dot"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "greaterThan"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "lessThan"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "equal"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "greaterThanEqual"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "lessThanEqual"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "notEqual"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "sin"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "cos"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "clamp"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "min"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "max"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "sqrt"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "inversesqrt"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "exp2"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "log2"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "dFdx"; + }; + + template<> + struct function_name_t + { + static constexpr char *name = "dFdy"; + }; + }; +} \ No newline at end of file diff --git a/shader_code/pch.cpp b/shader_code/pch.cpp new file mode 100644 index 0000000..bcb5590 --- /dev/null +++ b/shader_code/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/shader_code/pch.h b/shader_code/pch.h new file mode 100644 index 0000000..73b4b86 --- /dev/null +++ b/shader_code/pch.h @@ -0,0 +1 @@ +#pragma once diff --git a/shader_code/shader_code.vcxproj b/shader_code/shader_code.vcxproj new file mode 100644 index 0000000..617bde1 --- /dev/null +++ b/shader_code/shader_code.vcxproj @@ -0,0 +1,170 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {97E17077-A21F-45EF-9C3A-73A0BC092D7E} + Win32Proj + shader_code + 8.1 + + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + StaticLibrary + true + v140 + Unicode + + + StaticLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + + + true + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + + + false + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + + + false + $(SolutionDir)lib\$(Platform)-$(Configuration)\ + $(SolutionDir)tmp\$(ProjectName)\$(Platform)-$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/shader_code/shader_code.vcxproj.filters b/shader_code/shader_code.vcxproj.filters new file mode 100644 index 0000000..57b102a --- /dev/null +++ b/shader_code/shader_code.vcxproj.filters @@ -0,0 +1,42 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file