registry.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright 2019 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <tuple>
  6. #include "common/assert.h"
  7. #include "common/common_types.h"
  8. #include "video_core/engines/kepler_compute.h"
  9. #include "video_core/engines/maxwell_3d.h"
  10. #include "video_core/engines/shader_type.h"
  11. #include "video_core/shader/registry.h"
  12. namespace VideoCommon::Shader {
  13. using Tegra::Engines::ConstBufferEngineInterface;
  14. using Tegra::Engines::SamplerDescriptor;
  15. using Tegra::Engines::ShaderType;
  16. namespace {
  17. GraphicsInfo MakeGraphicsInfo(ShaderType shader_stage, ConstBufferEngineInterface& engine) {
  18. if (shader_stage == ShaderType::Compute) {
  19. return {};
  20. }
  21. auto& graphics = static_cast<Tegra::Engines::Maxwell3D&>(engine);
  22. GraphicsInfo info;
  23. info.tfb_layouts = graphics.regs.tfb_layouts;
  24. info.tfb_varying_locs = graphics.regs.tfb_varying_locs;
  25. info.primitive_topology = graphics.regs.draw.topology;
  26. info.tessellation_primitive = graphics.regs.tess_mode.prim;
  27. info.tessellation_spacing = graphics.regs.tess_mode.spacing;
  28. info.tfb_enabled = graphics.regs.tfb_enabled;
  29. info.tessellation_clockwise = graphics.regs.tess_mode.cw;
  30. return info;
  31. }
  32. ComputeInfo MakeComputeInfo(ShaderType shader_stage, ConstBufferEngineInterface& engine) {
  33. if (shader_stage != ShaderType::Compute) {
  34. return {};
  35. }
  36. auto& compute = static_cast<Tegra::Engines::KeplerCompute&>(engine);
  37. const auto& launch = compute.launch_description;
  38. ComputeInfo info;
  39. info.workgroup_size = {launch.block_dim_x, launch.block_dim_y, launch.block_dim_z};
  40. info.local_memory_size_in_words = launch.local_pos_alloc;
  41. info.shared_memory_size_in_words = launch.shared_alloc;
  42. return info;
  43. }
  44. } // Anonymous namespace
  45. Registry::Registry(Tegra::Engines::ShaderType shader_stage, const SerializedRegistryInfo& info)
  46. : stage{shader_stage}, stored_guest_driver_profile{info.guest_driver_profile},
  47. bound_buffer{info.bound_buffer}, graphics_info{info.graphics}, compute_info{info.compute} {}
  48. Registry::Registry(Tegra::Engines::ShaderType shader_stage,
  49. Tegra::Engines::ConstBufferEngineInterface& engine)
  50. : stage{shader_stage}, engine{&engine}, bound_buffer{engine.GetBoundBuffer()},
  51. graphics_info{MakeGraphicsInfo(shader_stage, engine)}, compute_info{MakeComputeInfo(
  52. shader_stage, engine)} {}
  53. Registry::~Registry() = default;
  54. std::optional<u32> Registry::ObtainKey(u32 buffer, u32 offset) {
  55. const std::pair<u32, u32> key = {buffer, offset};
  56. const auto iter = keys.find(key);
  57. if (iter != keys.end()) {
  58. return iter->second;
  59. }
  60. if (!engine) {
  61. return std::nullopt;
  62. }
  63. const u32 value = engine->AccessConstBuffer32(stage, buffer, offset);
  64. keys.emplace(key, value);
  65. return value;
  66. }
  67. std::optional<SamplerDescriptor> Registry::ObtainBoundSampler(u32 offset) {
  68. const u32 key = offset;
  69. const auto iter = bound_samplers.find(key);
  70. if (iter != bound_samplers.end()) {
  71. return iter->second;
  72. }
  73. if (!engine) {
  74. return std::nullopt;
  75. }
  76. const SamplerDescriptor value = engine->AccessBoundSampler(stage, offset);
  77. bound_samplers.emplace(key, value);
  78. return value;
  79. }
  80. std::optional<Tegra::Engines::SamplerDescriptor> Registry::ObtainSeparateSampler(
  81. std::pair<u32, u32> buffers, std::pair<u32, u32> offsets) {
  82. SeparateSamplerKey key;
  83. key.buffers = buffers;
  84. key.offsets = offsets;
  85. const auto iter = separate_samplers.find(key);
  86. if (iter != separate_samplers.end()) {
  87. return iter->second;
  88. }
  89. if (!engine) {
  90. return std::nullopt;
  91. }
  92. const u32 handle_1 = engine->AccessConstBuffer32(stage, key.buffers.first, key.offsets.first);
  93. const u32 handle_2 = engine->AccessConstBuffer32(stage, key.buffers.second, key.offsets.second);
  94. const SamplerDescriptor value = engine->AccessSampler(handle_1 | handle_2);
  95. separate_samplers.emplace(key, value);
  96. return value;
  97. }
  98. std::optional<Tegra::Engines::SamplerDescriptor> Registry::ObtainBindlessSampler(u32 buffer,
  99. u32 offset) {
  100. const std::pair key = {buffer, offset};
  101. const auto iter = bindless_samplers.find(key);
  102. if (iter != bindless_samplers.end()) {
  103. return iter->second;
  104. }
  105. if (!engine) {
  106. return std::nullopt;
  107. }
  108. const SamplerDescriptor value = engine->AccessBindlessSampler(stage, buffer, offset);
  109. bindless_samplers.emplace(key, value);
  110. return value;
  111. }
  112. void Registry::InsertKey(u32 buffer, u32 offset, u32 value) {
  113. keys.insert_or_assign({buffer, offset}, value);
  114. }
  115. void Registry::InsertBoundSampler(u32 offset, SamplerDescriptor sampler) {
  116. bound_samplers.insert_or_assign(offset, sampler);
  117. }
  118. void Registry::InsertBindlessSampler(u32 buffer, u32 offset, SamplerDescriptor sampler) {
  119. bindless_samplers.insert_or_assign({buffer, offset}, sampler);
  120. }
  121. bool Registry::IsConsistent() const {
  122. if (!engine) {
  123. return true;
  124. }
  125. return std::all_of(keys.begin(), keys.end(),
  126. [this](const auto& pair) {
  127. const auto [cbuf, offset] = pair.first;
  128. const auto value = pair.second;
  129. return value == engine->AccessConstBuffer32(stage, cbuf, offset);
  130. }) &&
  131. std::all_of(bound_samplers.begin(), bound_samplers.end(),
  132. [this](const auto& sampler) {
  133. const auto [key, value] = sampler;
  134. return value == engine->AccessBoundSampler(stage, key);
  135. }) &&
  136. std::all_of(bindless_samplers.begin(), bindless_samplers.end(),
  137. [this](const auto& sampler) {
  138. const auto [cbuf, offset] = sampler.first;
  139. const auto value = sampler.second;
  140. return value == engine->AccessBindlessSampler(stage, cbuf, offset);
  141. });
  142. }
  143. bool Registry::HasEqualKeys(const Registry& rhs) const {
  144. return std::tie(keys, bound_samplers, bindless_samplers) ==
  145. std::tie(rhs.keys, rhs.bound_samplers, rhs.bindless_samplers);
  146. }
  147. const GraphicsInfo& Registry::GetGraphicsInfo() const {
  148. ASSERT(stage != Tegra::Engines::ShaderType::Compute);
  149. return graphics_info;
  150. }
  151. const ComputeInfo& Registry::GetComputeInfo() const {
  152. ASSERT(stage == Tegra::Engines::ShaderType::Compute);
  153. return compute_info;
  154. }
  155. } // namespace VideoCommon::Shader