Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ services:
container_name: prometheus
ports:
- "9090:9090"
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- ./prometheus-config.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
Expand Down
7 changes: 6 additions & 1 deletion prometheus-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@ scrape_configs:
- job_name: "fastapi"
metrics_path: /metrics
static_configs:
- targets: ["backend:8000"]
- targets: ["backend:8000"]

- job_name: "renderer"
metrics_path: /metrics
static_configs:
- targets: ["host.docker.internal:9092"]
1 change: 0 additions & 1 deletion renderer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,5 @@ if(BUILD_WORKER)
endif()

if(BUILD_TESTS)
message(STATUS "Building tests")
add_subdirectory(tests)
endif()
5 changes: 4 additions & 1 deletion renderer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ docker run --rm renderer renderer_cli <width> <height> <samples> <input_scene> [
| `-c, --camera` | `vec3 vec3 float` | Set camera: `position lookAt fov` |
| `-B, --background` | `vec3` | Set background color (default: vec3(0,0,0)) |
| `-S, --sun` | `vec3 vec3 float` | Set sun: `color direction exponent` |
| `-M, --metrics` | `-` | Shows rendering statistics |;

---

Expand Down Expand Up @@ -331,7 +332,9 @@ docker run --rm --entrypoint /bin/sh renderer -c "cd build/tests && ctest --outp
```bash
cd renderer
mkdir build && cd build
cmake .. -DBUILD_MODE=CORE
cmake .. -DBUILD_MODE=CORE -DBUILD_TESTS=ON
cmake --build .
cd tests
ctest --output-on-failure
./test
```
58 changes: 57 additions & 1 deletion renderer/cli/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "context-guard.hpp"
#include "logger.hpp"
#include "metrics.hpp"
#include "render-engine.hpp"
#include "scene-loader.hpp"
#include "scene.hpp"
Expand All @@ -30,6 +31,7 @@ void printHelp(std::string_view programName) {
std::println(" -c, --camera Set camera properties: origin, direction, fov");
std::println(" -B, --background Set background color (default: vec3(0,0,0))");
std::println(" -S, --sun Set sun properties: color, direction, exponent");
std::println(" -M, --metrics Shows rendering statistics");
}

void printUsage(std::string_view programName) {
Expand Down Expand Up @@ -74,6 +76,7 @@ int main(int argc, char* argv[]) {
bool cameraSet = false;
bool sunSet = false;
Scene::Sun sun;
bool showMetrics = false;

for (int i = 5; i < argc; i++) {
std::string arg = argv[i];
Expand All @@ -84,6 +87,8 @@ int main(int argc, char* argv[]) {
logger.showDebug = true;
else if (arg == "-d" || arg == "--debug")
debugImages = true;
else if (arg == "-M" || arg == "--metrics")
showMetrics = true;
else if (arg == "-o" || arg == "--output") {
if (i + 1 == argc) {
std::println(std::cerr, "Error: {} requires an argument", arg);
Expand Down Expand Up @@ -174,7 +179,8 @@ int main(int argc, char* argv[]) {
if (cameraSet) scene.setCamera(userCamera);
if (sunSet) scene.setSun(sun);
std::shared_ptr<RenderTarget> egl = TargetManager::getInstance().createEGLTarget(width, height);
engine.renderFrame(*egl, scene, samples);
Metrics metrics;
engine.renderFrame(*egl, scene, samples, metrics);

auto* eglTarget = dynamic_cast<EglTarget*>(egl.get());
if (eglTarget) {
Expand Down Expand Up @@ -203,6 +209,56 @@ int main(int argc, char* argv[]) {
absoluteDirectoryPath / (outputFilename + "-heat.png"));
}
}
if (showMetrics) {
auto line = [](std::string_view label, auto&& value, std::string_view unit = "") {
std::println(" {:<18}{:>10} {}", label, value, unit);
};
auto timeLine = [&](std::string_view label, const std::optional<std::chrono::milliseconds>& t) {
if (!t) return;
std::string pct;
if (metrics.totalTime && metrics.totalTime->count() > 0) {
const double p = 100.0 * t->count() / metrics.totalTime->count();
pct = std::format(" ({:>5.1f}%)", p);
}
std::println(" {:<18}{:>8} ms{}", label, t->count(), pct);
};

std::println("\nRender statistics");
std::println("─────────────────────────────────────────");

bool anyImage = metrics.width || metrics.height || metrics.samples;
if (anyImage) {
std::println("[ Image ]");
if (metrics.width && metrics.height)
std::println(" {:<18}{:>5} x {:<5}", "Resolution", *metrics.width, *metrics.height);
if (metrics.samples) line("Samples", *metrics.samples);
}

if (metrics.polygonsCount || metrics.texturesCount) {
if (anyImage) std::println();
std::println("[ Scene ]");
if (metrics.polygonsCount) line("Polygons", *metrics.polygonsCount);
if (metrics.texturesCount) line("Textures", *metrics.texturesCount);
}

bool anyTime = metrics.BVHBuildingTime || metrics.pathTracingTime || metrics.gbufferFillingTime ||
metrics.postProcessingTime || metrics.denoisingTime || metrics.upscalingTime;
if (anyTime) {
if (anyImage || metrics.polygonsCount || metrics.texturesCount) std::println();
std::println("[ Timings ]");
timeLine("BVH building", metrics.BVHBuildingTime);
timeLine("Path tracing", metrics.pathTracingTime);
timeLine("G-buffer", metrics.gbufferFillingTime);
timeLine("Denoising", metrics.denoisingTime);
timeLine("Post-processing", metrics.postProcessingTime);
timeLine("Upscaling", metrics.upscalingTime);
}

if (metrics.totalTime) {
std::println("─────────────────────────────────────────");
std::println(" {:<18}{:>8} ms", "Total", metrics.totalTime->count());
}
}
logger.info("Renderer application stopped successfully");
return EXIT_SUCCESS;
} catch (const std::exception& e) {
Expand Down
18 changes: 18 additions & 0 deletions renderer/common/include/metrics.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once
#include <chrono>

struct Metrics {
std::optional<std::chrono::milliseconds> pathTracingTime;
std::optional<std::chrono::milliseconds> gbufferFillingTime;
std::optional<std::chrono::milliseconds> postProcessingTime;
std::optional<std::chrono::milliseconds> BVHBuildingTime;
std::optional<std::chrono::milliseconds> upscalingTime;
std::optional<std::chrono::milliseconds> denoisingTime;
std::optional<std::chrono::milliseconds> totalTime;
std::optional<size_t> polygonsCount;
std::optional<size_t> texturesCount;
std::optional<size_t> width;
std::optional<size_t> height;
std::optional<size_t> samples;
std::optional<bool> renderingSuccess;
};
11 changes: 7 additions & 4 deletions renderer/core/include/render-engine.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#pragma once
#include <glad/gl.h>

#include <atomic>
#include <metrics.hpp>
#include <optional>
#include <random>
#include <thread>

#include "bvh-builder.hpp"
#include "bvh.hpp"
Expand Down Expand Up @@ -59,16 +61,17 @@ class RenderEngine {

public:
RenderEngine();
void renderFrame(RenderTarget& target, const Scene& scene, int samples, Metrics& metrics);
void renderFrame(RenderTarget& target, const Scene& scene, int samples);
void destroy();
std::atomic<bool> stopRequested{false};
~RenderEngine();

private:
void pathTracing(RenderTarget& target, const Scene::Camera& camera, const glm::vec3& backgroundColor,
const Scene::Sun& sun, int samples);
void fillGbuffer(RenderTarget& target, const GPUData& gpuData, const Scene::Camera& camera);
void postProcess(RenderTarget& target) const;
const Scene::Sun& sun, int samples, Metrics& metrics);
void fillGbuffer(RenderTarget& target, const GPUData& gpuData, const Scene::Camera& camera, Metrics& metrics);
void postProcess(RenderTarget& target, Metrics& metrics) const;
void uploadGPUBuffers(const GPUData& gpuData, const BVH& bvh);
GLuint compileShader(const std::string& source);
void loadTextures(const std::vector<Scene::TextureData>& textures);
Expand Down
39 changes: 33 additions & 6 deletions renderer/core/src/render-engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ GLuint RenderEngine::compileShader(const std::string& source) {
}

void RenderEngine::pathTracing(RenderTarget& target, const Scene::Camera& camera, const glm::vec3& backgroundColor,
const Scene::Sun& sun, int samples) {
const Scene::Sun& sun, int samples, Metrics& metrics) {
logger.info("Path tracing started");

glUseProgram(pathTracingProgram);
Expand Down Expand Up @@ -231,12 +231,14 @@ void RenderEngine::pathTracing(RenderTarget& target, const Scene::Camera& camera
}
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
metrics.pathTracingTime = duration;
logger.info(std::format("Path tracing finished in {}ms", duration.count()));

glUseProgram(0);
}

void RenderEngine::fillGbuffer(RenderTarget& target, const GPUData& gpuData, const Scene::Camera& camera) {
void RenderEngine::fillGbuffer(RenderTarget& target, const GPUData& gpuData, const Scene::Camera& camera,
Metrics& metrics) {
logger.debug("Filling gbuffer");
glUseProgram(gbufferProgram);
glBindImageTexture(0, target.getNormalMap(), 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
Expand Down Expand Up @@ -266,11 +268,12 @@ void RenderEngine::fillGbuffer(RenderTarget& target, const GPUData& gpuData, con
glFinish();
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
metrics.gbufferFillingTime = duration;
logger.debug(std::format("gbuffer filling finished in {}ms", duration.count()));
glUseProgram(0);
}

void RenderEngine::postProcess(RenderTarget& target) const {
void RenderEngine::postProcess(RenderTarget& target, Metrics& metrics) const {
logger.info("Post processing started");
glUseProgram(postProcessingProgram);
glBindImageTexture(0, target.getDenoisedTexture(), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
Expand All @@ -288,6 +291,7 @@ void RenderEngine::postProcess(RenderTarget& target) const {
glFinish();
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
metrics.postProcessingTime = duration;
logger.info(std::format("Post processing finished in {}ms", duration.count()));
glUseProgram(0);
}
Expand Down Expand Up @@ -427,7 +431,17 @@ void RenderEngine::loadTextures(const std::vector<Scene::TextureData>& textures)
}

void RenderEngine::renderFrame(RenderTarget& target, const Scene& scene, int samples) {
Metrics metrics;
renderFrame(target, scene, samples, metrics);
}

void RenderEngine::renderFrame(RenderTarget& target, const Scene& scene, int samples, Metrics& metrics) {
try {
metrics.samples = samples;
metrics.width = target.getWidth();
metrics.height = target.getHeight();

auto toatalRenderingTimeStart = std::chrono::steady_clock::now();
logger.info(std::format("Rendering started ({}x{})", target.getWidth(), target.getHeight()));
ContextGuard context(target);
glClearTexImage(target.getRawTexture(), 0, GL_RGBA, GL_FLOAT, nullptr);
Expand All @@ -437,7 +451,12 @@ void RenderEngine::renderFrame(RenderTarget& target, const Scene& scene, int sam
GPUData gpuData = convertSceneToGPUData(scene);
BVH bvh;
try {
auto start = std::chrono::steady_clock::now();
bvh = std::move(bvhBuilder.build(gpuData.vertices, gpuData.vertexIndices));
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
metrics.BVHBuildingTime = duration;

} catch (const std::exception& e) {
logger.error(std::format("BVH building failed: {}", e.what()));
throw;
Expand All @@ -449,21 +468,23 @@ void RenderEngine::renderFrame(RenderTarget& target, const Scene& scene, int sam
return;
}
loadTextures(scene.getTexturesData());
metrics.texturesCount = scene.getTexturesData().size();
uploadGPUBuffers(gpuData, bvh);
metrics.polygonsCount = gpuData.vertexIndices.size() / 3;
if (stopRequested.load(std::memory_order_relaxed)) {
stopRequested = false;
logger.info("Rendering stopped");
return;
}
auto sun = scene.getSun();
sun.direction = glm::normalize(sun.direction);
pathTracing(target, camera, scene.getBackgroundColor(), sun, samples);
pathTracing(target, camera, scene.getBackgroundColor(), sun, samples, metrics);
if (stopRequested.load(std::memory_order_relaxed)) {
stopRequested = false;
logger.info("Rendering stopped");
return;
}
fillGbuffer(target, gpuData, camera);
fillGbuffer(target, gpuData, camera, metrics);
if (stopRequested.load(std::memory_order_relaxed)) {
stopRequested = false;
logger.info("Rendering stopped");
Expand All @@ -474,14 +495,20 @@ void RenderEngine::renderFrame(RenderTarget& target, const Scene& scene, int sam
denoiser.denoise(target);
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
metrics.denoisingTime = duration;
logger.info(std::format("Denoising finished in {}ms", duration.count()));
if (stopRequested.load(std::memory_order_relaxed)) {
stopRequested = false;
logger.info("Rendering stopped");
return;
}
postProcess(target);
postProcess(target, metrics);
auto toatalRenderingTimeEnd = std::chrono::steady_clock::now();
metrics.totalTime =
std::chrono::duration_cast<std::chrono::milliseconds>(toatalRenderingTimeEnd - toatalRenderingTimeStart);
metrics.renderingSuccess = true;
} catch (const std::exception& e) {
metrics.renderingSuccess = false;
logger.error(std::format("Rendering failed. Reason: {}", e.what()));
throw;
}
Expand Down
1 change: 1 addition & 0 deletions renderer/worker/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ add_executable(service
src/s3-client.cpp
src/dotenv.cpp
src/config.cpp
src/prometheus.cpp
)

target_include_directories(service PRIVATE
Expand Down
2 changes: 2 additions & 0 deletions renderer/worker/include/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class Config {
std::optional<std::string> kafkaTopicOutput_;
std::optional<std::string> kafkaTopicDLQ_;
std::optional<std::string> kafkaTopicCommands_;
std::optional<std::string> prometheusHost_;
int maxRetries_ = 5; // default
std::optional<std::string> s3Host_;
std::optional<std::string> s3AccessKey_;
Expand All @@ -29,6 +30,7 @@ class Config {
void fromEnvironment();

std::string kafkaHost() const;
std::string prometheusHost() const;
std::string kafkaTasksGroupID() const;
std::string kafkaCommandsGroupId() const;
std::string kafkaTopicTasks() const;
Expand Down
2 changes: 2 additions & 0 deletions renderer/worker/include/contract.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "metrics.hpp"

struct TaskHeader {
int width;
Expand All @@ -15,4 +16,5 @@ struct TaskHeader {

struct ResultHeader {
unsigned long long resultDataSize;
Metrics metrics;
};
Loading
Loading