diff options
Diffstat (limited to 'src/video_core/vertex_shader.h')
-rw-r--r-- | src/video_core/vertex_shader.h | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h new file mode 100644 index 000000000..1b71e367b --- /dev/null +++ b/src/video_core/vertex_shader.h @@ -0,0 +1,211 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include <initializer_list> + +#include <common/common_types.h> + +#include "math.h" +#include "pica.h" + +namespace Pica { + +namespace VertexShader { + +struct InputVertex { + Math::Vec4<float24> attr[16]; +}; + +struct OutputVertex { + OutputVertex() = default; + + // VS output attributes + Math::Vec4<float24> pos; + Math::Vec4<float24> dummy; // quaternions (not implemented, yet) + Math::Vec4<float24> color; + Math::Vec2<float24> tc0; + float24 tc0_v; + + // Padding for optimal alignment + float24 pad[14]; + + // Attributes used to store intermediate results + + // position after perspective divide + Math::Vec3<float24> screenpos; + + // Linear interpolation + // factor: 0=this, 1=vtx + void Lerp(float24 factor, const OutputVertex& vtx) { + pos = pos * factor + vtx.pos * (float24::FromFloat32(1) - factor); + + // TODO: Should perform perspective correct interpolation here... + tc0 = tc0 * factor + vtx.tc0 * (float24::FromFloat32(1) - factor); + + screenpos = screenpos * factor + vtx.screenpos * (float24::FromFloat32(1) - factor); + + color = color * factor + vtx.color * (float24::FromFloat32(1) - factor); + } + + // Linear interpolation + // factor: 0=v0, 1=v1 + static OutputVertex Lerp(float24 factor, const OutputVertex& v0, const OutputVertex& v1) { + OutputVertex ret = v0; + ret.Lerp(factor, v1); + return ret; + } +}; +static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); + +union Instruction { + enum class OpCode : u32 { + ADD = 0x0, + DP3 = 0x1, + DP4 = 0x2, + + MUL = 0x8, + + MAX = 0xC, + MIN = 0xD, + RCP = 0xE, + RSQ = 0xF, + + MOV = 0x13, + + RET = 0x21, + FLS = 0x22, // Flush + CALL = 0x24, + }; + + std::string GetOpCodeName() const { + std::map<OpCode, std::string> map = { + { OpCode::ADD, "ADD" }, + { OpCode::DP3, "DP3" }, + { OpCode::DP4, "DP4" }, + { OpCode::MUL, "MUL" }, + { OpCode::MAX, "MAX" }, + { OpCode::MIN, "MIN" }, + { OpCode::RCP, "RCP" }, + { OpCode::RSQ, "RSQ" }, + { OpCode::MOV, "MOV" }, + { OpCode::RET, "RET" }, + { OpCode::FLS, "FLS" }, + }; + auto it = map.find(opcode); + if (it == map.end()) + return "UNK"; + else + return it->second; + } + + u32 hex; + + BitField<0x1a, 0x6, OpCode> opcode; + + // General notes: + // + // When two input registers are used, one of them uses a 5-bit index while the other + // one uses a 7-bit index. This is because at most one floating point uniform may be used + // as an input. + + + // Format used e.g. by arithmetic instructions and comparisons + // "src1" and "src2" specify register indices (i.e. indices referring to groups of 4 floats), + // while "dest" addresses individual floats. + union { + BitField<0x00, 0x5, u32> operand_desc_id; + BitField<0x07, 0x5, u32> src2; + BitField<0x0c, 0x7, u32> src1; + BitField<0x13, 0x7, u32> dest; + } common; + + // Format used for flow control instructions ("if") + union { + BitField<0x00, 0x8, u32> num_instructions; + BitField<0x0a, 0xc, u32> offset_words; + } flow_control; +}; + +union SwizzlePattern { + u32 hex; + + enum class Selector : u32 { + x = 0, + y = 1, + z = 2, + w = 3 + }; + + Selector GetSelectorSrc1(int comp) const { + Selector selectors[] = { + src1_selector_0, src1_selector_1, src1_selector_2, src1_selector_3 + }; + return selectors[comp]; + } + + Selector GetSelectorSrc2(int comp) const { + Selector selectors[] = { + src2_selector_0, src2_selector_1, src2_selector_2, src2_selector_3 + }; + return selectors[comp]; + } + + bool DestComponentEnabled(int i) const { + return (dest_mask & (0x8 >> i)); + } + + std::string SelectorToString(bool src2) const { + std::map<Selector, std::string> map = { + { Selector::x, "x" }, + { Selector::y, "y" }, + { Selector::z, "z" }, + { Selector::w, "w" } + }; + std::string ret; + for (int i = 0; i < 4; ++i) { + ret += map.at(src2 ? GetSelectorSrc2(i) : GetSelectorSrc1(i)); + } + return ret; + } + + std::string DestMaskToString() const { + std::string ret; + for (int i = 0; i < 4; ++i) { + if (!DestComponentEnabled(i)) + ret += "_"; + else + ret += "xyzw"[i]; + } + return ret; + } + + // Components of "dest" that should be written to: LSB=dest.w, MSB=dest.x + BitField< 0, 4, u32> dest_mask; + + BitField< 5, 2, Selector> src1_selector_3; + BitField< 7, 2, Selector> src1_selector_2; + BitField< 9, 2, Selector> src1_selector_1; + BitField<11, 2, Selector> src1_selector_0; + + BitField<14, 2, Selector> src2_selector_3; + BitField<16, 2, Selector> src2_selector_2; + BitField<18, 2, Selector> src2_selector_1; + BitField<20, 2, Selector> src2_selector_0; + + BitField<31, 1, u32> flag; // not sure what this means, maybe it's the sign? +}; + +void SubmitShaderMemoryChange(u32 addr, u32 value); +void SubmitSwizzleDataChange(u32 addr, u32 value); + +OutputVertex RunShader(const InputVertex& input, int num_attributes); + +Math::Vec4<float24>& GetFloatUniform(u32 index); + +} // namespace + +} // namespace + |