mirror of
https://github.com/ZDoom/ZDRay.git
synced 2024-11-14 00:21:24 +00:00
Merge pull request #42 from MrRaveYard/pr_old_gpu_task_discarding
Discard trace tasks for GPURaytracer
This commit is contained in:
commit
42c1258fc9
7 changed files with 166 additions and 100 deletions
|
@ -174,6 +174,8 @@ set( SOURCES
|
||||||
src/lightmap/vulkanbuilders.h
|
src/lightmap/vulkanbuilders.h
|
||||||
src/lightmap/stacktrace.cpp
|
src/lightmap/stacktrace.cpp
|
||||||
src/lightmap/stacktrace.h
|
src/lightmap/stacktrace.h
|
||||||
|
src/lightmap/surfaceclip.cpp
|
||||||
|
src/lightmap/surfaceclip.h
|
||||||
src/lightmap/gpuraytracer.cpp
|
src/lightmap/gpuraytracer.cpp
|
||||||
src/lightmap/gpuraytracer.h
|
src/lightmap/gpuraytracer.h
|
||||||
src/lightmap/gpuraytracer2.cpp
|
src/lightmap/gpuraytracer2.cpp
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "framework/binfile.h"
|
#include "framework/binfile.h"
|
||||||
#include "framework/templates.h"
|
#include "framework/templates.h"
|
||||||
#include "framework/halffloat.h"
|
#include "framework/halffloat.h"
|
||||||
#include "delauneytriangulator.h"
|
#include "surfaceclip.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -347,14 +347,6 @@ float CPURaytracer::RadicalInverse_VdC(uint32_t bits)
|
||||||
return float(bits) * 2.3283064365386963e-10f; // / 0x100000000
|
return float(bits) * 2.3283064365386963e-10f; // / 0x100000000
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef DelauneyTriangulator::Vertex DTVertex;
|
|
||||||
|
|
||||||
inline bool PointOnSide(const vec2& p, const DTVertex& v1, const DTVertex& v2, float tolerance)
|
|
||||||
{
|
|
||||||
vec2 p2 = p - normalize(vec2(-(v2.y - v1.y), v2.x - v1.x)) * tolerance;
|
|
||||||
return (p2.y - v1.y) * (v2.x - v1.x) + (v1.x - p2.x) * (v2.y - v1.y) <= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPURaytracer::CreateTasks(std::vector<CPUTraceTask>& tasks)
|
void CPURaytracer::CreateTasks(std::vector<CPUTraceTask>& tasks)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < mesh->lightProbes.size(); i++)
|
for (size_t i = 0; i < mesh->lightProbes.size(); i++)
|
||||||
|
@ -371,82 +363,24 @@ void CPURaytracer::CreateTasks(std::vector<CPUTraceTask>& tasks)
|
||||||
for (size_t i = 0; i < mesh->surfaces.size(); i++)
|
for (size_t i = 0; i < mesh->surfaces.size(); i++)
|
||||||
{
|
{
|
||||||
if (i % 4096 == 0)
|
if (i % 4096 == 0)
|
||||||
printf("\rGathering surface trace tasks: %d / %d", i, mesh->surfaces.size());
|
printf("\rGathering surface trace tasks: %llu / %llu", i, mesh->surfaces.size());
|
||||||
|
|
||||||
Surface* surface = mesh->surfaces[i].get();
|
Surface* surface = mesh->surfaces[i].get();
|
||||||
int sampleWidth = surface->lightmapDims[0];
|
|
||||||
int sampleHeight = surface->lightmapDims[1];
|
|
||||||
|
|
||||||
if (!surface->bSky)
|
if (!surface->bSky)
|
||||||
{
|
{
|
||||||
// Transformation matrix
|
int sampleWidth = surface->lightmapDims[0];
|
||||||
mat3 base;
|
int sampleHeight = surface->lightmapDims[1];
|
||||||
base[0] = surface->lightmapSteps[0].x;
|
|
||||||
base[1] = surface->lightmapSteps[0].y;
|
|
||||||
base[2] = surface->lightmapSteps[0].z;
|
|
||||||
base[3] = surface->lightmapSteps[1].x;
|
|
||||||
base[4] = surface->lightmapSteps[1].y;
|
|
||||||
base[5] = surface->lightmapSteps[1].z;
|
|
||||||
base[6] = surface->plane.a;
|
|
||||||
base[7] = surface->plane.b;
|
|
||||||
base[8] = surface->plane.c;
|
|
||||||
|
|
||||||
mat3 inverseProjection = mat3::inverse(base);
|
|
||||||
|
|
||||||
// Transform vertices to XY and triangulate
|
|
||||||
DelauneyTriangulator triangulator;
|
|
||||||
|
|
||||||
BBox bounds;
|
|
||||||
|
|
||||||
for (const auto& vertex : surface->verts)
|
|
||||||
{
|
|
||||||
auto flattenedVertex = inverseProjection * vertex;
|
|
||||||
|
|
||||||
triangulator.vertices.emplace_back(flattenedVertex.x, flattenedVertex.y, nullptr);
|
|
||||||
|
|
||||||
if (triangulator.vertices.empty())
|
|
||||||
{
|
|
||||||
bounds = BBox(flattenedVertex, flattenedVertex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bounds.AddPoint(flattenedVertex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
triangulator.triangulate();
|
|
||||||
|
|
||||||
const float boundsWidth = bounds.max.x - bounds.min.x;
|
|
||||||
const float boundsHeight = bounds.max.y - bounds.min.y;
|
|
||||||
|
|
||||||
const float offsetW = boundsWidth / sampleWidth;
|
|
||||||
const float offsetH = boundsHeight / sampleHeight;
|
|
||||||
|
|
||||||
const float offset = (offsetH > offsetW ? offsetH : offsetW);
|
|
||||||
|
|
||||||
auto isInBounds = [&](int x, int y) {
|
|
||||||
const float fx = (float(x) / float(sampleWidth)) * boundsWidth + bounds.min.x + offsetW;
|
|
||||||
const float fy = (float(y) / float(sampleHeight)) * boundsHeight + bounds.min.y + offsetH;
|
|
||||||
|
|
||||||
for (const auto& triangle : triangulator.triangles)
|
|
||||||
{
|
|
||||||
if (PointOnSide(vec2(fx, fy), *triangle.A, *triangle.B, offset)
|
|
||||||
&& PointOnSide(vec2(fx, fy), *triangle.B, *triangle.C, offset)
|
|
||||||
&& PointOnSide(vec2(fx, fy), *triangle.C, *triangle.A, offset))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
fullTaskCount += size_t(sampleHeight) * size_t(sampleWidth);
|
fullTaskCount += size_t(sampleHeight) * size_t(sampleWidth);
|
||||||
|
|
||||||
|
SurfaceClip surfaceClip(surface);
|
||||||
|
|
||||||
for (int y = 0; y < sampleHeight; y++)
|
for (int y = 0; y < sampleHeight; y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < sampleWidth; x++)
|
for (int x = 0; x < sampleWidth; x++)
|
||||||
{
|
{
|
||||||
if (isInBounds(x, y))
|
if (surfaceClip.SampleIsInBounds(float(x), float(y)))
|
||||||
{
|
{
|
||||||
CPUTraceTask task;
|
CPUTraceTask task;
|
||||||
task.id = (int)i;
|
task.id = (int)i;
|
||||||
|
@ -458,7 +392,7 @@ void CPURaytracer::CreateTasks(std::vector<CPUTraceTask>& tasks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\rGathering surface trace tasks: %d / %d\n", mesh->surfaces.size(), mesh->surfaces.size());
|
printf("\rGathering surface trace tasks: %llu / %llu\n", mesh->surfaces.size(), mesh->surfaces.size());
|
||||||
printf("\tDiscarded %.3f%% of all tasks\n", (1.0 - double(tasks.size()) / fullTaskCount) * 100.0);
|
printf("\tDiscarded %.3f%% of all tasks\n", (1.0 - double(tasks.size()) / fullTaskCount) * 100.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "framework/templates.h"
|
#include "framework/templates.h"
|
||||||
#include "framework/halffloat.h"
|
#include "framework/halffloat.h"
|
||||||
#include "vulkanbuilders.h"
|
#include "vulkanbuilders.h"
|
||||||
|
#include "surfaceclip.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -50,32 +51,7 @@ void GPURaytracer::Raytrace(LevelMesh* level)
|
||||||
CreateVulkanObjects();
|
CreateVulkanObjects();
|
||||||
|
|
||||||
std::vector<TraceTask> tasks;
|
std::vector<TraceTask> tasks;
|
||||||
for (size_t i = 0; i < mesh->lightProbes.size(); i++)
|
CreateTasks(tasks);
|
||||||
{
|
|
||||||
TraceTask task;
|
|
||||||
task.id = -(int)(i + 2);
|
|
||||||
task.x = 0;
|
|
||||||
task.y = 0;
|
|
||||||
tasks.push_back(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < mesh->surfaces.size(); i++)
|
|
||||||
{
|
|
||||||
Surface* surface = mesh->surfaces[i].get();
|
|
||||||
int sampleWidth = surface->lightmapDims[0];
|
|
||||||
int sampleHeight = surface->lightmapDims[1];
|
|
||||||
for (int y = 0; y < sampleHeight; y++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < sampleWidth; x++)
|
|
||||||
{
|
|
||||||
TraceTask task;
|
|
||||||
task.id = (int)i;
|
|
||||||
task.x = x;
|
|
||||||
task.y = y;
|
|
||||||
tasks.push_back(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<vec3> HemisphereVectors;
|
std::vector<vec3> HemisphereVectors;
|
||||||
HemisphereVectors.reserve(bounceSampleCount);
|
HemisphereVectors.reserve(bounceSampleCount);
|
||||||
|
@ -152,6 +128,57 @@ void GPURaytracer::Raytrace(LevelMesh* level)
|
||||||
printf("Ray trace complete\n");
|
printf("Ray trace complete\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPURaytracer::CreateTasks(std::vector<TraceTask>& tasks)
|
||||||
|
{
|
||||||
|
tasks.resize(mesh->lightProbes.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mesh->lightProbes.size(); i++)
|
||||||
|
{
|
||||||
|
TraceTask task;
|
||||||
|
task.id = -(int)(i + 2);
|
||||||
|
task.x = 0;
|
||||||
|
task.y = 0;
|
||||||
|
tasks.push_back(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fullTaskCount = mesh->lightProbes.size();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mesh->surfaces.size(); i++)
|
||||||
|
{
|
||||||
|
if (i % 4096 == 0)
|
||||||
|
printf("\rGathering surface trace tasks: %llu / %llu", i, mesh->surfaces.size());
|
||||||
|
|
||||||
|
Surface* surface = mesh->surfaces[i].get();
|
||||||
|
|
||||||
|
if (!surface->bSky)
|
||||||
|
{
|
||||||
|
int sampleWidth = surface->lightmapDims[0];
|
||||||
|
int sampleHeight = surface->lightmapDims[1];
|
||||||
|
|
||||||
|
fullTaskCount += size_t(sampleHeight) * size_t(sampleWidth);
|
||||||
|
|
||||||
|
SurfaceClip surfaceClip(surface);
|
||||||
|
|
||||||
|
for (int y = 0; y < sampleHeight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < sampleWidth; x++)
|
||||||
|
{
|
||||||
|
if (surfaceClip.SampleIsInBounds(float(x), float(y)))
|
||||||
|
{
|
||||||
|
TraceTask task;
|
||||||
|
task.id = (int)i;
|
||||||
|
task.x = x;
|
||||||
|
task.y = y;
|
||||||
|
tasks.push_back(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\rGathering surface trace tasks: %llu / %llu\n", mesh->surfaces.size(), mesh->surfaces.size());
|
||||||
|
printf("\tDiscarded %.3f%% of all tasks\n", (1.0 - double(tasks.size()) / fullTaskCount) * 100.0);
|
||||||
|
}
|
||||||
|
|
||||||
void GPURaytracer::CreateVulkanObjects()
|
void GPURaytracer::CreateVulkanObjects()
|
||||||
{
|
{
|
||||||
cmdpool = std::make_unique<VulkanCommandPool>(device.get(), device->graphicsFamily);
|
cmdpool = std::make_unique<VulkanCommandPool>(device.get(), device->graphicsFamily);
|
||||||
|
|
|
@ -66,6 +66,7 @@ public:
|
||||||
void Raytrace(LevelMesh* level);
|
void Raytrace(LevelMesh* level);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void CreateTasks(std::vector<TraceTask>& tasks);
|
||||||
void CreateVulkanObjects();
|
void CreateVulkanObjects();
|
||||||
void CreateVertexAndIndexBuffers();
|
void CreateVertexAndIndexBuffers();
|
||||||
void CreateBottomLevelAccelerationStructure();
|
void CreateBottomLevelAccelerationStructure();
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "framework/tarray.h"
|
#include "framework/tarray.h"
|
||||||
#include "framework/halffloat.h"
|
#include "framework/halffloat.h"
|
||||||
#include "lightmaptexture.h"
|
#include "lightmaptexture.h"
|
||||||
|
#include "math/mathlib.h"
|
||||||
|
|
||||||
struct MapSubsectorEx;
|
struct MapSubsectorEx;
|
||||||
struct IntSector;
|
struct IntSector;
|
||||||
|
|
75
src/lightmap/surfaceclip.cpp
Normal file
75
src/lightmap/surfaceclip.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
#include "surfaceclip.h"
|
||||||
|
|
||||||
|
typedef DelauneyTriangulator::Vertex DTVertex;
|
||||||
|
|
||||||
|
inline bool PointOnSide(const vec2& p, const DTVertex& v1, const DTVertex& v2, float tolerance)
|
||||||
|
{
|
||||||
|
vec2 p2 = p - normalize(vec2(-(v2.y - v1.y), v2.x - v1.x)) * tolerance;
|
||||||
|
return (p2.y - v1.y) * (v2.x - v1.x) + (v1.x - p2.x) * (v2.y - v1.y) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SurfaceClip::SurfaceClip(Surface* surface)
|
||||||
|
{
|
||||||
|
sampleWidth = float(surface->lightmapDims[0]);
|
||||||
|
sampleHeight = float(surface->lightmapDims[1]);
|
||||||
|
|
||||||
|
// Transformation matrix
|
||||||
|
mat3 base;
|
||||||
|
base[0] = surface->lightmapSteps[0].x;
|
||||||
|
base[1] = surface->lightmapSteps[0].y;
|
||||||
|
base[2] = surface->lightmapSteps[0].z;
|
||||||
|
base[3] = surface->lightmapSteps[1].x;
|
||||||
|
base[4] = surface->lightmapSteps[1].y;
|
||||||
|
base[5] = surface->lightmapSteps[1].z;
|
||||||
|
base[6] = surface->plane.a;
|
||||||
|
base[7] = surface->plane.b;
|
||||||
|
base[8] = surface->plane.c;
|
||||||
|
|
||||||
|
mat3 inverseProjection = mat3::inverse(base);
|
||||||
|
|
||||||
|
// Transform vertices to XY and triangulate
|
||||||
|
triangulator.vertices.reserve(surface->verts.size());
|
||||||
|
|
||||||
|
for (const auto& vertex : surface->verts)
|
||||||
|
{
|
||||||
|
auto flattenedVertex = inverseProjection * vertex;
|
||||||
|
|
||||||
|
triangulator.vertices.emplace_back(flattenedVertex.x, flattenedVertex.y, nullptr);
|
||||||
|
|
||||||
|
if (triangulator.vertices.empty())
|
||||||
|
{
|
||||||
|
bounds = BBox(flattenedVertex, flattenedVertex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bounds.AddPoint(flattenedVertex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
triangulator.triangulate();
|
||||||
|
|
||||||
|
// Init misc. variables
|
||||||
|
boundsWidth = bounds.max.x - bounds.min.x;
|
||||||
|
boundsHeight = bounds.max.y - bounds.min.y;
|
||||||
|
|
||||||
|
offsetW = boundsWidth / sampleWidth;
|
||||||
|
offsetH = boundsHeight / sampleHeight;
|
||||||
|
|
||||||
|
tolerance = (offsetH > offsetW ? offsetH : offsetW) * 2.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SurfaceClip::SampleIsInBounds(float x, float y) const
|
||||||
|
{
|
||||||
|
const vec2 p = vec2((x / float(sampleWidth)) * boundsWidth + bounds.min.x + offsetW, (y / float(sampleHeight)) * boundsHeight + bounds.min.y + offsetH);
|
||||||
|
|
||||||
|
for (const auto& triangle : triangulator.triangles)
|
||||||
|
{
|
||||||
|
if (PointOnSide(p, *triangle.A, *triangle.B, tolerance)
|
||||||
|
&& PointOnSide(p, *triangle.B, *triangle.C, tolerance)
|
||||||
|
&& PointOnSide(p, *triangle.C, *triangle.A, tolerance))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
26
src/lightmap/surfaceclip.h
Normal file
26
src/lightmap/surfaceclip.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lightmap/levelmesh.h"
|
||||||
|
#include "math/mathlib.h"
|
||||||
|
#include "delauneytriangulator.h"
|
||||||
|
|
||||||
|
class SurfaceClip
|
||||||
|
{
|
||||||
|
DelauneyTriangulator triangulator;
|
||||||
|
|
||||||
|
float sampleWidth;
|
||||||
|
float sampleHeight;
|
||||||
|
|
||||||
|
BBox bounds;
|
||||||
|
float boundsWidth;
|
||||||
|
float boundsHeight;
|
||||||
|
float offsetW;
|
||||||
|
float offsetH;
|
||||||
|
float tolerance;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SurfaceClip(Surface* surface);
|
||||||
|
|
||||||
|
// Tolerates points close enough to the surface to avoid missing used samples
|
||||||
|
bool SampleIsInBounds(float x, float y) const;
|
||||||
|
};
|
Loading…
Reference in a new issue