diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/shader/const_buffer_locker.cpp | 152 | ||||
| -rw-r--r-- | src/video_core/shader/const_buffer_locker.h | 76 |
2 files changed, 76 insertions, 152 deletions
diff --git a/src/video_core/shader/const_buffer_locker.cpp b/src/video_core/shader/const_buffer_locker.cpp index 37a0968a1..ebeba102d 100644 --- a/src/video_core/shader/const_buffer_locker.cpp +++ b/src/video_core/shader/const_buffer_locker.cpp | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <algorithm> | ||
| 8 | #include <memory> | ||
| 7 | #include "common/assert.h" | 9 | #include "common/assert.h" |
| 8 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 9 | #include "video_core/engines/maxwell_3d.h" | 11 | #include "video_core/engines/maxwell_3d.h" |
| @@ -11,140 +13,92 @@ | |||
| 11 | 13 | ||
| 12 | namespace VideoCommon::Shader { | 14 | namespace VideoCommon::Shader { |
| 13 | 15 | ||
| 16 | using Tegra::Engines::SamplerDescriptor; | ||
| 17 | |||
| 14 | ConstBufferLocker::ConstBufferLocker(Tegra::Engines::ShaderType shader_stage) | 18 | ConstBufferLocker::ConstBufferLocker(Tegra::Engines::ShaderType shader_stage) |
| 15 | : engine{nullptr}, shader_stage{shader_stage} {} | 19 | : stage{shader_stage} {} |
| 16 | 20 | ||
| 17 | ConstBufferLocker::ConstBufferLocker(Tegra::Engines::ShaderType shader_stage, | 21 | ConstBufferLocker::ConstBufferLocker(Tegra::Engines::ShaderType shader_stage, |
| 18 | Tegra::Engines::ConstBufferEngineInterface& engine) | 22 | Tegra::Engines::ConstBufferEngineInterface& engine) |
| 19 | : engine{&engine}, shader_stage{shader_stage} {} | 23 | : stage{shader_stage}, engine{&engine} {} |
| 20 | |||
| 21 | bool ConstBufferLocker::IsEngineSet() const { | ||
| 22 | return engine != nullptr; | ||
| 23 | } | ||
| 24 | |||
| 25 | void ConstBufferLocker::SetEngine(Tegra::Engines::ConstBufferEngineInterface& engine_) { | ||
| 26 | engine = &engine_; | ||
| 27 | } | ||
| 28 | 24 | ||
| 29 | std::optional<u32> ConstBufferLocker::ObtainKey(u32 buffer, u32 offset) { | 25 | std::optional<u32> ConstBufferLocker::ObtainKey(u32 buffer, u32 offset) { |
| 30 | if (!keys) { | ||
| 31 | keys = std::make_shared<KeyMap>(); | ||
| 32 | } | ||
| 33 | auto& key_map = *keys; | ||
| 34 | const std::pair<u32, u32> key = {buffer, offset}; | 26 | const std::pair<u32, u32> key = {buffer, offset}; |
| 35 | const auto iter = key_map.find(key); | 27 | const auto iter = keys.find(key); |
| 36 | if (iter != key_map.end()) { | 28 | if (iter != keys.end()) { |
| 37 | return {iter->second}; | 29 | return iter->second; |
| 38 | } | 30 | } |
| 39 | if (!IsEngineSet()) { | 31 | if (!engine) { |
| 40 | return {}; | 32 | return {}; |
| 41 | } | 33 | } |
| 42 | const u32 value = engine->AccessConstBuffer32(shader_stage, buffer, offset); | 34 | const u32 value = engine->AccessConstBuffer32(stage, buffer, offset); |
| 43 | key_map.emplace(key, value); | 35 | keys.emplace(key, value); |
| 44 | return {value}; | 36 | return value; |
| 45 | } | 37 | } |
| 46 | 38 | ||
| 47 | std::optional<Tegra::Engines::SamplerDescriptor> ConstBufferLocker::ObtainBoundSampler(u32 offset) { | 39 | std::optional<SamplerDescriptor> ConstBufferLocker::ObtainBoundSampler(u32 offset) { |
| 48 | if (!bound_samplers) { | ||
| 49 | bound_samplers = std::make_shared<BoundSamplerMap>(); | ||
| 50 | } | ||
| 51 | auto& key_map = *bound_samplers; | ||
| 52 | const u32 key = offset; | 40 | const u32 key = offset; |
| 53 | const auto iter = key_map.find(key); | 41 | const auto iter = bound_samplers.find(key); |
| 54 | if (iter != key_map.end()) { | 42 | if (iter != bound_samplers.end()) { |
| 55 | return {iter->second}; | 43 | return iter->second; |
| 56 | } | 44 | } |
| 57 | if (!IsEngineSet()) { | 45 | if (!engine) { |
| 58 | return {}; | 46 | return {}; |
| 59 | } | 47 | } |
| 60 | const Tegra::Engines::SamplerDescriptor value = | 48 | const SamplerDescriptor value = engine->AccessBoundSampler(stage, offset); |
| 61 | engine->AccessBoundSampler(shader_stage, offset); | 49 | bound_samplers.emplace(key, value); |
| 62 | key_map.emplace(key, value); | 50 | return value; |
| 63 | return {value}; | ||
| 64 | } | 51 | } |
| 65 | 52 | ||
| 66 | std::optional<Tegra::Engines::SamplerDescriptor> ConstBufferLocker::ObtainBindlessSampler( | 53 | std::optional<Tegra::Engines::SamplerDescriptor> ConstBufferLocker::ObtainBindlessSampler( |
| 67 | u32 buffer, u32 offset) { | 54 | u32 buffer, u32 offset) { |
| 68 | if (!bindless_samplers) { | 55 | const std::pair key = {buffer, offset}; |
| 69 | bindless_samplers = std::make_shared<BindlessSamplerMap>(); | 56 | const auto iter = bindless_samplers.find(key); |
| 70 | } | 57 | if (iter != bindless_samplers.end()) { |
| 71 | auto& key_map = *bindless_samplers; | 58 | return iter->second; |
| 72 | const std::pair<u32, u32> key = {buffer, offset}; | ||
| 73 | const auto iter = key_map.find(key); | ||
| 74 | if (iter != key_map.end()) { | ||
| 75 | return {iter->second}; | ||
| 76 | } | 59 | } |
| 77 | if (!IsEngineSet()) { | 60 | if (!engine) { |
| 78 | return {}; | 61 | return {}; |
| 79 | } | 62 | } |
| 80 | const Tegra::Engines::SamplerDescriptor value = | 63 | const SamplerDescriptor value = engine->AccessBindlessSampler(stage, buffer, offset); |
| 81 | engine->AccessBindlessSampler(shader_stage, buffer, offset); | 64 | bindless_samplers.emplace(key, value); |
| 82 | key_map.emplace(key, value); | 65 | return value; |
| 83 | return {value}; | ||
| 84 | } | 66 | } |
| 85 | 67 | ||
| 86 | void ConstBufferLocker::InsertKey(u32 buffer, u32 offset, u32 value) { | 68 | void ConstBufferLocker::InsertKey(u32 buffer, u32 offset, u32 value) { |
| 87 | if (!keys) { | 69 | keys.insert_or_assign({buffer, offset}, value); |
| 88 | keys = std::make_shared<KeyMap>(); | ||
| 89 | } | ||
| 90 | const std::pair<u32, u32> key = {buffer, offset}; | ||
| 91 | (*keys)[key] = value; | ||
| 92 | } | 70 | } |
| 93 | 71 | ||
| 94 | void ConstBufferLocker::InsertBoundSampler(u32 offset, Tegra::Engines::SamplerDescriptor sampler) { | 72 | void ConstBufferLocker::InsertBoundSampler(u32 offset, SamplerDescriptor sampler) { |
| 95 | if (!bound_samplers) { | 73 | bound_samplers.insert_or_assign(offset, sampler); |
| 96 | bound_samplers = std::make_shared<BoundSamplerMap>(); | ||
| 97 | } | ||
| 98 | (*bound_samplers)[offset] = sampler; | ||
| 99 | } | 74 | } |
| 100 | 75 | ||
| 101 | void ConstBufferLocker::InsertBindlessSampler(u32 buffer, u32 offset, | 76 | void ConstBufferLocker::InsertBindlessSampler(u32 buffer, u32 offset, SamplerDescriptor sampler) { |
| 102 | Tegra::Engines::SamplerDescriptor sampler) { | 77 | bindless_samplers.insert_or_assign({buffer, offset}, sampler); |
| 103 | if (!bindless_samplers) { | ||
| 104 | bindless_samplers = std::make_shared<BindlessSamplerMap>(); | ||
| 105 | } | ||
| 106 | const std::pair<u32, u32> key = {buffer, offset}; | ||
| 107 | (*bindless_samplers)[key] = sampler; | ||
| 108 | } | 78 | } |
| 109 | 79 | ||
| 110 | bool ConstBufferLocker::IsConsistent() const { | 80 | bool ConstBufferLocker::IsConsistent() const { |
| 111 | if (!IsEngineSet()) { | 81 | if (!engine) { |
| 112 | return false; | 82 | return false; |
| 113 | } | 83 | } |
| 114 | if (keys) { | 84 | return std::all_of(keys.begin(), keys.end(), |
| 115 | for (const auto& key_val : *keys) { | 85 | [](const auto& key) { |
| 116 | const std::pair<u32, u32> key = key_val.first; | 86 | const auto [value, other_value] = key.first; |
| 117 | const u32 value = key_val.second; | 87 | return value == other_value; |
| 118 | const u32 other_value = | 88 | }) && |
| 119 | engine->AccessConstBuffer32(shader_stage, key.first, key.second); | 89 | std::all_of(bound_samplers.begin(), bound_samplers.end(), |
| 120 | if (other_value != value) { | 90 | [this](const auto& sampler) { |
| 121 | return false; | 91 | const auto [key, value] = sampler; |
| 122 | } | 92 | const auto other_value = engine->AccessBoundSampler(stage, key); |
| 123 | } | 93 | return value.raw == other_value.raw; |
| 124 | } | 94 | }) && |
| 125 | if (bound_samplers) { | 95 | std::all_of( |
| 126 | for (const auto& sampler_val : *bound_samplers) { | 96 | bindless_samplers.begin(), bindless_samplers.end(), [this](const auto& sampler) { |
| 127 | const u32 key = sampler_val.first; | 97 | const auto [cbuf, offset] = sampler.first; |
| 128 | const Tegra::Engines::SamplerDescriptor value = sampler_val.second; | 98 | const auto value = sampler.second; |
| 129 | const Tegra::Engines::SamplerDescriptor other_value = | 99 | const auto other_value = engine->AccessBindlessSampler(stage, cbuf, offset); |
| 130 | engine->AccessBoundSampler(shader_stage, key); | 100 | return value.raw == other_value.raw; |
| 131 | if (other_value.raw != value.raw) { | 101 | }); |
| 132 | return false; | ||
| 133 | } | ||
| 134 | } | ||
| 135 | } | ||
| 136 | if (bindless_samplers) { | ||
| 137 | for (const auto& sampler_val : *bindless_samplers) { | ||
| 138 | const std::pair<u32, u32> key = sampler_val.first; | ||
| 139 | const Tegra::Engines::SamplerDescriptor value = sampler_val.second; | ||
| 140 | const Tegra::Engines::SamplerDescriptor other_value = | ||
| 141 | engine->AccessBindlessSampler(shader_stage, key.first, key.second); | ||
| 142 | if (other_value.raw != value.raw) { | ||
| 143 | return false; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | } | ||
| 147 | return true; | ||
| 148 | } | 102 | } |
| 149 | 103 | ||
| 150 | } // namespace VideoCommon::Shader | 104 | } // namespace VideoCommon::Shader |
diff --git a/src/video_core/shader/const_buffer_locker.h b/src/video_core/shader/const_buffer_locker.h index 54459977f..417d5a16f 100644 --- a/src/video_core/shader/const_buffer_locker.h +++ b/src/video_core/shader/const_buffer_locker.h | |||
| @@ -23,78 +23,48 @@ public: | |||
| 23 | explicit ConstBufferLocker(Tegra::Engines::ShaderType shader_stage, | 23 | explicit ConstBufferLocker(Tegra::Engines::ShaderType shader_stage, |
| 24 | Tegra::Engines::ConstBufferEngineInterface& engine); | 24 | Tegra::Engines::ConstBufferEngineInterface& engine); |
| 25 | 25 | ||
| 26 | // Checks if an engine is setup, it may be possible that during disk shader | 26 | /// Retrieves a key from the locker, if it's registered, it will give the registered value, if |
| 27 | // cache run, the engines have not been created yet. | 27 | /// not it will obtain it from maxwell3d and register it. |
| 28 | bool IsEngineSet() const; | ||
| 29 | |||
| 30 | // Use this to set/change the engine used for this shader. | ||
| 31 | void SetEngine(Tegra::Engines::ConstBufferEngineInterface& engine); | ||
| 32 | |||
| 33 | // Retrieves a key from the locker, if it's registered, it will give the | ||
| 34 | // registered value, if not it will obtain it from maxwell3d and register it. | ||
| 35 | std::optional<u32> ObtainKey(u32 buffer, u32 offset); | 28 | std::optional<u32> ObtainKey(u32 buffer, u32 offset); |
| 36 | 29 | ||
| 37 | std::optional<Tegra::Engines::SamplerDescriptor> ObtainBoundSampler(u32 offset); | 30 | std::optional<Tegra::Engines::SamplerDescriptor> ObtainBoundSampler(u32 offset); |
| 38 | 31 | ||
| 39 | std::optional<Tegra::Engines::SamplerDescriptor> ObtainBindlessSampler(u32 buffer, u32 offset); | 32 | std::optional<Tegra::Engines::SamplerDescriptor> ObtainBindlessSampler(u32 buffer, u32 offset); |
| 40 | 33 | ||
| 41 | // Manually inserts a key. | 34 | /// Inserts a key. |
| 42 | void InsertKey(u32 buffer, u32 offset, u32 value); | 35 | void InsertKey(u32 buffer, u32 offset, u32 value); |
| 43 | 36 | ||
| 37 | /// Inserts a bound sampler key. | ||
| 44 | void InsertBoundSampler(u32 offset, Tegra::Engines::SamplerDescriptor sampler); | 38 | void InsertBoundSampler(u32 offset, Tegra::Engines::SamplerDescriptor sampler); |
| 45 | 39 | ||
| 40 | /// Inserts a bindless sampler key. | ||
| 46 | void InsertBindlessSampler(u32 buffer, u32 offset, Tegra::Engines::SamplerDescriptor sampler); | 41 | void InsertBindlessSampler(u32 buffer, u32 offset, Tegra::Engines::SamplerDescriptor sampler); |
| 47 | 42 | ||
| 48 | // Retrieves the number of keys registered. | 43 | /// Checks keys and samplers against engine's current const buffers. Returns true if they are |
| 49 | std::size_t NumKeys() const { | 44 | /// the same value, false otherwise; |
| 50 | if (!keys) { | 45 | bool IsConsistent() const; |
| 51 | return 0; | ||
| 52 | } | ||
| 53 | return keys->size(); | ||
| 54 | } | ||
| 55 | |||
| 56 | std::size_t NumBoundSamplers() const { | ||
| 57 | if (!bound_samplers) { | ||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | return bound_samplers->size(); | ||
| 61 | } | ||
| 62 | |||
| 63 | std::size_t NumBindlessSamplers() const { | ||
| 64 | if (!bindless_samplers) { | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | return bindless_samplers->size(); | ||
| 68 | } | ||
| 69 | 46 | ||
| 70 | // Gives an accessor to the key's database. | 47 | /// Gives an getter to the const buffer keys in the database. |
| 71 | // Pre: NumKeys > 0 | 48 | const KeyMap& GetKeys() const { |
| 72 | const KeyMap& AccessKeys() const { | 49 | return keys; |
| 73 | return *keys; | ||
| 74 | } | 50 | } |
| 75 | 51 | ||
| 76 | // Gives an accessor to the sampler's database. | 52 | /// Gets samplers database. |
| 77 | // Pre: NumBindlessSamplers > 0 | 53 | const BoundSamplerMap& GetBoundSamplers() const { |
| 78 | const BoundSamplerMap& AccessBoundSamplers() const { | 54 | return bound_samplers; |
| 79 | return *bound_samplers; | ||
| 80 | } | 55 | } |
| 81 | 56 | ||
| 82 | // Gives an accessor to the sampler's database. | 57 | /// Gets bindless samplers database. |
| 83 | // Pre: NumBindlessSamplers > 0 | 58 | const BindlessSamplerMap& GetBindlessSamplers() const { |
| 84 | const BindlessSamplerMap& AccessBindlessSamplers() const { | 59 | return bindless_samplers; |
| 85 | return *bindless_samplers; | ||
| 86 | } | 60 | } |
| 87 | 61 | ||
| 88 | // Checks keys & samplers against engine's current const buffers. Returns true if they | ||
| 89 | // are the same value, false otherwise; | ||
| 90 | bool IsConsistent() const; | ||
| 91 | |||
| 92 | private: | 62 | private: |
| 93 | Tegra::Engines::ConstBufferEngineInterface* engine; | 63 | const Tegra::Engines::ShaderType stage; |
| 94 | Tegra::Engines::ShaderType shader_stage; | 64 | Tegra::Engines::ConstBufferEngineInterface* engine = nullptr; |
| 95 | // All containers are lazy initialized as most shaders don't use them. | 65 | KeyMap keys; |
| 96 | std::shared_ptr<KeyMap> keys{}; | 66 | BoundSamplerMap bound_samplers; |
| 97 | std::shared_ptr<BoundSamplerMap> bound_samplers{}; | 67 | BindlessSamplerMap bindless_samplers; |
| 98 | std::shared_ptr<BindlessSamplerMap> bindless_samplers{}; | ||
| 99 | }; | 68 | }; |
| 69 | |||
| 100 | } // namespace VideoCommon::Shader | 70 | } // namespace VideoCommon::Shader |