From 8f564c9210102cc87551062179ce71c5360df20e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 31 Dec 2018 16:43:50 +0100 Subject: [PATCH] - improve distribution of work between worker threads --- src/lightmap/lightmap.cpp | 224 ++++++++++++++++++++------------------ src/lightmap/lightmap.h | 22 +++- src/lightmap/worker.cpp | 4 +- 3 files changed, 136 insertions(+), 114 deletions(-) diff --git a/src/lightmap/lightmap.cpp b/src/lightmap/lightmap.cpp index 85bbff8..bf98a6d 100644 --- a/src/lightmap/lightmap.cpp +++ b/src/lightmap/lightmap.cpp @@ -398,53 +398,41 @@ void LightmapBuilder::BuildSurfaceParams(Surface *surface) } // Steps through each texel and traces a line to the world. -void LightmapBuilder::TraceSurface(Surface *surface) +void LightmapBuilder::TraceSurface(Surface *surface, int offset) { int sampleWidth = surface->lightmapDims[0]; int sampleHeight = surface->lightmapDims[1]; - Vec3 normal = surface->plane.Normal(); - int multisampleCount = Multisample; - - surface->samples.resize(sampleWidth * sampleHeight); Vec3 *colorSamples = surface->samples.data(); - // start walking through each texel - for (int i = 0; i < sampleHeight; i++) + int offsetend = std::min(offset + TraceTask::tasksize, sampleWidth * sampleHeight); + for (int pos = offset; pos < offsetend; pos++) { - for (int j = 0; j < sampleWidth; j++) + int i = pos / sampleWidth; + int j = pos % sampleWidth; + + Vec3 c(0.0f, 0.0f, 0.0f); + + int totalsamples = (multisampleCount * 2 + 1); + float scale = 0.5f / totalsamples; + for (int yy = -multisampleCount; yy <= multisampleCount; yy++) { - Vec3 c(0.0f, 0.0f, 0.0f); - - int totalsamples = (multisampleCount * 2 + 1); - float scale = 0.5f / totalsamples; - for (int yy = -multisampleCount; yy <= multisampleCount; yy++) + for (int xx = -multisampleCount; xx <= multisampleCount; xx++) { - for (int xx = -multisampleCount; xx <= multisampleCount; xx++) - { - Vec2 multisamplePos((float)j + xx * scale, (float)i + yy * scale); + Vec2 multisamplePos((float)j + xx * scale, (float)i + yy * scale); - // convert the texel into world-space coordinates. - // this will be the origin in which a line will be traced from - Vec3 pos = surface->lightmapOrigin + normal + (surface->lightmapSteps[0] * multisamplePos.x) + (surface->lightmapSteps[1] * multisamplePos.y); + // convert the texel into world-space coordinates. + // this will be the origin in which a line will be traced from + Vec3 pos = surface->lightmapOrigin + normal + (surface->lightmapSteps[0] * multisamplePos.x) + (surface->lightmapSteps[1] * multisamplePos.y); - c += LightTexelSample(pos, surface); - } + c += LightTexelSample(pos, surface); } - - c /= totalsamples * totalsamples; - - colorSamples[i * sampleWidth + j] = c; } - } - // texture coordinates relative to block - for (int i = 0; i < surface->numVerts; i++) - { - Vec3 tDelta = surface->verts[i] - surface->bounds.min; - surface->lightmapCoords[i * 2 + 0] = tDelta.Dot(surface->textureCoords[0]); - surface->lightmapCoords[i * 2 + 1] = tDelta.Dot(surface->textureCoords[1]); + c /= totalsamples * totalsamples; + + colorSamples[i * sampleWidth + j] = c; } } @@ -575,111 +563,132 @@ static Vec3 ImportanceSampleGGX(Vec2 Xi, Vec3 N, float roughness) return Vec3::Normalize(sampleVec); } -void LightmapBuilder::TraceIndirectLight(Surface *surface) +void LightmapBuilder::TraceIndirectLight(Surface *surface, int offset) { int sampleWidth = surface->lightmapDims[0]; int sampleHeight = surface->lightmapDims[1]; - Vec3 normal = surface->plane.Normal(); - - surface->indirect.resize(sampleWidth * sampleHeight); Vec3 *indirect = surface->indirect.data(); - for (int i = 0; i < sampleHeight; i++) + int offsetend = std::min(offset + TraceTask::tasksize, sampleWidth * sampleHeight); + for (int offpos = offset; offpos < offsetend; offpos++) { - for (int j = 0; j < sampleWidth; j++) + int i = offpos / sampleWidth; + int j = offpos % sampleWidth; + + Vec3 pos = surface->lightmapOrigin + normal + + (surface->lightmapSteps[0] * (float)j) + + (surface->lightmapSteps[1] * (float)i); + + const int SAMPLE_COUNT = 128;// 1024; + + float totalWeight = 0.0f; + Vec3 c(0.0f, 0.0f, 0.0f); + + for (int i = 0; i < SAMPLE_COUNT; i++) { - Vec3 pos = surface->lightmapOrigin + normal + - (surface->lightmapSteps[0] * (float)j) + - (surface->lightmapSteps[1] * (float)i); + Vec2 Xi = Hammersley(i, SAMPLE_COUNT); + Vec3 H = ImportanceSampleGGX(Xi, normal, 1.0f); + Vec3 L = Vec3::Normalize(H * (2.0f * Vec3::Dot(normal, H)) - normal); - const int SAMPLE_COUNT = 128;// 1024; - - float totalWeight = 0.0f; - Vec3 c(0.0f, 0.0f, 0.0f); - - for (int i = 0; i < SAMPLE_COUNT; i++) + float NdotL = std::max(Vec3::Dot(normal, L), 0.0f); + if (NdotL > 0.0f) { - Vec2 Xi = Hammersley(i, SAMPLE_COUNT); - Vec3 H = ImportanceSampleGGX(Xi, normal, 1.0f); - Vec3 L = Vec3::Normalize(H * (2.0f * Vec3::Dot(normal, H)) - normal); - - float NdotL = std::max(Vec3::Dot(normal, L), 0.0f); - if (NdotL > 0.0f) + tracedTexels++; + LevelTraceHit hit = mesh->Trace(pos, pos + L * 1000.0f); + if (hit.fraction < 1.0f) { - tracedTexels++; - LevelTraceHit hit = mesh->Trace(pos, pos + L * 1000.0f); - if (hit.fraction < 1.0f) + Vec3 surfaceLight; + if (hit.hitSurface->bSky) { - Vec3 surfaceLight; - if (hit.hitSurface->bSky) - { - surfaceLight = { 0.5f, 0.5f, 0.5f }; - } - else - { - float u = - hit.hitSurface->lightmapCoords[hit.indices[0] * 2] * (1.0f - hit.b - hit.c) + - hit.hitSurface->lightmapCoords[hit.indices[1] * 2] * hit.b + - hit.hitSurface->lightmapCoords[hit.indices[2] * 2] * hit.c; - - float v = - hit.hitSurface->lightmapCoords[hit.indices[0] * 2 + 1] * (1.0f - hit.b - hit.c) + - hit.hitSurface->lightmapCoords[hit.indices[1] * 2 + 1] * hit.b + - hit.hitSurface->lightmapCoords[hit.indices[2] * 2 + 1] * hit.c; - - int hitTexelX = clamp((int)(u + 0.5f), 0, hit.hitSurface->lightmapDims[0] - 1); - int hitTexelY = clamp((int)(v + 0.5f), 0, hit.hitSurface->lightmapDims[1] - 1); - - Vec3 *hitTexture = hit.hitSurface->samples.data(); - const Vec3 &hitPixel = hitTexture[hitTexelX + hitTexelY * hit.hitSurface->lightmapDims[0]]; - - float attenuation = (1.0f - hit.fraction); - surfaceLight = hitPixel * attenuation; - } - c += surfaceLight * NdotL; + surfaceLight = { 0.5f, 0.5f, 0.5f }; } - totalWeight += NdotL; + else + { + float u = + hit.hitSurface->lightmapCoords[hit.indices[0] * 2] * (1.0f - hit.b - hit.c) + + hit.hitSurface->lightmapCoords[hit.indices[1] * 2] * hit.b + + hit.hitSurface->lightmapCoords[hit.indices[2] * 2] * hit.c; + + float v = + hit.hitSurface->lightmapCoords[hit.indices[0] * 2 + 1] * (1.0f - hit.b - hit.c) + + hit.hitSurface->lightmapCoords[hit.indices[1] * 2 + 1] * hit.b + + hit.hitSurface->lightmapCoords[hit.indices[2] * 2 + 1] * hit.c; + + int hitTexelX = clamp((int)(u + 0.5f), 0, hit.hitSurface->lightmapDims[0] - 1); + int hitTexelY = clamp((int)(v + 0.5f), 0, hit.hitSurface->lightmapDims[1] - 1); + + Vec3 *hitTexture = hit.hitSurface->samples.data(); + const Vec3 &hitPixel = hitTexture[hitTexelX + hitTexelY * hit.hitSurface->lightmapDims[0]]; + + float attenuation = (1.0f - hit.fraction); + surfaceLight = hitPixel * attenuation; + } + c += surfaceLight * NdotL; } + totalWeight += NdotL; } - - c = c / totalWeight; - - indirect[i * sampleWidth + j] = c; } + + c = c / totalWeight; + + indirect[i * sampleWidth + j] = c; } } -void LightmapBuilder::LightSurface(const int surfid) +void LightmapBuilder::CreateTraceTasks() { - BuildSurfaceParams(mesh->surfaces[surfid].get()); - TraceSurface(mesh->surfaces[surfid].get()); + for (size_t i = 0; i < mesh->surfaces.size(); i++) + { + Surface *surface = mesh->surfaces[i].get(); + + BuildSurfaceParams(surface); + + int sampleWidth = surface->lightmapDims[0]; + int sampleHeight = surface->lightmapDims[1]; + surface->samples.resize(sampleWidth * sampleHeight); + + if (LightBounce > 0) + surface->indirect.resize(sampleWidth * sampleHeight); + + int total = sampleWidth * sampleHeight; + int count = (total + TraceTask::tasksize - 1) / TraceTask::tasksize; + for (int j = 0; j < count; j++) + traceTasks.push_back(TraceTask(i, j * TraceTask::tasksize)); + } +} + +void LightmapBuilder::LightSurface(const int taskid) +{ + const TraceTask &task = traceTasks[taskid]; + TraceSurface(mesh->surfaces[task.surface].get(), task.offset); std::unique_lock lock(mutex); - int numsurfs = mesh->surfaces.size(); - int lastproc = processed * 100 / numsurfs; + int numtasks = traceTasks.size(); + int lastproc = processed * 100 / numtasks; processed++; - int curproc = processed * 100 / numsurfs; + int curproc = processed * 100 / numtasks; if (lastproc != curproc || processed == 1) { - float remaining = (float)processed / (float)numsurfs; - printf("%i%c surfaces done\r", (int)(remaining * 100.0f), '%'); + float remaining = (float)processed / (float)numtasks; + printf("%i%c done\r", (int)(remaining * 100.0f), '%'); } } -void LightmapBuilder::LightIndirect(const int surfid) +void LightmapBuilder::LightIndirect(const int taskid) { - TraceIndirectLight(mesh->surfaces[surfid].get()); + const TraceTask &task = traceTasks[taskid]; + TraceIndirectLight(mesh->surfaces[task.surface].get(), task.offset); - int numsurfs = mesh->surfaces.size(); - int lastproc = processed * 100 / numsurfs; + int numtasks = traceTasks.size(); + int lastproc = processed * 100 / numtasks; processed++; - int curproc = processed * 100 / numsurfs; + int curproc = processed * 100 / numtasks; if (lastproc != curproc || processed == 1) { - float remaining = (float)processed / (float)numsurfs; - printf("%i%c surfaces done\r", (int)(remaining * 100.0f), '%'); + float remaining = (float)processed / (float)numtasks; + printf("%i%c done\r", (int)(remaining * 100.0f), '%'); } } @@ -733,6 +742,7 @@ void LightmapBuilder::CreateLightmaps(FLevel &doomMap, int sampleDistance, int t mesh = std::make_unique(doomMap); CreateSurfaceLights(); + CreateTraceTasks(); printf("-------------- Tracing cells ---------------\n"); @@ -750,7 +760,7 @@ void LightmapBuilder::CreateLightmaps(FLevel &doomMap, int sampleDistance, int t tracedTexels = 0; processed = 0; - Worker::RunJob(mesh->surfaces.size(), [=](int id) { + Worker::RunJob(traceTasks.size(), [=](int id) { LightSurface(id); }); @@ -762,12 +772,12 @@ void LightmapBuilder::CreateLightmaps(FLevel &doomMap, int sampleDistance, int t tracedTexels = 0; processed = 0; - Worker::RunJob(mesh->surfaces.size(), [=](int id) { + Worker::RunJob(traceTasks.size(), [=](int id) { LightIndirect(id); }); - } - printf("Texels traced: %i \n\n", tracedTexels); + printf("Texels traced: %i \n\n", tracedTexels); + } for (auto &surf : mesh->surfaces) { diff --git a/src/lightmap/lightmap.h b/src/lightmap/lightmap.h index b635748..71a0781 100644 --- a/src/lightmap/lightmap.h +++ b/src/lightmap/lightmap.h @@ -67,6 +67,18 @@ private: std::vector mPixels; }; +class TraceTask +{ +public: + TraceTask() { } + TraceTask(int surface, int offset) : surface(surface), offset(offset) { } + + int surface = 0; + int offset = 0; + + static const int tasksize = 64; +}; + class LightmapBuilder { public: @@ -84,13 +96,14 @@ private: bool EmitFromCeiling(const Surface *surface, const Vec3 &origin, const Vec3 &normal, Vec3 &color); void BuildSurfaceParams(Surface *surface); - void TraceSurface(Surface *surface); - void TraceIndirectLight(Surface *surface); + void TraceSurface(Surface *surface, int offset); + void TraceIndirectLight(Surface *surface, int offset); void FinishSurface(Surface *surface); void SetupLightCellGrid(); void LightBlock(int blockid); - void LightSurface(const int surfid); - void LightIndirect(const int surfid); + void CreateTraceTasks(); + void LightSurface(const int taskid); + void LightIndirect(const int taskid); void CreateSurfaceLights(); @@ -102,6 +115,7 @@ private: std::unique_ptr mesh; std::vector> surfaceLights; std::vector> textures; + std::vector traceTasks; std::vector> allocBlocks; int numTextures = 0; int extraSamples = 2; diff --git a/src/lightmap/worker.cpp b/src/lightmap/worker.cpp index 6746e55..0bf792b 100644 --- a/src/lightmap/worker.cpp +++ b/src/lightmap/worker.cpp @@ -23,9 +23,7 @@ void Worker::RunJob(int count, std::function callback) { threads.push_back(std::thread([=]() { - int start = threadIndex * count / numThreads; - int end = std::min((threadIndex + 1) * count / numThreads, count); - for (int i = start; i < end; i++) + for (int i = threadIndex; i < count; i += numThreads) { callback(i); }