Add SchedulerBenchmark test
This commit is contained in:
parent
7f1ef0fe41
commit
56751072f5
|
|
@ -0,0 +1,113 @@
|
|||
#include <Nazara/Core/Clock.hpp>
|
||||
#include <Nazara/Core/Core.hpp>
|
||||
#include <Nazara/Core/TaskScheduler.hpp>
|
||||
#include <Nazara/Utility/Image.hpp>
|
||||
#include <Nazara/Utility/Utility.hpp>
|
||||
#include "task.hpp"
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
|
||||
int main()
|
||||
{
|
||||
Nz::Modules<Nz::Utility> core;
|
||||
|
||||
constexpr unsigned int imageDimensions = 4096; // Will produce imageDimensions² rays
|
||||
constexpr unsigned int tileSize = 128;
|
||||
|
||||
std::minstd_rand randEngine(std::random_device{}());
|
||||
std::uniform_real_distribution<float> posDis(-1.f, 1.f);
|
||||
std::uniform_real_distribution<float> velDis(-10.f, 10.f);
|
||||
|
||||
Nz::TaskScheduler taskScheduler;
|
||||
|
||||
std::cout << "Initializing..." << std::endl;
|
||||
|
||||
// from https://raytracing.github.io/books/RayTracingInOneWeekend.html
|
||||
double focalLength = 1.0;
|
||||
double viewportHeight = 2.0;
|
||||
double viewportWidth = viewportHeight * (static_cast<double>(imageDimensions) / imageDimensions);
|
||||
Nz::Vector3d cameraCenter = Nz::Vector3d::Zero();
|
||||
|
||||
Nz::Vector3d viewportU = Nz::Vector3d(viewportWidth, 0, 0);
|
||||
Nz::Vector3d viewportV = Nz::Vector3d(0, -viewportHeight, 0);
|
||||
Nz::Vector3d viewportUpperLeft = cameraCenter - Nz::Vector3d(0, 0, focalLength) - viewportU / 2 - viewportV / 2;
|
||||
|
||||
SceneData sceneData;
|
||||
sceneData.imageSize = imageDimensions;
|
||||
sceneData.pixels = std::make_unique<PixelColor[]>(imageDimensions * imageDimensions * 3);
|
||||
sceneData.pixelDeltaU = viewportU / imageDimensions;
|
||||
sceneData.pixelDeltaV = viewportV / imageDimensions;
|
||||
sceneData.originPos = viewportUpperLeft + 0.5 * (sceneData.pixelDeltaU + sceneData.pixelDeltaV);
|
||||
sceneData.cameraPos = cameraCenter;
|
||||
sceneData.spheres.push_back(Nz::Sphered(Nz::Vector3d(-1.5, 0.5, -10.0), 0.5));
|
||||
sceneData.spheres.push_back(Nz::Sphered(Nz::Vector3d(0.0, 0.75, -2.5), 0.75));
|
||||
sceneData.spheres.push_back(Nz::Sphered(Nz::Vector3d(1.5, 0.5, -10.0), 0.5));
|
||||
|
||||
std::cout << "Warming up..." << std::endl;
|
||||
RayCast(sceneData, Nz::Vector2ui(0, 0), Nz::Vector2ui(imageDimensions, imageDimensions));
|
||||
|
||||
std::cout << "Measuring mono-threaded..." << std::endl;
|
||||
|
||||
Nz::Time t1 = Nz::GetElapsedNanoseconds();
|
||||
RayCast(sceneData, Nz::Vector2ui(0, 0), Nz::Vector2ui(imageDimensions, imageDimensions));
|
||||
Nz::Time t2 = Nz::GetElapsedNanoseconds();
|
||||
|
||||
std::cout << "Mono-threaded update time: " << (t2 - t1) << std::endl;
|
||||
|
||||
std::cout << "Measuring task-scheduler..." << std::endl;
|
||||
|
||||
unsigned int boxCount = imageDimensions / tileSize;
|
||||
if (imageDimensions % tileSize != 0)
|
||||
boxCount++;
|
||||
|
||||
std::vector<std::pair<Nz::Vector2ui, Nz::Vector2ui>> boxes(boxCount * boxCount);
|
||||
for (unsigned int i = 0; i < boxes.size(); ++i)
|
||||
{
|
||||
unsigned int x = i % boxCount;
|
||||
unsigned int y = i % boxCount;
|
||||
|
||||
Nz::Vector2ui mins(x * tileSize, y * tileSize);
|
||||
Nz::Vector2ui maxs = mins + Nz::Vector2ui(tileSize);
|
||||
maxs.Minimize(Nz::Vector2ui(imageDimensions));
|
||||
|
||||
Nz::Vector2ui dims = maxs - mins;
|
||||
boxes[i] = std::make_pair(mins, dims);
|
||||
}
|
||||
|
||||
Nz::Time t3 = Nz::GetElapsedNanoseconds();
|
||||
std::atomic_uint64_t acc = 0;
|
||||
std::atomic_uint boxCountAcc = 0;
|
||||
std::atomic_uint threadCounter = 0;
|
||||
|
||||
for (auto&& [offset, dims] : boxes)
|
||||
{
|
||||
taskScheduler.AddTask([&, offset, dims]
|
||||
{
|
||||
thread_local std::size_t threadId = ++threadCounter;
|
||||
|
||||
Nz::Time taskStart = Nz::GetElapsedNanoseconds();
|
||||
RayCast(sceneData, offset, dims);
|
||||
Nz::Time taskEnd = Nz::GetElapsedNanoseconds();
|
||||
|
||||
acc += (taskEnd - taskStart).AsNanoseconds();
|
||||
boxCountAcc++;
|
||||
});
|
||||
}
|
||||
taskScheduler.WaitForTasks();
|
||||
|
||||
Nz::Time t4 = Nz::GetElapsedNanoseconds();
|
||||
|
||||
Nz::Time taskSchedulerTime = t4 - t3;
|
||||
std::cout << "task-scheduler update time: " << taskSchedulerTime << std::endl;
|
||||
std::cout << "accumulated task time: " << Nz::Time::Nanoseconds(acc) << std::endl;
|
||||
std::cout << "difference: " << taskSchedulerTime - Nz::Time::Nanoseconds(acc) << std::endl;
|
||||
std::cout << "thread count: " << threadCounter << std::endl;
|
||||
std::cout << "box count: " << boxCountAcc << std::endl;
|
||||
|
||||
static_assert(sizeof(PixelColor) == 3 * sizeof(Nz::UInt8));
|
||||
|
||||
Nz::Image image(Nz::ImageType::E2D, Nz::PixelFormat::RGB8, imageDimensions, imageDimensions);
|
||||
image.Update(sceneData.pixels.get());
|
||||
image.SaveToFile(Nz::Utf8Path("raycast_test.png"));
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
#include "task.hpp"
|
||||
#include <Nazara/Core/Color.hpp>
|
||||
#include <Nazara/Math/Ray.hpp>
|
||||
|
||||
|
||||
bool HitSphere(const Nz::Vector3d& center, double radius, const Nz::Rayd& r)
|
||||
{
|
||||
Nz::Vector3d oc = r.origin - center;
|
||||
double a = Nz::Vector3d::DotProduct(r.direction, r.direction);
|
||||
double b = 2.0 * Nz::Vector3d::DotProduct(oc, r.direction);
|
||||
double c = Nz::Vector3d::DotProduct(oc, oc) - radius * radius;
|
||||
double discriminant = b * b - 4 * a * c;
|
||||
return (discriminant >= 0);
|
||||
}
|
||||
|
||||
Nz::Color RayColor(const SceneData& sceneData, const Nz::Rayd& r)
|
||||
{
|
||||
double closestHit = std::numeric_limits<double>::infinity();
|
||||
const Nz::Sphered* closestSphere = nullptr;
|
||||
for (const Nz::Sphered& sphere : sceneData.spheres)
|
||||
{
|
||||
double t;
|
||||
if (r.Intersect(sphere, &t, nullptr) && t < closestHit)
|
||||
{
|
||||
closestHit = t;
|
||||
closestSphere = &sphere;
|
||||
}
|
||||
}
|
||||
|
||||
if (closestSphere)
|
||||
{
|
||||
Nz::Vector3d hitPos = r.GetPoint(closestHit);
|
||||
Nz::Vector3d hitNormal = Nz::Vector3d::Normalize(hitPos - closestSphere->GetPosition());
|
||||
Nz::Vector3d normalAsColor = (hitNormal + Nz::Vector3d(1.0)) / 2.0;
|
||||
return Nz::Color((float) normalAsColor.x, (float)normalAsColor.y, (float)normalAsColor.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
Nz::Vector3d unitDirection = Nz::Vector3d::Normalize(r.direction);
|
||||
double a = 0.5 * (unitDirection.y + 1.0);
|
||||
return (1.0 - a) * Nz::Color(1.0, 1.0, 1.0) + a * Nz::Color(0.5, 0.7, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
void RayCast(SceneData& sceneData, const Nz::Vector2ui& origin, const Nz::Vector2ui& dims)
|
||||
{
|
||||
for (std::size_t j = 0; j < dims.y; ++j)
|
||||
{
|
||||
std::size_t y = origin.y + j;
|
||||
for (std::size_t i = 0; i < dims.x; ++i)
|
||||
{
|
||||
std::size_t x = origin.x + i;
|
||||
Nz::Vector3d pixelCenter = sceneData.originPos + (double(x) * sceneData.pixelDeltaU) + (double(y) * sceneData.pixelDeltaV);
|
||||
Nz::Vector3d rayDirection = pixelCenter - sceneData.cameraPos;
|
||||
Nz::Rayd ray(sceneData.cameraPos, rayDirection);
|
||||
Nz::Color color = RayColor(sceneData, ray);
|
||||
|
||||
PixelColor& pixelColor = sceneData.pixels[y * sceneData.imageSize + x];
|
||||
color.ToRGB8(color, &pixelColor.r, &pixelColor.g, &pixelColor.b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#include <Nazara/Math/Sphere.hpp>
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
#include <memory>
|
||||
|
||||
// Don't use Nz::Color as it's 4 floats and may get us memory-bound
|
||||
struct PixelColor
|
||||
{
|
||||
Nz::UInt8 r, g, b;
|
||||
};
|
||||
|
||||
struct SceneData
|
||||
{
|
||||
std::size_t imageSize;
|
||||
std::unique_ptr<PixelColor[]> pixels;
|
||||
std::vector<Nz::Sphered> spheres;
|
||||
Nz::Vector3d cameraPos;
|
||||
Nz::Vector3d originPos;
|
||||
Nz::Vector3d pixelDeltaU;
|
||||
Nz::Vector3d pixelDeltaV;
|
||||
};
|
||||
|
||||
void RayCast(SceneData& sceneData, const Nz::Vector2ui& origin, const Nz::Vector2ui& dims);
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
target("SchedulerBenchmark")
|
||||
add_deps("NazaraCore", "NazaraUtility")
|
||||
add_files("main.cpp")
|
||||
add_headerfiles("task.hpp")
|
||||
add_files("task.cpp")
|
||||
Loading…
Reference in New Issue