Execute scene slices on worker threads

This commit is contained in:
Magnus Norddahl 2017-02-04 16:45:36 +01:00
parent d9e545a519
commit 8ad132b64f
3 changed files with 93 additions and 10 deletions

View file

@ -23,6 +23,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <thread>
class DrawerCommandQueue; class DrawerCommandQueue;
typedef std::shared_ptr<DrawerCommandQueue> DrawerCommandQueuePtr; typedef std::shared_ptr<DrawerCommandQueue> DrawerCommandQueuePtr;
@ -67,6 +68,8 @@ namespace swrenderer
std::unique_ptr<RenderClipSegment> ClipSegments; std::unique_ptr<RenderClipSegment> ClipSegments;
DrawerCommandQueuePtr DrawQueue; DrawerCommandQueuePtr DrawQueue;
std::thread thread;
// VisibleSprite working buffers // VisibleSprite working buffers
short clipbot[MAXWIDTH]; short clipbot[MAXWIDTH];
short cliptop[MAXWIDTH]; short cliptop[MAXWIDTH];

View file

@ -63,6 +63,11 @@ namespace swrenderer
Threads.push_back(std::make_unique<RenderThread>(this)); Threads.push_back(std::make_unique<RenderThread>(this));
} }
RenderScene::~RenderScene()
{
StopThreads();
}
void RenderScene::SetClearColor(int color) void RenderScene::SetClearColor(int color)
{ {
clearcolor = color; clearcolor = color;
@ -161,26 +166,38 @@ namespace swrenderer
void RenderScene::RenderThreadSlices() void RenderScene::RenderThreadSlices()
{ {
int numThreads = r_scene_multithreaded ? 8 : 1; int numThreads = r_scene_multithreaded ? 8 : 1;
if (numThreads != Threads.size())
while (Threads.size() > (size_t)numThreads)
{ {
Threads.pop_back(); StopThreads();
} StartThreads(numThreads);
while (Threads.size() < (size_t)numThreads)
{
Threads.push_back(std::make_unique<RenderThread>(this));
} }
// Setup threads:
std::unique_lock<std::mutex> start_lock(start_mutex);
for (int i = 0; i < numThreads; i++) for (int i = 0; i < numThreads; i++)
{ {
Threads[i]->X1 = viewwidth * i / numThreads; Threads[i]->X1 = viewwidth * i / numThreads;
Threads[i]->X2 = viewwidth * (i + 1) / numThreads; Threads[i]->X2 = viewwidth * (i + 1) / numThreads;
} }
run_id++;
start_lock.unlock();
for (int i = 0; i < numThreads; i++) // Notify threads to run
if (Threads.size() > 1)
{ {
RenderThreadSlice(Threads[i].get()); start_condition.notify_all();
}
// Do the main thread ourselves:
RenderThreadSlice(MainThread());
// Wait for everyone to finish:
if (Threads.size() > 1)
{
std::unique_lock<std::mutex> end_lock(end_mutex);
finished_threads++;
end_condition.wait(end_lock, [&]() { return finished_threads == Threads.size(); });
finished_threads = 0;
} }
} }
@ -246,6 +263,54 @@ namespace swrenderer
} }
} }
void RenderScene::StartThreads(size_t numThreads)
{
while (Threads.size() < (size_t)numThreads)
{
auto thread = std::make_unique<RenderThread>(this);
auto renderthread = thread.get();
int start_run_id = run_id;
thread->thread = std::thread([=]()
{
int last_run_id = start_run_id;
while (true)
{
// Wait until we are signalled to run:
std::unique_lock<std::mutex> start_lock(start_mutex);
start_condition.wait(start_lock, [&]() { return run_id != last_run_id || shutdown_flag; });
if (shutdown_flag)
break;
last_run_id = run_id;
start_lock.unlock();
RenderThreadSlice(renderthread);
// Notify main thread that we finished:
std::unique_lock<std::mutex> end_lock(end_mutex);
finished_threads++;
end_lock.unlock();
end_condition.notify_all();
}
});
Threads.push_back(std::move(thread));
}
}
void RenderScene::StopThreads()
{
std::unique_lock<std::mutex> lock(start_mutex);
shutdown_flag = true;
lock.unlock();
start_condition.notify_all();
while (Threads.size() > 1)
{
Threads.back()->thread.join();
Threads.pop_back();
}
lock.lock();
shutdown_flag = false;
}
void RenderScene::RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines) void RenderScene::RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines)
{ {
auto viewport = RenderViewport::Instance(); auto viewport = RenderViewport::Instance();

View file

@ -14,7 +14,11 @@
#pragma once #pragma once
#include <stddef.h> #include <stddef.h>
#include <vector>
#include <memory> #include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include "r_defs.h" #include "r_defs.h"
#include "d_player.h" #include "d_player.h"
@ -30,6 +34,7 @@ namespace swrenderer
{ {
public: public:
RenderScene(); RenderScene();
~RenderScene();
void Init(); void Init();
void ScreenResized(); void ScreenResized();
@ -50,9 +55,19 @@ namespace swrenderer
void RenderThreadSlices(); void RenderThreadSlices();
void RenderThreadSlice(RenderThread *thread); void RenderThreadSlice(RenderThread *thread);
void StartThreads(size_t numThreads);
void StopThreads();
bool dontmaplines = false; bool dontmaplines = false;
int clearcolor = 0; int clearcolor = 0;
std::vector<std::unique_ptr<RenderThread>> Threads; std::vector<std::unique_ptr<RenderThread>> Threads;
std::mutex start_mutex;
std::condition_variable start_condition;
bool shutdown_flag = false;
int run_id = 0;
std::mutex end_mutex;
std::condition_variable end_condition;
size_t finished_threads = 0;
}; };
} }