shader.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <array>
  6. #include <cstddef>
  7. #include <type_traits>
  8. #include <nihstro/shader_bytecode.h>
  9. #include "common/assert.h"
  10. #include "common/common_funcs.h"
  11. #include "common/common_types.h"
  12. #include "common/vector_math.h"
  13. #include "video_core/pica.h"
  14. #include "video_core/pica_types.h"
  15. using nihstro::RegisterType;
  16. using nihstro::SourceRegister;
  17. using nihstro::DestRegister;
  18. namespace Pica {
  19. namespace Shader {
  20. struct AttributeBuffer {
  21. alignas(16) Math::Vec4<float24> attr[16];
  22. };
  23. struct OutputVertex {
  24. Math::Vec4<float24> pos;
  25. Math::Vec4<float24> quat;
  26. Math::Vec4<float24> color;
  27. Math::Vec2<float24> tc0;
  28. Math::Vec2<float24> tc1;
  29. float24 tc0_w;
  30. INSERT_PADDING_WORDS(1);
  31. Math::Vec3<float24> view;
  32. INSERT_PADDING_WORDS(1);
  33. Math::Vec2<float24> tc2;
  34. static OutputVertex FromAttributeBuffer(const Regs& regs, AttributeBuffer& output);
  35. };
  36. #define ASSERT_POS(var, pos) \
  37. static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong " \
  38. "offset.")
  39. ASSERT_POS(pos, Regs::VSOutputAttributes::POSITION_X);
  40. ASSERT_POS(quat, Regs::VSOutputAttributes::QUATERNION_X);
  41. ASSERT_POS(color, Regs::VSOutputAttributes::COLOR_R);
  42. ASSERT_POS(tc0, Regs::VSOutputAttributes::TEXCOORD0_U);
  43. ASSERT_POS(tc1, Regs::VSOutputAttributes::TEXCOORD1_U);
  44. ASSERT_POS(tc0_w, Regs::VSOutputAttributes::TEXCOORD0_W);
  45. ASSERT_POS(view, Regs::VSOutputAttributes::VIEW_X);
  46. ASSERT_POS(tc2, Regs::VSOutputAttributes::TEXCOORD2_U);
  47. #undef ASSERT_POS
  48. static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
  49. static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size");
  50. /**
  51. * This structure contains the state information that needs to be unique for a shader unit. The 3DS
  52. * has four shader units that process shaders in parallel. At the present, Citra only implements a
  53. * single shader unit that processes all shaders serially. Putting the state information in a struct
  54. * here will make it easier for us to parallelize the shader processing later.
  55. */
  56. struct UnitState {
  57. struct Registers {
  58. // The registers are accessed by the shader JIT using SSE instructions, and are therefore
  59. // required to be 16-byte aligned.
  60. alignas(16) Math::Vec4<float24> input[16];
  61. alignas(16) Math::Vec4<float24> temporary[16];
  62. alignas(16) Math::Vec4<float24> output[16];
  63. } registers;
  64. static_assert(std::is_pod<Registers>::value, "Structure is not POD");
  65. bool conditional_code[2];
  66. // Two Address registers and one loop counter
  67. // TODO: How many bits do these actually have?
  68. s32 address_registers[3];
  69. static size_t InputOffset(const SourceRegister& reg) {
  70. switch (reg.GetRegisterType()) {
  71. case RegisterType::Input:
  72. return offsetof(UnitState, registers.input) +
  73. reg.GetIndex() * sizeof(Math::Vec4<float24>);
  74. case RegisterType::Temporary:
  75. return offsetof(UnitState, registers.temporary) +
  76. reg.GetIndex() * sizeof(Math::Vec4<float24>);
  77. default:
  78. UNREACHABLE();
  79. return 0;
  80. }
  81. }
  82. static size_t OutputOffset(const DestRegister& reg) {
  83. switch (reg.GetRegisterType()) {
  84. case RegisterType::Output:
  85. return offsetof(UnitState, registers.output) +
  86. reg.GetIndex() * sizeof(Math::Vec4<float24>);
  87. case RegisterType::Temporary:
  88. return offsetof(UnitState, registers.temporary) +
  89. reg.GetIndex() * sizeof(Math::Vec4<float24>);
  90. default:
  91. UNREACHABLE();
  92. return 0;
  93. }
  94. }
  95. /**
  96. * Loads the unit state with an input vertex.
  97. *
  98. * @param config Shader configuration registers corresponding to the unit.
  99. * @param input Attribute buffer to load into the input registers.
  100. */
  101. void LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input);
  102. void WriteOutput(const Regs::ShaderConfig& config, AttributeBuffer& output);
  103. };
  104. struct ShaderSetup {
  105. struct {
  106. // The float uniforms are accessed by the shader JIT using SSE instructions, and are
  107. // therefore required to be 16-byte aligned.
  108. alignas(16) Math::Vec4<float24> f[96];
  109. std::array<bool, 16> b;
  110. std::array<Math::Vec4<u8>, 4> i;
  111. } uniforms;
  112. static size_t GetFloatUniformOffset(unsigned index) {
  113. return offsetof(ShaderSetup, uniforms.f) + index * sizeof(Math::Vec4<float24>);
  114. }
  115. static size_t GetBoolUniformOffset(unsigned index) {
  116. return offsetof(ShaderSetup, uniforms.b) + index * sizeof(bool);
  117. }
  118. static size_t GetIntUniformOffset(unsigned index) {
  119. return offsetof(ShaderSetup, uniforms.i) + index * sizeof(Math::Vec4<u8>);
  120. }
  121. std::array<u32, 1024> program_code;
  122. std::array<u32, 1024> swizzle_data;
  123. /// Data private to ShaderEngines
  124. struct EngineData {
  125. unsigned int entry_point;
  126. /// Used by the JIT, points to a compiled shader object.
  127. const void* cached_shader = nullptr;
  128. } engine_data;
  129. };
  130. class ShaderEngine {
  131. public:
  132. virtual ~ShaderEngine() = default;
  133. /**
  134. * Performs any shader unit setup that only needs to happen once per shader (as opposed to once
  135. * per vertex, which would happen within the `Run` function).
  136. */
  137. virtual void SetupBatch(ShaderSetup& setup, unsigned int entry_point) = 0;
  138. /**
  139. * Runs the currently setup shader.
  140. *
  141. * @param setup Shader engine state, must be setup with SetupBatch on each shader change.
  142. * @param state Shader unit state, must be setup with input data before each shader invocation.
  143. */
  144. virtual void Run(const ShaderSetup& setup, UnitState& state) const = 0;
  145. };
  146. // TODO(yuriks): Remove and make it non-global state somewhere
  147. ShaderEngine* GetEngine();
  148. void Shutdown();
  149. } // namespace Shader
  150. } // namespace Pica