diff --git a/core/shader/recompiler/Recompiler.cpp b/core/shader/recompiler/Recompiler.cpp index 7e5883eeb..770bcef49 100644 --- a/core/shader/recompiler/Recompiler.cpp +++ b/core/shader/recompiler/Recompiler.cpp @@ -290,6 +290,14 @@ struct SourceEntry { namespace { +class PrimedSharedMutex : public std::shared_mutex { +public: + PrimedSharedMutex() { + lock(); + unlock(); + } +}; + struct ResourceProgram { explicit ResourceProgram(const RecompileRequest& request, ShaderPreparationContext* preparation = nullptr) : program(std::make_unique(PrepareResourceProgram(request, preparation))), plan(std::make_shared(ResourceMaterializer{}.ExtractPlan(*program))) {} @@ -318,7 +326,7 @@ bool FailureMemo() { } std::shared_ptr getSource(const RecompileRequest& request, ShaderPreparationContext* preparation = nullptr) { - static std::shared_mutex mutex; + static PrimedSharedMutex mutex; // Entries whose code hashes alike share a bucket; the code comparison picks the right one. static std::unordered_map, std::vector>, SourceKeyHash> sources; struct SourceKeyStorage {}; @@ -587,7 +595,7 @@ struct PreparedBindingPlan { std::once_flag ready; std::exception_ptr failure; DescriptorBindingPlan bindings; - std::shared_mutex mutex; + PrimedSharedMutex mutex; std::map, std::shared_ptr> modules; }; @@ -618,7 +626,7 @@ std::shared_ptr preparedBindingPlan(const CompiledVariant& } key.push_back(exports.size()); for (const auto mapping : exports) key.push_back(mapping); - static std::shared_mutex mutex; + static PrimedSharedMutex mutex; static std::map, std::shared_ptr> plans; std::shared_ptr plan; { @@ -647,7 +655,7 @@ std::shared_ptr specializeModule(const CompiledShaderAr key.clear(); key.push_back(artifact.variantId); for (const auto& constant : constants) key.push_back((static_cast(constant.id) << 32u) | constant.value); - static std::shared_mutex mutex; + static PrimedSharedMutex mutex; static std::map, std::shared_ptr> modules; std::shared_ptr entry; { diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index 0c72b62a7..cd6228162 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -7,7 +7,7 @@ - libgcc_s_seh-1.dll - libstdc++-6.dll - libwinpthread-1.dll -- winpthreads initializes a statically initialized rwlock on its first lock and fails a concurrent first lock with `EINVAL`, which `std::shared_mutex` and `std::shared_timed_mutex` ignore, so that lock does not exclude. Guest rwlocks ([Pthread.hpp](../../core/libs/prx/libkernel/Pthread/include/Pthread.hpp)) are locked once when created. The host `std::shared_mutex` objects in [Recompiler.cpp](../../core/shader/recompiler/Recompiler.cpp) and [GuestWriteWatch.cpp](../../core/libs/prx/libc/src/GuestWriteWatch.cpp) are not, and can still race on their first contended use. +- winpthreads initializes a statically initialized rwlock on its first lock and fails a concurrent first lock with `EINVAL`, which `std::shared_mutex` and `std::shared_timed_mutex` ignore, so that lock does not exclude. Guest rwlocks ([Pthread.hpp](../../core/libs/prx/libkernel/Pthread/include/Pthread.hpp)) and the host `std::shared_mutex` objects in [Recompiler.cpp](../../core/shader/recompiler/Recompiler.cpp) are locked once when created. A new host `std::shared_mutex` used on Windows needs the same. ### Silent stubs