diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index fee97a90b6..64440db92f 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -283,6 +283,10 @@ protected: bool everUsedEqualDepth_ = false; bool everUsedExactEqualDepth_ = false; + // The draw context's invalidation callback is installed from BeginFrame, on the emu thread. The draw + // engine is created on the loader thread, while the UI thread may already be rendering and calling it. + bool invalidationCallbackInstalled_ = false; + // Vertex collector buffers u8 *decoded_ = nullptr; u16 *decIndex_ = nullptr; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 02c4a98958..576a803513 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -83,13 +83,12 @@ DrawEngineD3D11::~DrawEngineD3D11() { void DrawEngineD3D11::InitDeviceObjects() { pushVerts_ = new PushBufferD3D11(device_, VERTEX_PUSH_SIZE, D3D11_BIND_VERTEX_BUFFER); pushInds_ = new PushBufferD3D11(device_, INDEX_PUSH_SIZE, D3D11_BIND_INDEX_BUFFER); - - draw_->SetInvalidationCallback(std::bind(&DrawEngineD3D11::Invalidate, this, std::placeholders::_1)); } void DrawEngineD3D11::DestroyDeviceObjects() { if (draw_) { draw_->SetInvalidationCallback(InvalidationCallback()); + invalidationCallbackInstalled_ = false; } ClearInputLayoutMap(); @@ -251,6 +250,10 @@ HRESULT DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshader, const De void DrawEngineD3D11::BeginFrame() { DrawEngineCommon::BeginFrame(); + if (!invalidationCallbackInstalled_) { + draw_->SetInvalidationCallback(std::bind(&DrawEngineD3D11::Invalidate, this, std::placeholders::_1)); + invalidationCallbackInstalled_ = true; + } pushVerts_->Reset(); pushInds_->Reset(); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 4111aa2bd4..d63d6cf9e9 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -91,7 +91,6 @@ void DrawEngineGLES::InitDeviceObjects() { entries.push_back({ ATTR_NORMAL, 1, GL_FLOAT, GL_FALSE, offsetof(TransformedVertex, fog) }); softwareInputLayout_ = render_->CreateInputLayout(entries, stride); - draw_->SetInvalidationCallback(std::bind(&DrawEngineGLES::Invalidate, this, std::placeholders::_1)); } void DrawEngineGLES::DestroyDeviceObjects() { @@ -99,6 +98,7 @@ void DrawEngineGLES::DestroyDeviceObjects() { return; } draw_->SetInvalidationCallback(InvalidationCallback()); + invalidationCallbackInstalled_ = false; // Beware: this could be called twice in a row, sometimes. for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) { @@ -129,6 +129,10 @@ void DrawEngineGLES::ClearInputLayoutMap() { void DrawEngineGLES::BeginFrame() { DrawEngineCommon::BeginFrame(); + if (!invalidationCallbackInstalled_) { + draw_->SetInvalidationCallback(std::bind(&DrawEngineGLES::Invalidate, this, std::placeholders::_1)); + invalidationCallbackInstalled_ = true; + } FrameData &frameData = frameData_[render_->GetCurFrame()]; frameData.pushIndex->Begin(); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 17dc21a94f..4851e4aed8 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -89,7 +89,6 @@ void DrawEngineVulkan::InitDeviceObjects() { res = vkCreateSampler(device, &samp, nullptr, &nullSampler_); _dbg_assert_(VK_SUCCESS == res); - draw_->SetInvalidationCallback(std::bind(&DrawEngineVulkan::Invalidate, this, std::placeholders::_1)); } DrawEngineVulkan::~DrawEngineVulkan() { @@ -106,6 +105,7 @@ void DrawEngineVulkan::DestroyDeviceObjects() { VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); draw_->SetInvalidationCallback(InvalidationCallback()); + invalidationCallbackInstalled_ = false; pushUBO_ = nullptr; @@ -143,6 +143,10 @@ void DrawEngineVulkan::DeviceRestore(Draw::DrawContext *draw) { void DrawEngineVulkan::BeginFrame() { DrawEngineCommon::BeginFrame(); + if (!invalidationCallbackInstalled_) { + draw_->SetInvalidationCallback(std::bind(&DrawEngineVulkan::Invalidate, this, std::placeholders::_1)); + invalidationCallbackInstalled_ = true; + } lastPipeline_ = nullptr;