Make sure we never copy GLRRenderThreadTask objects

This commit is contained in:
Henrik Rydgård 2023-05-16 23:14:54 +02:00
parent c30895b6b4
commit 78eaa8c235
2 changed files with 24 additions and 21 deletions

View File

@ -129,7 +129,7 @@ bool GLRenderManager::ThreadFrame() {
return false;
}
GLRRenderThreadTask task;
GLRRenderThreadTask *task = nullptr;
// In case of syncs or other partial completion, we keep going until we complete a frame.
while (true) {
@ -147,7 +147,7 @@ bool GLRenderManager::ThreadFrame() {
// We got a task! We can now have pushMutex_ unlocked, allowing the host to
// push more work when it feels like it, and just start working.
if (task.runType == GLRRunType::EXIT) {
if (task->runType == GLRRunType::EXIT) {
// Oh, host wanted out. Let's leave, and also let's notify the host.
// This is unlike Vulkan too which can just block on the thread existing.
std::unique_lock<std::mutex> lock(syncMutex_);
@ -157,11 +157,13 @@ bool GLRenderManager::ThreadFrame() {
}
// Render the scene.
VLOG(" PULL: Frame %d RUN (%0.3f)", task.frame, time_now_d());
if (Run(task)) {
VLOG(" PULL: Frame %d RUN (%0.3f)", task->frame, time_now_d());
if (Run(*task)) {
// Swap requested, so we just bail the loop.
delete task;
break;
}
delete task;
};
return true;
@ -174,9 +176,7 @@ void GLRenderManager::StopThread() {
run_ = false;
std::unique_lock<std::mutex> lock(pushMutex_);
GLRRenderThreadTask exitTask{};
exitTask.runType = GLRRunType::EXIT;
renderThreadQueue_.push(exitTask);
renderThreadQueue_.push(new GLRRenderThreadTask(GLRRunType::EXIT));
pushCondVar_.notify_one();
} else {
WARN_LOG(G3D, "GL submission thread was already paused.");
@ -377,15 +377,14 @@ void GLRenderManager::Finish() {
frameData_[curFrame].deleter.Take(deleter_);
VLOG("PUSH: Finish, pushing task. curFrame = %d", curFrame);
GLRRenderThreadTask task;
task.frame = curFrame;
task.runType = GLRRunType::PRESENT;
GLRRenderThreadTask *task = new GLRRenderThreadTask(GLRRunType::PRESENT);
task->frame = curFrame;
{
std::unique_lock<std::mutex> lock(pushMutex_);
renderThreadQueue_.push(task);
renderThreadQueue_.back().initSteps = std::move(initSteps_);
renderThreadQueue_.back().steps = std::move(steps_);
renderThreadQueue_.back()->initSteps = std::move(initSteps_);
renderThreadQueue_.back()->steps = std::move(steps_);
initSteps_.clear();
steps_.clear();
pushCondVar_.notify_one();
@ -507,14 +506,13 @@ void GLRenderManager::FlushSync() {
{
VLOG("PUSH: Frame[%d].readyForRun = true (sync)", curFrame_);
GLRRenderThreadTask task;
task.frame = curFrame_;
task.runType = GLRRunType::SYNC;
GLRRenderThreadTask *task = new GLRRenderThreadTask(GLRRunType::SYNC);
task->frame = curFrame_;
std::unique_lock<std::mutex> lock(pushMutex_);
renderThreadQueue_.push(task);
renderThreadQueue_.back().initSteps = std::move(initSteps_);
renderThreadQueue_.back().steps = std::move(steps_);
renderThreadQueue_.back()->initSteps = std::move(initSteps_);
renderThreadQueue_.back()->steps = std::move(steps_);
pushCondVar_.notify_one();
steps_.clear();
}

View File

@ -203,14 +203,19 @@ enum class GLRRunType {
class GLRenderManager;
class GLPushBuffer;
// These are enqueued from the main thread,
// and the render thread pops them off
// These are enqueued from the main thread, and the render thread pops them off
struct GLRRenderThreadTask {
GLRRenderThreadTask(GLRRunType _runType) : runType(_runType) {}
std::vector<GLRStep *> steps;
std::vector<GLRInitStep> initSteps;
int frame;
int frame = -1;
GLRRunType runType;
// Avoid copying these by accident.
GLRRenderThreadTask(GLRRenderThreadTask &) = delete;
GLRRenderThreadTask& operator =(GLRRenderThreadTask &) = delete;
};
// Note: The GLRenderManager is created and destroyed on the render thread, and the latter
@ -866,7 +871,7 @@ private:
std::mutex pushMutex_;
std::condition_variable pushCondVar_;
std::queue<GLRRenderThreadTask> renderThreadQueue_;
std::queue<GLRRenderThreadTask *> renderThreadQueue_;
// For readbacks and other reasons we need to sync with the render thread.
std::mutex syncMutex_;