From 0adb152913003e04bc0f687cb0a8ab79bc15d13e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 17 May 2023 22:39:22 +0200 Subject: [PATCH] Create a RenderState object for each thread --- src/common/rendering/v_video.h | 4 +- .../vulkan/commands/vk_commandbuffer.cpp | 2 +- .../rendering/vulkan/vk_postprocess.cpp | 13 +++-- .../rendering/vulkan/vk_pprenderstate.cpp | 2 +- .../rendering/vulkan/vk_renderdevice.cpp | 49 ++++++++++++++----- src/common/rendering/vulkan/vk_renderdevice.h | 7 ++- src/maploader/maploader.cpp | 2 +- src/rendering/hwrenderer/hw_entrypoint.cpp | 10 ++-- src/rendering/hwrenderer/hw_precache.cpp | 2 +- src/rendering/hwrenderer/scene/hw_bsp.cpp | 2 +- 10 files changed, 62 insertions(+), 31 deletions(-) diff --git a/src/common/rendering/v_video.h b/src/common/rendering/v_video.h index 743090aca3..df12a82a3c 100644 --- a/src/common/rendering/v_video.h +++ b/src/common/rendering/v_video.h @@ -214,7 +214,7 @@ public: virtual void BeginFrame() {} virtual void SetWindowSize(int w, int h) {} virtual void StartPrecaching() {} - virtual FRenderState* RenderState() { return nullptr; } + virtual FRenderState* RenderState(int threadIndex) { return nullptr; } virtual int GetClientWidth() = 0; virtual int GetClientHeight() = 0; @@ -277,6 +277,8 @@ public: uint64_t FrameTime = 0; uint64_t FrameTimeNS = 0; + int MaxThreads = 8; // To do: this may need to be limited by how much memory is available for dedicated buffer mapping (i.e. is resizeable bar available or not) + private: uint64_t fpsLimitTime = 0; diff --git a/src/common/rendering/vulkan/commands/vk_commandbuffer.cpp b/src/common/rendering/vulkan/commands/vk_commandbuffer.cpp index bcb3aed831..5fc5275705 100644 --- a/src/common/rendering/vulkan/commands/vk_commandbuffer.cpp +++ b/src/common/rendering/vulkan/commands/vk_commandbuffer.cpp @@ -151,7 +151,7 @@ void VkCommandBufferManager::FlushCommands(VulkanCommandBuffer** commands, size_ void VkCommandBufferManager::FlushCommands(bool finish, bool lastsubmit, bool uploadOnly) { if (!uploadOnly) - fb->GetRenderState()->EndRenderPass(); + fb->GetRenderState(0)->EndRenderPass(); std::unique_lock lock(mMutex); diff --git a/src/common/rendering/vulkan/vk_postprocess.cpp b/src/common/rendering/vulkan/vk_postprocess.cpp index fb858058d2..41b80239f1 100644 --- a/src/common/rendering/vulkan/vk_postprocess.cpp +++ b/src/common/rendering/vulkan/vk_postprocess.cpp @@ -61,11 +61,16 @@ void VkPostprocess::SetActiveRenderTarget() .AddImage(&buffers->PipelineDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false) .Execute(fb->GetCommands()->GetDrawCommands()); - fb->GetRenderState()->SetRenderTarget(&buffers->PipelineImage[mCurrentPipelineImage], buffers->PipelineDepthStencil.View.get(), buffers->GetWidth(), buffers->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, VK_SAMPLE_COUNT_1_BIT); + for (int i = 0; i < fb->MaxThreads; i++) + fb->GetRenderState(i)->SetRenderTarget(&buffers->PipelineImage[mCurrentPipelineImage], buffers->PipelineDepthStencil.View.get(), buffers->GetWidth(), buffers->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, VK_SAMPLE_COUNT_1_BIT); } void VkPostprocess::PostProcessScene(int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) { + for (int i = 0; i < fb->MaxThreads; i++) + fb->GetRenderState(i)->EndRenderPass(); + fb->GetCommands()->FlushCommands(false); + int sceneWidth = fb->GetBuffers()->GetSceneWidth(); int sceneHeight = fb->GetBuffers()->GetSceneHeight(); @@ -79,7 +84,8 @@ void VkPostprocess::PostProcessScene(int fixedcm, float flash, const std::functi void VkPostprocess::BlitSceneToPostprocess() { - fb->GetRenderState()->EndRenderPass(); + for (int i = 0; i < fb->MaxThreads; i++) + fb->GetRenderState(i)->EndRenderPass(); auto buffers = fb->GetBuffers(); auto cmdbuffer = fb->GetCommands()->GetDrawCommands(); @@ -148,7 +154,8 @@ void VkPostprocess::ImageTransitionScene(bool undefinedSrcLayout) void VkPostprocess::BlitCurrentToImage(VkTextureImage *dstimage, VkImageLayout finallayout) { - fb->GetRenderState()->EndRenderPass(); + for (int i = 0; i < fb->MaxThreads; i++) + fb->GetRenderState(i)->EndRenderPass(); auto srcimage = &fb->GetBuffers()->PipelineImage[mCurrentPipelineImage]; auto cmdbuffer = fb->GetCommands()->GetDrawCommands(); diff --git a/src/common/rendering/vulkan/vk_pprenderstate.cpp b/src/common/rendering/vulkan/vk_pprenderstate.cpp index ff32135894..231cb5e551 100644 --- a/src/common/rendering/vulkan/vk_pprenderstate.cpp +++ b/src/common/rendering/vulkan/vk_pprenderstate.cpp @@ -53,7 +53,7 @@ void VkPPRenderState::PopGroup() void VkPPRenderState::Draw() { - fb->GetRenderState()->EndRenderPass(); + fb->GetRenderState(0)->EndRenderPass(); VkPPRenderPassKey key; key.BlendMode = BlendMode; diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index d1fe909bb2..282840c564 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -190,11 +190,15 @@ void VulkanRenderDevice::InitializeState() mShaderManager.reset(new VkShaderManager(this)); mDescriptorSetManager->Init(); + + for (int threadIndex = 0; threadIndex < MaxThreads; threadIndex++) + { #ifdef __APPLE__ - mRenderState.reset(new VkRenderStateMolten(this)); + mRenderState.push_back(std::make_unique(this)); #else - mRenderState.reset(new VkRenderState(this, 0)); + mRenderState.push_back(std::make_unique(this, 0)); #endif + } } void VulkanRenderDevice::Update() @@ -209,8 +213,11 @@ void VulkanRenderDevice::Update() Draw2D(); twod->Clear(); - mRenderState->EndRenderPass(); - mRenderState->EndFrame(); + for (auto& renderstate : mRenderState) + { + renderstate->EndRenderPass(); + renderstate->EndFrame(); + } Flush3D.Unclock(); @@ -232,13 +239,19 @@ void VulkanRenderDevice::RenderTextureView(FCanvasTexture* tex, std::functionGetImage(tex, 0, 0); VkTextureImage *depthStencil = BaseLayer->GetDepthStencil(tex); - mRenderState->EndRenderPass(); + for (auto& renderstate : mRenderState) + { + renderstate->EndRenderPass(); + } VkImageTransition() .AddImage(image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, false) .Execute(mCommands->GetDrawCommands()); - mRenderState->SetRenderTarget(image, depthStencil->View.get(), image->Image->width, image->Image->height, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT); + for (auto& renderstate : mRenderState) + { + renderstate->SetRenderTarget(image, depthStencil->View.get(), image->Image->width, image->Image->height, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT); + } IntRect bounds; bounds.left = bounds.top = 0; @@ -247,13 +260,19 @@ void VulkanRenderDevice::RenderTextureView(FCanvasTexture* tex, std::functionEndRenderPass(); + for (auto& renderstate : mRenderState) + { + renderstate->EndRenderPass(); + } VkImageTransition() .AddImage(image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false) .Execute(mCommands->GetDrawCommands()); - mRenderState->SetRenderTarget(&GetBuffers()->SceneColor, GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples()); + for (auto& renderstate : mRenderState) + { + renderstate->SetRenderTarget(&GetBuffers()->SceneColor, GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples()); + } tex->SetUpdated(true); } @@ -450,7 +469,8 @@ void VulkanRenderDevice::BeginFrame() mTextureManager->BeginFrame(); mScreenBuffers->BeginFrame(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height); mSaveBuffers->BeginFrame(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT); - mRenderState->BeginFrame(); + for (auto& renderstate : mRenderState) + renderstate->BeginFrame(); mDescriptorSetManager->BeginFrame(); } @@ -465,7 +485,7 @@ void VulkanRenderDevice::InitLightmap(int LMTextureSize, int LMTextureCount, TAr void VulkanRenderDevice::Draw2D() { - ::Draw2D(twod, *mRenderState); + ::Draw2D(twod, *RenderState(0)); } void VulkanRenderDevice::WaitForCommands(bool finish) @@ -546,9 +566,9 @@ void VulkanRenderDevice::ImageTransitionScene(bool unknown) mPostprocess->ImageTransitionScene(unknown); } -FRenderState* VulkanRenderDevice::RenderState() +FRenderState* VulkanRenderDevice::RenderState(int threadIndex) { - return mRenderState.get(); + return mRenderState[threadIndex].get(); } void VulkanRenderDevice::AmbientOccludeScene(float m5) @@ -558,5 +578,8 @@ void VulkanRenderDevice::AmbientOccludeScene(float m5) void VulkanRenderDevice::SetSceneRenderTarget(bool useSSAO) { - mRenderState->SetRenderTarget(&GetBuffers()->SceneColor, GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples()); + for (auto& renderstate : mRenderState) + { + renderstate->SetRenderTarget(&GetBuffers()->SceneColor, GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples()); + } } diff --git a/src/common/rendering/vulkan/vk_renderdevice.h b/src/common/rendering/vulkan/vk_renderdevice.h index 699b2e82a0..1701cb3710 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.h +++ b/src/common/rendering/vulkan/vk_renderdevice.h @@ -38,10 +38,10 @@ public: VkDescriptorSetManager* GetDescriptorSetManager() { return mDescriptorSetManager.get(); } VkRenderPassManager *GetRenderPassManager() { return mRenderPassManager.get(); } VkRaytrace* GetRaytrace() { return mRaytrace.get(); } - VkRenderState *GetRenderState() { return mRenderState.get(); } + VkRenderState *GetRenderState(int threadIndex) { return mRenderState[threadIndex].get(); } VkPostprocess *GetPostprocess() { return mPostprocess.get(); } VkRenderBuffers *GetBuffers() { return mActiveRenderBuffers; } - FRenderState* RenderState() override; + FRenderState* RenderState(int threadIndex) override; bool IsVulkan() override { return true; } @@ -85,7 +85,6 @@ public: void WaitForCommands(bool finish) override; - int MaxThreads = 8; // To do: this may need to be limited by how much memory is available for dedicated buffer mapping (i.e. is resizeable bar available or not) std::mutex ThreadMutex; private: @@ -106,7 +105,7 @@ private: std::unique_ptr mDescriptorSetManager; std::unique_ptr mRenderPassManager; std::unique_ptr mRaytrace; - std::unique_ptr mRenderState; + std::vector> mRenderState; VkRenderBuffers *mActiveRenderBuffers = nullptr; diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index 75ccd056f5..f07e2be442 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -3243,7 +3243,7 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position) InitRenderInfo(); // create hardware independent renderer resources for the level. This must be done BEFORE the PolyObj Spawn!!! Level->ClearDynamic3DFloorData(); // CreateVBO must be run on the plain 3D floor data. - CreateVBO(*screen->RenderState(), Level->sectors); + CreateVBO(*screen->RenderState(0), Level->sectors); meshcache.Clear(); screen->InitLightmap(Level->LMTextureSize, Level->LMTextureCount, Level->LMTextureData); diff --git a/src/rendering/hwrenderer/hw_entrypoint.cpp b/src/rendering/hwrenderer/hw_entrypoint.cpp index 47e7286c1b..40a52b7318 100644 --- a/src/rendering/hwrenderer/hw_entrypoint.cpp +++ b/src/rendering/hwrenderer/hw_entrypoint.cpp @@ -104,7 +104,7 @@ void CollectLights(FLevelLocals* Level) sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen) { - auto& RenderState = *screen->RenderState(); + auto& RenderState = *screen->RenderState(0); R_SetupFrame(mainvp, r_viewwindow, camera); @@ -168,7 +168,7 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees()); di->SetupView(RenderState, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false); - di->ProcessScene(toscreen, *screen->RenderState()); + di->ProcessScene(toscreen, *screen->RenderState(0)); if (mainview) { @@ -264,7 +264,7 @@ void WriteSavePic(player_t* player, FileWriter* file, int width, int height) bounds.top = 0; bounds.width = width; bounds.height = height; - auto& RenderState = *screen->RenderState(); + auto& RenderState = *screen->RenderState(0); // we must be sure the GPU finished reading from the buffer before we fill it with new data. screen->WaitForCommands(false); @@ -312,7 +312,7 @@ static void CheckTimer(FRenderState &state, uint64_t ShaderStartTime) sector_t* RenderView(player_t* player) { - auto RenderState = screen->RenderState(); + auto RenderState = screen->RenderState(0); RenderState->SetFlatVertexBuffer(); RenderState->ResetVertices(); hw_postprocess.SetTonemapMode(level.info ? level.info->tonemap : ETonemapMode::None); @@ -356,7 +356,7 @@ sector_t* RenderView(player_t* player) screen->RenderTextureView(canvas->Tex, [=](IntRect& bounds) { screen->SetViewportRects(&bounds); - Draw2D(&canvas->Drawer, *screen->RenderState(), 0, 0, canvas->Tex->GetWidth(), canvas->Tex->GetHeight()); + Draw2D(&canvas->Drawer, *screen->RenderState(0), 0, 0, canvas->Tex->GetWidth(), canvas->Tex->GetHeight()); canvas->Drawer.Clear(); }); canvas->Tex->SetUpdated(true); diff --git a/src/rendering/hwrenderer/hw_precache.cpp b/src/rendering/hwrenderer/hw_precache.cpp index 7ea1ecb388..b58c292d77 100644 --- a/src/rendering/hwrenderer/hw_precache.cpp +++ b/src/rendering/hwrenderer/hw_precache.cpp @@ -316,7 +316,7 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitl FImageSource::EndPrecaching(); // cache all used models - FModelRenderer* renderer = new FHWModelRenderer(nullptr, *screen->RenderState(), -1); + FModelRenderer* renderer = new FHWModelRenderer(nullptr, *screen->RenderState(0), -1); for (unsigned i = 0; i < Models.Size(); i++) { if (modellist[i]) diff --git a/src/rendering/hwrenderer/scene/hw_bsp.cpp b/src/rendering/hwrenderer/scene/hw_bsp.cpp index 9665127023..684bed8516 100644 --- a/src/rendering/hwrenderer/scene/hw_bsp.cpp +++ b/src/rendering/hwrenderer/scene/hw_bsp.cpp @@ -106,7 +106,7 @@ void HWDrawInfo::WorkerThread() { sector_t *front, *back; - FRenderState& state = *screen->RenderState(); + FRenderState& state = *screen->RenderState(0); WTTotal.Clock(); isWorkerThread = true; // for adding asserts in GL API code. The worker thread may never call any GL API.