Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More crash fix attempts #18211

Merged
merged 3 commits into from
Sep 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Common/Data/Collections/Hashmaps.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ class DenseHashMap {
return false;
}

// This will never crash if you call it without locking - but, the value might not be right.
size_t size() const {
return count_;
}
Expand Down
3 changes: 3 additions & 0 deletions Common/GPU/Vulkan/thin3d_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -874,8 +874,11 @@ VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread)
caps_.tesselationShaderSupported = vulkan->GetDeviceFeatures().enabled.standard.tessellationShader != 0;
caps_.dualSourceBlend = vulkan->GetDeviceFeatures().enabled.standard.dualSrcBlend != 0;
caps_.depthClampSupported = vulkan->GetDeviceFeatures().enabled.standard.depthClamp != 0;

// Comment out these two to test geometry shader culling on any geometry shader-supporting hardware.
caps_.clipDistanceSupported = vulkan->GetDeviceFeatures().enabled.standard.shaderClipDistance != 0;
caps_.cullDistanceSupported = vulkan->GetDeviceFeatures().enabled.standard.shaderCullDistance != 0;

caps_.framebufferBlitSupported = true;
caps_.framebufferCopySupported = true;
caps_.framebufferDepthBlitSupported = vulkan->GetDeviceInfo().canBlitToPreferredDepthStencilFormat;
Expand Down
4 changes: 2 additions & 2 deletions GPU/Vulkan/DrawEngineVulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ void DrawEngineVulkan::InitDeviceObjects() {
bindings[3].descriptorCount = 1;
bindings[3].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
bindings[3].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
if (gstate_c.Use(GPU_USE_GS_CULLING))
bindings[3].stageFlags |= VK_SHADER_STAGE_GEOMETRY_BIT;
if (draw_->GetDeviceCaps().geometryShaderSupported)
bindings[3].stageFlags |= VK_SHADER_STAGE_GEOMETRY_BIT; // unlikely to have a penalty. if we check GPU_USE_GS_CULLING, we have problems on runtime toggle.
bindings[3].binding = DRAW_BINDING_DYNUBO_BASE;
bindings[4].descriptorCount = 1;
bindings[4].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
Expand Down
10 changes: 8 additions & 2 deletions GPU/Vulkan/GPU_Vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "Common/GraphicsContext.h"
#include "Common/Serialize/Serializer.h"
#include "Common/TimeUtil.h"
#include "Common/Thread/ThreadUtil.h"

#include "Core/Config.h"
#include "Core/Debugger/Breakpoints.h"
Expand Down Expand Up @@ -94,11 +95,12 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
shaderCachePath_ = GetSysDirectory(DIRECTORY_APP_CACHE) / (discID + ".vkshadercache");
shaderCacheLoaded_ = false;

std::thread th([&] {
shaderCacheLoadThread_ = std::thread([&] {
SetCurrentThreadName("VulkanLoadCache");
AndroidJNIThreadContext ctx;
LoadCache(shaderCachePath_);
shaderCacheLoaded_ = true;
});
th.detach();
} else {
shaderCacheLoaded_ = true;
}
Expand Down Expand Up @@ -180,6 +182,10 @@ void GPU_Vulkan::SaveCache(const Path &filename) {
}

GPU_Vulkan::~GPU_Vulkan() {
if (shaderCacheLoadThread_.joinable()) {
shaderCacheLoadThread_.join();
}

if (draw_) {
VulkanRenderManager *rm = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
rm->DrainAndBlockCompileQueue();
Expand Down
3 changes: 3 additions & 0 deletions GPU/Vulkan/GPU_Vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <string>
#include <vector>
#include <thread>

#include "Common/File/Path.h"

Expand Down Expand Up @@ -84,4 +85,6 @@ class GPU_Vulkan : public GPUCommonHW {

Path shaderCachePath_;
std::atomic<bool> shaderCacheLoaded_{};

std::thread shaderCacheLoadThread_;
};
70 changes: 35 additions & 35 deletions GPU/Vulkan/ShaderManagerVulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ void ShaderManagerVulkan::DeviceRestore(Draw::DrawContext *draw) {
}

void ShaderManagerVulkan::Clear() {
std::lock_guard<std::mutex> guard(cacheLock_);

fsCache_.Iterate([&](const FShaderID &key, VulkanFragmentShader *shader) {
delete shader;
});
Expand Down Expand Up @@ -333,6 +335,8 @@ void ShaderManagerVulkan::GetShaders(int prim, VertexDecoder *decoder, VulkanVer
return;
}

std::lock_guard<std::mutex> guard(cacheLock_);

VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
VulkanVertexShader *vs = nullptr;
if (!vsCache_.Get(VSID, &vs)) {
Expand All @@ -345,14 +349,12 @@ void ShaderManagerVulkan::GetShaders(int prim, VertexDecoder *decoder, VulkanVer
_assert_msg_(success, "VS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));

std::lock_guard<std::mutex> guard(cacheLock_);
if (!vsCache_.Get(VSID, &vs)) {
vs = new VulkanVertexShader(vulkan, VSID, flags, codeBuffer_, useHWTransform);
vsCache_.Insert(VSID, vs);
}
// Don't need to re-lookup anymore, now that we lock wider.
vs = new VulkanVertexShader(vulkan, VSID, flags, codeBuffer_, useHWTransform);
vsCache_.Insert(VSID, vs);
}

VulkanFragmentShader *fs;
VulkanFragmentShader *fs = nullptr;
if (!fsCache_.Get(FSID, &fs)) {
// Fragment shader not in cache. Let's compile it.
std::string genErrorString;
Expand All @@ -362,14 +364,11 @@ void ShaderManagerVulkan::GetShaders(int prim, VertexDecoder *decoder, VulkanVer
_assert_msg_(success, "FS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));

std::lock_guard<std::mutex> guard(cacheLock_);
if (!fsCache_.Get(FSID, &fs)) {
fs = new VulkanFragmentShader(vulkan, FSID, flags, codeBuffer_);
fsCache_.Insert(FSID, fs);
}
fs = new VulkanFragmentShader(vulkan, FSID, flags, codeBuffer_);
fsCache_.Insert(FSID, fs);
}

VulkanGeometryShader *gs;
VulkanGeometryShader *gs = nullptr;
if (GSID.Bit(GS_BIT_ENABLED)) {
if (!gsCache_.Get(GSID, &gs)) {
// Geometry shader not in cache. Let's compile it.
Expand All @@ -378,11 +377,8 @@ void ShaderManagerVulkan::GetShaders(int prim, VertexDecoder *decoder, VulkanVer
_assert_msg_(success, "GS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_));

std::lock_guard<std::mutex> guard(cacheLock_);
if (!gsCache_.Get(GSID, &gs)) {
gs = new VulkanGeometryShader(vulkan, GSID, codeBuffer_);
gsCache_.Insert(GSID, gs);
}
gs = new VulkanGeometryShader(vulkan, GSID, codeBuffer_);
gsCache_.Insert(GSID, gs);
}
} else {
gs = nullptr;
Expand All @@ -403,6 +399,7 @@ void ShaderManagerVulkan::GetShaders(int prim, VertexDecoder *decoder, VulkanVer
}

std::vector<std::string> ShaderManagerVulkan::DebugGetShaderIDs(DebugShaderType type) {
std::lock_guard<std::mutex> guard(cacheLock_);
std::vector<std::string> ids;
switch (type) {
case SHADER_TYPE_VERTEX:
Expand Down Expand Up @@ -621,24 +618,27 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
}
}

for (int i = 0; i < header.numGeometryShaders; i++) {
GShaderID id;
if (fread(&id, sizeof(id), 1, f) != 1) {
ERROR_LOG(G3D, "Vulkan shader cache truncated (in GeometryShaders)");
return false;
}
std::string genErrorString;
if (!GenerateGeometryShader(id, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString)) {
ERROR_LOG(G3D, "Failed to generate geometry shader during cache load");
// We just ignore this one and carry on.
failCount++;
continue;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_));
std::lock_guard<std::mutex> guard(cacheLock_);
if (!gsCache_.ContainsKey(id)) {
VulkanGeometryShader *gs = new VulkanGeometryShader(vulkan, id, codeBuffer_);
gsCache_.Insert(id, gs);
// If it's not enabled, don't create shaders cached from earlier runs - creation will likely fail.
if (gstate_c.Use(GPU_USE_GS_CULLING)) {
for (int i = 0; i < header.numGeometryShaders; i++) {
GShaderID id;
if (fread(&id, sizeof(id), 1, f) != 1) {
ERROR_LOG(G3D, "Vulkan shader cache truncated (in GeometryShaders)");
return false;
}
std::string genErrorString;
if (!GenerateGeometryShader(id, codeBuffer_, compat_, draw_->GetBugs(), &genErrorString)) {
ERROR_LOG(G3D, "Failed to generate geometry shader during cache load");
// We just ignore this one and carry on.
failCount++;
continue;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "GS length error: %d", (int)strlen(codeBuffer_));
std::lock_guard<std::mutex> guard(cacheLock_);
if (!gsCache_.ContainsKey(id)) {
VulkanGeometryShader *gs = new VulkanGeometryShader(vulkan, id, codeBuffer_);
gsCache_.Insert(id, gs);
}
}
}

Expand Down
7 changes: 4 additions & 3 deletions GPU/Vulkan/ShaderManagerVulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,10 @@ class ShaderManagerVulkan : public ShaderManagerCommon {
int GetNumGeometryShaders() const { return (int)gsCache_.size(); }

// Used for saving/loading the cache. Don't need to be particularly fast.
VulkanVertexShader *GetVertexShaderFromID(VShaderID id) { return vsCache_.GetOrNull(id); }
VulkanFragmentShader *GetFragmentShaderFromID(FShaderID id) { return fsCache_.GetOrNull(id); }
VulkanGeometryShader *GetGeometryShaderFromID(GShaderID id) { return gsCache_.GetOrNull(id); }
VulkanVertexShader *GetVertexShaderFromID(VShaderID id) { std::lock_guard<std::mutex> guard(cacheLock_); return vsCache_.GetOrNull(id); }
VulkanFragmentShader *GetFragmentShaderFromID(FShaderID id) { std::lock_guard<std::mutex> guard(cacheLock_); return fsCache_.GetOrNull(id); }
VulkanGeometryShader *GetGeometryShaderFromID(GShaderID id) { std::lock_guard<std::mutex> guard(cacheLock_); return gsCache_.GetOrNull(id); }

VulkanVertexShader *GetVertexShaderFromModule(VkShaderModule module);
VulkanFragmentShader *GetFragmentShaderFromModule(VkShaderModule module);
VulkanGeometryShader *GetGeometryShaderFromModule(VkShaderModule module);
Expand Down