mirror of
https://github.com/ZDoom/ZDRay.git
synced 2025-02-03 13:11:04 +00:00
- fix race condition crash
- rewrote kexWorker to use std::function - added --threads, --samples, --size command line arguments - changed the default threading to be what the processor supports (64 threads on my Threadripper, muhahaha!)
This commit is contained in:
parent
6459b10724
commit
81a70d7c96
6 changed files with 343 additions and 515 deletions
|
@ -22,6 +22,9 @@
|
|||
//#include "rejectbuilder.h"
|
||||
#include <memory>
|
||||
|
||||
extern int LMDims;
|
||||
extern int Samples;
|
||||
|
||||
extern void ShowView (FLevel *level);
|
||||
|
||||
enum
|
||||
|
@ -597,9 +600,9 @@ void FProcessor::BuildNodes()
|
|||
void FProcessor::BuildLightmaps(const char *configFile)
|
||||
{
|
||||
LMBuilder.ambience = 0.0f;
|
||||
LMBuilder.samples = 8;
|
||||
LMBuilder.textureWidth = LIGHTMAP_MAX_SIZE;
|
||||
LMBuilder.textureHeight = LIGHTMAP_MAX_SIZE;
|
||||
LMBuilder.samples = Samples;
|
||||
LMBuilder.textureWidth = LMDims;
|
||||
LMBuilder.textureHeight = LMDims;
|
||||
|
||||
Level.ParseConfigFile(configFile);
|
||||
Level.SetupDlight();
|
||||
|
|
|
@ -42,30 +42,8 @@
|
|||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
kexWorker lightmapWorker;
|
||||
|
||||
const kexVec3 kexLightmapBuilder::gridSize(64, 64, 128);
|
||||
|
||||
//
|
||||
// LightmapWorkerFunc
|
||||
//
|
||||
|
||||
static void LightmapWorkerFunc(void *data, int id)
|
||||
{
|
||||
kexLightmapBuilder *builder = static_cast<kexLightmapBuilder*>(data);
|
||||
builder->LightSurface(id);
|
||||
}
|
||||
|
||||
//
|
||||
// LightGridWorkerFunc
|
||||
//
|
||||
|
||||
static void LightGridWorkerFunc(void *data, int id)
|
||||
{
|
||||
kexLightmapBuilder *builder = static_cast<kexLightmapBuilder*>(data);
|
||||
builder->LightGrid(id);
|
||||
}
|
||||
|
||||
//
|
||||
// kexLightmapBuilder::kexLightmapBuilder
|
||||
//
|
||||
|
@ -536,15 +514,15 @@ void kexLightmapBuilder::TraceSurface(surface_t *surface)
|
|||
int width = surface->lightmapDims[0];
|
||||
int height = surface->lightmapDims[1];
|
||||
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
|
||||
// now that we know the width and height of this block, see if we got
|
||||
// room for it in the light map texture. if not, then we must allocate
|
||||
// a new texture
|
||||
if(!MakeRoomForBlock(width, height, &x, &y, &surface->lightmapNum))
|
||||
{
|
||||
// allocate a new texture for this block
|
||||
lightmapWorker.LockMutex();
|
||||
NewTexture();
|
||||
lightmapWorker.UnlockMutex();
|
||||
|
||||
if(!MakeRoomForBlock(width, height, &x, &y, &surface->lightmapNum))
|
||||
{
|
||||
|
@ -553,6 +531,8 @@ void kexLightmapBuilder::TraceSurface(surface_t *surface)
|
|||
}
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
||||
// calculate texture coordinates
|
||||
for(i = 0; i < surface->numVerts; i++)
|
||||
{
|
||||
|
@ -567,9 +547,9 @@ void kexLightmapBuilder::TraceSurface(surface_t *surface)
|
|||
surface->lightmapOffs[1] = y;
|
||||
}
|
||||
|
||||
lightmapWorker.LockMutex();
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
currentTexture = textures[surface->lightmapNum];
|
||||
lightmapWorker.UnlockMutex();
|
||||
lock.unlock();
|
||||
|
||||
// store results to lightmap texture
|
||||
for(i = 0; i < sampleHeight; i++)
|
||||
|
@ -581,9 +561,9 @@ void kexLightmapBuilder::TraceSurface(surface_t *surface)
|
|||
surface->lightmapOffs[0]) * 3);
|
||||
|
||||
// convert RGB to bytes
|
||||
rgb[0] = (byte)(colorSamples[i][j][0] * 255);
|
||||
rgb[1] = (byte)(colorSamples[i][j][1] * 255);
|
||||
rgb[2] = (byte)(colorSamples[i][j][2] * 255);
|
||||
rgb[0] = (uint32_t)(colorSamples[i][j][0] * 255 + 0.5f);
|
||||
rgb[1] = (uint32_t)(colorSamples[i][j][1] * 255 + 0.5f);
|
||||
rgb[2] = (uint32_t)(colorSamples[i][j][2] * 255 + 0.5f);
|
||||
|
||||
currentTexture[offs + j * 3 + 0] = rgb[0];
|
||||
currentTexture[offs + j * 3 + 1] = rgb[1];
|
||||
|
@ -611,12 +591,12 @@ void kexLightmapBuilder::LightSurface(const int surfid)
|
|||
BuildSurfaceParams(surfaces[surfid]);
|
||||
TraceSurface(surfaces[surfid]);
|
||||
|
||||
lightmapWorker.LockMutex();
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
|
||||
remaining = (float)processed / (float)numsurfs;
|
||||
processed++;
|
||||
|
||||
printf("%i%c surfaces done\r", (int)(remaining * 100.0f), '%');
|
||||
lightmapWorker.UnlockMutex();
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -822,11 +802,11 @@ void kexLightmapBuilder::LightGrid(const int gridid)
|
|||
|
||||
kexMath::Clamp(gridMap[gridid].color, 0, 1);
|
||||
|
||||
lightmapWorker.LockMutex();
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
|
||||
remaining = (float)processed / (float)numLightGrids;
|
||||
|
||||
printf("%i%c cells done\r", (int)(remaining * 100.0f), '%');
|
||||
lightmapWorker.UnlockMutex();
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -841,15 +821,12 @@ void kexLightmapBuilder::CreateLightmaps(FLevel &doomMap)
|
|||
CreateLightGrid();
|
||||
|
||||
printf("------------- Tracing surfaces -------------\n");
|
||||
lightmapWorker.RunThreads(surfaces.Length(), this, LightmapWorkerFunc);
|
||||
|
||||
while(!lightmapWorker.FinishedAllJobs())
|
||||
{
|
||||
Delay(1000);
|
||||
}
|
||||
kexWorker::RunJob(surfaces.Length(), [=](int id) {
|
||||
LightSurface(id);
|
||||
});
|
||||
|
||||
printf("Texels traced: %i \n\n", tracedTexels);
|
||||
lightmapWorker.Destroy();
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -895,12 +872,9 @@ void kexLightmapBuilder::CreateLightGrid()
|
|||
(int)(gridBlock.x * gridBlock.y), hb_static);
|
||||
|
||||
// process all grid cells
|
||||
lightmapWorker.RunThreads(count, this, LightGridWorkerFunc);
|
||||
|
||||
while(!lightmapWorker.FinishedAllJobs())
|
||||
{
|
||||
Delay(1000);
|
||||
}
|
||||
kexWorker::RunJob(count, [=](int id) {
|
||||
LightGrid(id);
|
||||
});
|
||||
|
||||
printf("\nGrid cells: %i\n\n", count);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "surfaces.h"
|
||||
#include <mutex>
|
||||
|
||||
#define LIGHTMAP_MAX_SIZE 1024
|
||||
|
||||
|
@ -87,4 +88,6 @@ private:
|
|||
kexBBox worldGrid;
|
||||
kexBBox gridBound;
|
||||
kexVec3 gridBlock;
|
||||
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
|
|
@ -1,407 +1,36 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Note: this is a modified version of dlight. It is not the original software.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2013-2014 Samuel Villarreal
|
||||
// svkaiser@gmail.com
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// DESCRIPTION: Worker Threads
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "common.h"
|
||||
#include "worker.h"
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
|
||||
int kexWorker::maxWorkThreads = MAX_THREADS;
|
||||
extern int NumThreads;
|
||||
|
||||
//
|
||||
// WorkThread
|
||||
//
|
||||
|
||||
void *WorkThread(void *p)
|
||||
void kexWorker::RunJob(int count, std::function<void(int)> callback)
|
||||
{
|
||||
jobFuncArgs_t *args = (jobFuncArgs_t*)p;
|
||||
kexWorker *worker = args->worker;
|
||||
int numThreads = NumThreads;
|
||||
if (numThreads <= 0)
|
||||
numThreads = std::thread::hardware_concurrency();
|
||||
if (numThreads <= 0)
|
||||
numThreads = 4;
|
||||
|
||||
while(1)
|
||||
numThreads = std::min(numThreads, count);
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
for (int threadIndex = 0; threadIndex < numThreads; threadIndex++)
|
||||
{
|
||||
int jobid;
|
||||
threads.push_back(std::thread([=]() {
|
||||
|
||||
worker->LockMutex();
|
||||
|
||||
if(worker->FinishedAllJobs())
|
||||
int start = threadIndex * count / numThreads;
|
||||
int end = std::min((threadIndex + 1) * count / numThreads, count);
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
worker->UnlockMutex();
|
||||
break;
|
||||
callback(i);
|
||||
}
|
||||
|
||||
jobid = worker->DispatchJob();
|
||||
worker->UnlockMutex();
|
||||
|
||||
worker->RunJob(args->data, jobid);
|
||||
}));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// kexWorker::kexWorker
|
||||
//
|
||||
|
||||
kexWorker::kexWorker()
|
||||
{
|
||||
this->numWorkLoad = 0;
|
||||
this->jobsWorked = 0;
|
||||
this->job = NULL;
|
||||
|
||||
memset(this->jobArgs, 0, sizeof(this->jobArgs));
|
||||
}
|
||||
|
||||
//
|
||||
// kexWorker::~kexWorker
|
||||
//
|
||||
|
||||
kexWorker::~kexWorker()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// kexWorker::LockMutex
|
||||
//
|
||||
|
||||
void kexWorker::LockMutex()
|
||||
{
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
//
|
||||
// kexWorker::UnlockMutex
|
||||
//
|
||||
|
||||
void kexWorker::UnlockMutex()
|
||||
{
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
//
|
||||
// kexWorker::Destroy
|
||||
//
|
||||
|
||||
void kexWorker::Destroy()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// kexWorker::RunThreads
|
||||
//
|
||||
|
||||
void kexWorker::RunThreads(const int count, void *data, jobFunc_t jobFunc)
|
||||
{
|
||||
job = jobFunc;
|
||||
numWorkLoad = count;
|
||||
jobsWorked = 0;
|
||||
|
||||
for(int i = 0; i < kexWorker::maxWorkThreads; ++i)
|
||||
{
|
||||
jobArgs[i].worker = this;
|
||||
jobArgs[i].jobID = i;
|
||||
jobArgs[i].data = data;
|
||||
|
||||
threads[i] = std::thread([=]() { WorkThread(&jobArgs[i]); });
|
||||
}
|
||||
|
||||
for(int i = 0; i < kexWorker::maxWorkThreads; ++i)
|
||||
{
|
||||
for (int i = 0; i < numThreads; i++)
|
||||
threads[i].join();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Stuff from old main.cpp
|
||||
|
||||
void Error(const char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
|
||||
va_start(argptr, error);
|
||||
vprintf(error, argptr);
|
||||
va_end(argptr);
|
||||
printf("\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *Va(const char *str, ...)
|
||||
{
|
||||
va_list v;
|
||||
static char vastr[1024];
|
||||
|
||||
va_start(v, str);
|
||||
vsprintf(vastr, str, v);
|
||||
va_end(v);
|
||||
|
||||
return vastr;
|
||||
}
|
||||
|
||||
void Delay(int ms)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
//
|
||||
// GetSeconds
|
||||
//
|
||||
|
||||
const int64_t GetSeconds()
|
||||
{
|
||||
return time(0);
|
||||
}
|
||||
|
||||
//
|
||||
// Main
|
||||
//
|
||||
|
||||
#if 0
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
kexWadFile wadFile;
|
||||
kexWadFile outWadFile;
|
||||
FLevel doomMap;
|
||||
lump_t *lmLump;
|
||||
kexArray<int> ignoreLumps;
|
||||
kexLightmapBuilder builder;
|
||||
kexStr configFile("strife_sve.cfg");
|
||||
bool bWriteTGA;
|
||||
int map = 1;
|
||||
int arg = 1;
|
||||
|
||||
printf("DLight (c) 2013-2014 Samuel Villarreal\n\n");
|
||||
|
||||
if (argc < 1 || argv[1] == NULL)
|
||||
{
|
||||
printf("Usage: dlight [options] [wadfile]\n");
|
||||
printf("Use -help for list of options\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
basePath = argv[0];
|
||||
basePath.StripFile();
|
||||
|
||||
bWriteTGA = false;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!strcmp(argv[arg], "-help"))
|
||||
{
|
||||
printf("Options:\n");
|
||||
printf("-help: displays all known options\n");
|
||||
printf("-map: process lightmap for MAP##\n");
|
||||
printf("-samples: set texel sampling size (lowest = higher quaility but\n");
|
||||
printf(" slow compile time) must be in powers of two\n");
|
||||
printf("-ambience: set global ambience value for lightmaps (0.0 - 1.0)\n");
|
||||
printf("-size: lightmap texture dimentions for width and height\n");
|
||||
printf(" must be in powers of two (1, 2, 4, 8, 16, etc)\n");
|
||||
printf("-threads: set total number of threads (1 min, 128 max)\n");
|
||||
printf("-config: specify a config file to parse (default: strife_sve.cfg)\n");
|
||||
printf("-writetga: dumps lightmaps to targa (.TGA) files\n");
|
||||
arg++;
|
||||
return 0;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-map"))
|
||||
{
|
||||
if (argv[arg + 1] == NULL)
|
||||
{
|
||||
Error("Specify map number for -map\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
map = atoi(argv[++arg]);
|
||||
arg++;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-samples"))
|
||||
{
|
||||
if (argv[arg + 1] == NULL)
|
||||
{
|
||||
Error("Specify value for -samples\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
builder.samples = atoi(argv[++arg]);
|
||||
if (builder.samples <= 0)
|
||||
{
|
||||
builder.samples = 1;
|
||||
}
|
||||
if (builder.samples > 128)
|
||||
{
|
||||
builder.samples = 128;
|
||||
}
|
||||
|
||||
builder.samples = kexMath::RoundPowerOfTwo(builder.samples);
|
||||
arg++;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-ambience"))
|
||||
{
|
||||
if (argv[arg + 1] == NULL)
|
||||
{
|
||||
Error("Specify value for -ambience\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
builder.ambience = (float)atof(argv[++arg]);
|
||||
if (builder.ambience < 0)
|
||||
{
|
||||
builder.ambience = 0;
|
||||
}
|
||||
if (builder.ambience > 1)
|
||||
{
|
||||
builder.ambience = 1;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-size"))
|
||||
{
|
||||
int lmDims;
|
||||
|
||||
if (argv[arg + 1] == NULL)
|
||||
{
|
||||
Error("Specify value for -size\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
lmDims = atoi(argv[++arg]);
|
||||
if (lmDims <= 0)
|
||||
{
|
||||
lmDims = 1;
|
||||
}
|
||||
if (lmDims > LIGHTMAP_MAX_SIZE)
|
||||
{
|
||||
lmDims = LIGHTMAP_MAX_SIZE;
|
||||
}
|
||||
|
||||
lmDims = kexMath::RoundPowerOfTwo(lmDims);
|
||||
|
||||
builder.textureWidth = lmDims;
|
||||
builder.textureHeight = lmDims;
|
||||
arg++;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-threads"))
|
||||
{
|
||||
kexWorker::maxWorkThreads = atoi(argv[++arg]);
|
||||
kexMath::Clamp(kexWorker::maxWorkThreads, 1, MAX_THREADS);
|
||||
arg++;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-config"))
|
||||
{
|
||||
configFile = argv[++arg];
|
||||
arg++;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-writetga"))
|
||||
{
|
||||
bWriteTGA = true;
|
||||
arg++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argv[arg] == NULL)
|
||||
{
|
||||
printf("Usage: dlight [options] [wadfile]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!wadFile.Open(argv[arg]))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// concat the base path to light def file if there is none
|
||||
if (configFile.IndexOf("\\") == -1 && configFile.IndexOf("/") == -1)
|
||||
{
|
||||
configFile = basePath + configFile;
|
||||
}
|
||||
|
||||
int starttime = (int)GetSeconds();
|
||||
|
||||
printf("---------------- Parsing config file ----------------\n\n");
|
||||
doomMap.ParseConfigFile(configFile.c_str());
|
||||
|
||||
printf("------------- Building level structures -------------\n\n");
|
||||
wadFile.SetCurrentMap(map);
|
||||
doomMap.BuildMapFromWad(wadFile);
|
||||
|
||||
printf("----------- Allocating surfaces from level ----------\n\n");
|
||||
Surface_AllocateFromMap(doomMap);
|
||||
|
||||
printf("---------------- Allocating lights ----------------\n\n");
|
||||
doomMap.CreateLights();
|
||||
|
||||
printf("---------------- Creating lightmaps ---------------\n\n");
|
||||
builder.CreateLightmaps(doomMap);
|
||||
doomMap.CleanupThingLights();
|
||||
|
||||
if (bWriteTGA)
|
||||
{
|
||||
builder.WriteTexturesToTGA();
|
||||
}
|
||||
|
||||
printf("------------------ Rebuilding wad ----------------\n\n");
|
||||
wadFile.CreateBackup();
|
||||
|
||||
lmLump = wadFile.GetLumpFromName(Va("LM_MAP%02d", wadFile.currentmap));
|
||||
|
||||
if (lmLump)
|
||||
{
|
||||
int lumpnum = lmLump - wadFile.lumps;
|
||||
|
||||
ignoreLumps.Push(lumpnum + ML_LM_LABEL);
|
||||
ignoreLumps.Push(lumpnum + ML_LM_CELLS);
|
||||
ignoreLumps.Push(lumpnum + ML_LM_SUN);
|
||||
ignoreLumps.Push(lumpnum + ML_LM_SURFS);
|
||||
ignoreLumps.Push(lumpnum + ML_LM_TXCRD);
|
||||
ignoreLumps.Push(lumpnum + ML_LM_LMAPS);
|
||||
}
|
||||
|
||||
outWadFile.InitForWrite();
|
||||
outWadFile.CopyLumpsFromWadFile(wadFile, ignoreLumps);
|
||||
outWadFile.AddLump(Va("LM_MAP%02d", wadFile.currentmap), 0, NULL);
|
||||
|
||||
builder.AddLightGridLump(outWadFile);
|
||||
builder.AddLightmapLumps(outWadFile);
|
||||
|
||||
printf("------------- Writing %s -------------\n\n", wadFile.wadName.c_str());
|
||||
outWadFile.Write(wadFile.wadName);
|
||||
outWadFile.Close();
|
||||
wadFile.Close();
|
||||
|
||||
printf("----------------- Shutting down -----------------\n\n");
|
||||
Mem_Purge(hb_static);
|
||||
|
||||
int proctime = (int)GetSeconds() - starttime;
|
||||
printf("\nBuild time: %d:%02d:%02d\n",
|
||||
proctime / 3600, (proctime / 60) % 60, proctime % 60);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,75 +1,10 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Note: this is a modified version of dlight. It is not the original software.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2013-2014 Samuel Villarreal
|
||||
// svkaiser@gmail.com
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
// There's a race condition in the code that causes it to sometimes fail if using multiple threads
|
||||
//#define MAX_THREADS 128
|
||||
#define MAX_THREADS 1
|
||||
|
||||
class kexWorker;
|
||||
|
||||
typedef void(*jobFunc_t)(void*, int);
|
||||
|
||||
struct jobFuncArgs_t
|
||||
{
|
||||
kexWorker *worker;
|
||||
void *data;
|
||||
int jobID;
|
||||
};
|
||||
#include <functional>
|
||||
|
||||
class kexWorker
|
||||
{
|
||||
public:
|
||||
kexWorker();
|
||||
~kexWorker();
|
||||
|
||||
void RunThreads(const int count, void *data, jobFunc_t jobFunc);
|
||||
void LockMutex();
|
||||
void UnlockMutex();
|
||||
void Destroy();
|
||||
|
||||
bool FinishedAllJobs() { return jobsWorked == numWorkLoad; }
|
||||
int DispatchJob() { int j = jobsWorked; jobsWorked++; return j; }
|
||||
void RunJob(void *data, const int jobID) { job(data, jobID); }
|
||||
|
||||
jobFuncArgs_t *Args(const int id) { return &jobArgs[id]; }
|
||||
const int JobsWorked() const { return jobsWorked; }
|
||||
|
||||
static int maxWorkThreads;
|
||||
|
||||
private:
|
||||
std::thread threads[MAX_THREADS];
|
||||
jobFuncArgs_t jobArgs[MAX_THREADS];
|
||||
std::mutex mutex;
|
||||
jobFunc_t job;
|
||||
int jobsWorked;
|
||||
int numWorkLoad;
|
||||
static void RunJob(int count, std::function<void(int i)> callback);
|
||||
};
|
||||
|
|
292
src/main.cpp
292
src/main.cpp
|
@ -53,6 +53,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <thread>
|
||||
|
||||
#include "framework/zdray.h"
|
||||
#include "wad/wad.h"
|
||||
|
@ -113,6 +114,9 @@ bool GLOnly = true;// false;
|
|||
bool V5GLNodes = false;
|
||||
bool HaveSSE1, HaveSSE2;
|
||||
int SSELevel;
|
||||
int NumThreads = 0;
|
||||
int LMDims = LIGHTMAP_MAX_SIZE;
|
||||
int Samples = 8;
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
|
@ -148,6 +152,9 @@ static option long_opts[] =
|
|||
{"no-sse", no_argument, 0, 1002},
|
||||
{"no-sse2", no_argument, 0, 1003},
|
||||
{"comments", no_argument, 0, 'c'},
|
||||
{"threads", required_argument, 0, 'j'},
|
||||
{"samples", required_argument, 0, 'Q'},
|
||||
{"size", required_argument, 0, 'S'},
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
|
@ -426,6 +433,21 @@ static void ParseArgs(int argc, char **argv)
|
|||
case 1003: // Disable only SSE2 ClassifyLine routine
|
||||
HaveSSE2 = false;
|
||||
break;
|
||||
case 'j':
|
||||
NumThreads = atoi(optarg);
|
||||
break;
|
||||
case 'Q':
|
||||
Samples = atoi(optarg);
|
||||
if (Samples <= 0) Samples = 1;
|
||||
if (Samples > 128) Samples = 128;
|
||||
Samples = kexMath::RoundPowerOfTwo(Samples);
|
||||
break;
|
||||
case 'S':
|
||||
LMDims = atoi(optarg);
|
||||
if (LMDims <= 0) LMDims = 1;
|
||||
if (LMDims > LIGHTMAP_MAX_SIZE) LMDims = LIGHTMAP_MAX_SIZE;
|
||||
LMDims = kexMath::RoundPowerOfTwo(LMDims);
|
||||
break;
|
||||
case 1000:
|
||||
ShowUsage();
|
||||
exit(0);
|
||||
|
@ -466,6 +488,11 @@ static void ShowUsage()
|
|||
" -s, --split-cost=NNN Cost for splitting segs (default %d)\n"
|
||||
" -d, --diagonal-cost=NNN Cost for avoiding diagonal splitters (default %d)\n"
|
||||
" -P, --no-polyobjs Do not check for polyobject subsector splits\n"
|
||||
" -j, --threads=NNN Number of threads used for raytracing (default %d)\n"
|
||||
" -Q, --samples=NNN Set texel sampling size (lowest = higher quaility but\n"
|
||||
" slow compile time) must be in powers of two\n"
|
||||
" -S, --size=NNN lightmap texture dimensions for width and height\n"
|
||||
" must be in powers of two (1, 2, 4, 8, 16, etc)\n"
|
||||
#ifdef _WIN32
|
||||
" -v, --view View the nodes\n"
|
||||
#endif
|
||||
|
@ -481,6 +508,7 @@ static void ShowUsage()
|
|||
, MaxSegs /* Partition size */
|
||||
, SplitCost
|
||||
, AAPreference
|
||||
, (int)std::thread::hardware_concurrency()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -678,10 +706,6 @@ static void CheckSSE()
|
|||
}
|
||||
#endif
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Warn
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void Warn(const char *format, ...)
|
||||
|
@ -697,3 +721,263 @@ void Warn(const char *format, ...)
|
|||
vprintf(format, marker);
|
||||
va_end(marker);
|
||||
}
|
||||
|
||||
void Error(const char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
|
||||
va_start(argptr, error);
|
||||
vprintf(error, argptr);
|
||||
va_end(argptr);
|
||||
printf("\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *Va(const char *str, ...)
|
||||
{
|
||||
va_list v;
|
||||
static char vastr[1024];
|
||||
|
||||
va_start(v, str);
|
||||
vsprintf(vastr, str, v);
|
||||
va_end(v);
|
||||
|
||||
return vastr;
|
||||
}
|
||||
|
||||
void Delay(int ms)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
const int64_t GetSeconds()
|
||||
{
|
||||
return time(0);
|
||||
}
|
||||
|
||||
#if 0 // Old dlight main function
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
kexWadFile wadFile;
|
||||
kexWadFile outWadFile;
|
||||
FLevel doomMap;
|
||||
lump_t *lmLump;
|
||||
kexArray<int> ignoreLumps;
|
||||
kexLightmapBuilder builder;
|
||||
kexStr configFile("strife_sve.cfg");
|
||||
bool bWriteTGA;
|
||||
int map = 1;
|
||||
int arg = 1;
|
||||
|
||||
printf("DLight (c) 2013-2014 Samuel Villarreal\n\n");
|
||||
|
||||
if (argc < 1 || argv[1] == NULL)
|
||||
{
|
||||
printf("Usage: dlight [options] [wadfile]\n");
|
||||
printf("Use -help for list of options\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
basePath = argv[0];
|
||||
basePath.StripFile();
|
||||
|
||||
bWriteTGA = false;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!strcmp(argv[arg], "-help"))
|
||||
{
|
||||
printf("Options:\n");
|
||||
printf("-help: displays all known options\n");
|
||||
printf("-map: process lightmap for MAP##\n");
|
||||
printf("-samples: set texel sampling size (lowest = higher quaility but\n");
|
||||
printf(" slow compile time) must be in powers of two\n");
|
||||
printf("-ambience: set global ambience value for lightmaps (0.0 - 1.0)\n");
|
||||
printf("-size: lightmap texture dimentions for width and height\n");
|
||||
printf(" must be in powers of two (1, 2, 4, 8, 16, etc)\n");
|
||||
printf("-threads: set total number of threads (1 min, 128 max)\n");
|
||||
printf("-config: specify a config file to parse (default: strife_sve.cfg)\n");
|
||||
printf("-writetga: dumps lightmaps to targa (.TGA) files\n");
|
||||
arg++;
|
||||
return 0;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-map"))
|
||||
{
|
||||
if (argv[arg + 1] == NULL)
|
||||
{
|
||||
Error("Specify map number for -map\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
map = atoi(argv[++arg]);
|
||||
arg++;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-samples"))
|
||||
{
|
||||
if (argv[arg + 1] == NULL)
|
||||
{
|
||||
Error("Specify value for -samples\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
builder.samples = atoi(argv[++arg]);
|
||||
if (builder.samples <= 0)
|
||||
{
|
||||
builder.samples = 1;
|
||||
}
|
||||
if (builder.samples > 128)
|
||||
{
|
||||
builder.samples = 128;
|
||||
}
|
||||
|
||||
builder.samples = kexMath::RoundPowerOfTwo(builder.samples);
|
||||
arg++;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-ambience"))
|
||||
{
|
||||
if (argv[arg + 1] == NULL)
|
||||
{
|
||||
Error("Specify value for -ambience\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
builder.ambience = (float)atof(argv[++arg]);
|
||||
if (builder.ambience < 0)
|
||||
{
|
||||
builder.ambience = 0;
|
||||
}
|
||||
if (builder.ambience > 1)
|
||||
{
|
||||
builder.ambience = 1;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-size"))
|
||||
{
|
||||
int lmDims;
|
||||
|
||||
if (argv[arg + 1] == NULL)
|
||||
{
|
||||
Error("Specify value for -size\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
lmDims = atoi(argv[++arg]);
|
||||
if (lmDims <= 0)
|
||||
{
|
||||
lmDims = 1;
|
||||
}
|
||||
if (lmDims > LIGHTMAP_MAX_SIZE)
|
||||
{
|
||||
lmDims = LIGHTMAP_MAX_SIZE;
|
||||
}
|
||||
|
||||
lmDims = kexMath::RoundPowerOfTwo(lmDims);
|
||||
|
||||
builder.textureWidth = lmDims;
|
||||
builder.textureHeight = lmDims;
|
||||
arg++;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-threads"))
|
||||
{
|
||||
kexWorker::maxWorkThreads = atoi(argv[++arg]);
|
||||
kexMath::Clamp(kexWorker::maxWorkThreads, 1, MAX_THREADS);
|
||||
arg++;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-config"))
|
||||
{
|
||||
configFile = argv[++arg];
|
||||
arg++;
|
||||
}
|
||||
else if (!strcmp(argv[arg], "-writetga"))
|
||||
{
|
||||
bWriteTGA = true;
|
||||
arg++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argv[arg] == NULL)
|
||||
{
|
||||
printf("Usage: dlight [options] [wadfile]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!wadFile.Open(argv[arg]))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// concat the base path to light def file if there is none
|
||||
if (configFile.IndexOf("\\") == -1 && configFile.IndexOf("/") == -1)
|
||||
{
|
||||
configFile = basePath + configFile;
|
||||
}
|
||||
|
||||
int starttime = (int)GetSeconds();
|
||||
|
||||
printf("---------------- Parsing config file ----------------\n\n");
|
||||
doomMap.ParseConfigFile(configFile.c_str());
|
||||
|
||||
printf("------------- Building level structures -------------\n\n");
|
||||
wadFile.SetCurrentMap(map);
|
||||
doomMap.BuildMapFromWad(wadFile);
|
||||
|
||||
printf("----------- Allocating surfaces from level ----------\n\n");
|
||||
Surface_AllocateFromMap(doomMap);
|
||||
|
||||
printf("---------------- Allocating lights ----------------\n\n");
|
||||
doomMap.CreateLights();
|
||||
|
||||
printf("---------------- Creating lightmaps ---------------\n\n");
|
||||
builder.CreateLightmaps(doomMap);
|
||||
doomMap.CleanupThingLights();
|
||||
|
||||
if (bWriteTGA)
|
||||
{
|
||||
builder.WriteTexturesToTGA();
|
||||
}
|
||||
|
||||
printf("------------------ Rebuilding wad ----------------\n\n");
|
||||
wadFile.CreateBackup();
|
||||
|
||||
lmLump = wadFile.GetLumpFromName(Va("LM_MAP%02d", wadFile.currentmap));
|
||||
|
||||
if (lmLump)
|
||||
{
|
||||
int lumpnum = lmLump - wadFile.lumps;
|
||||
|
||||
ignoreLumps.Push(lumpnum + ML_LM_LABEL);
|
||||
ignoreLumps.Push(lumpnum + ML_LM_CELLS);
|
||||
ignoreLumps.Push(lumpnum + ML_LM_SUN);
|
||||
ignoreLumps.Push(lumpnum + ML_LM_SURFS);
|
||||
ignoreLumps.Push(lumpnum + ML_LM_TXCRD);
|
||||
ignoreLumps.Push(lumpnum + ML_LM_LMAPS);
|
||||
}
|
||||
|
||||
outWadFile.InitForWrite();
|
||||
outWadFile.CopyLumpsFromWadFile(wadFile, ignoreLumps);
|
||||
outWadFile.AddLump(Va("LM_MAP%02d", wadFile.currentmap), 0, NULL);
|
||||
|
||||
builder.AddLightGridLump(outWadFile);
|
||||
builder.AddLightmapLumps(outWadFile);
|
||||
|
||||
printf("------------- Writing %s -------------\n\n", wadFile.wadName.c_str());
|
||||
outWadFile.Write(wadFile.wadName);
|
||||
outWadFile.Close();
|
||||
wadFile.Close();
|
||||
|
||||
printf("----------------- Shutting down -----------------\n\n");
|
||||
Mem_Purge(hb_static);
|
||||
|
||||
int proctime = (int)GetSeconds() - starttime;
|
||||
printf("\nBuild time: %d:%02d:%02d\n",
|
||||
proctime / 3600, (proctime / 60) % 60, proctime % 60);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue