Skip to content

Commit

Permalink
Refactor: Refactored the exception reporting mechanism in nova
Browse files Browse the repository at this point in the history
Previous exception management was relying on a mutable property in the manager class, now is replaced with a better design.

We now keep the resource management class reference and the exception management class reference as properties of the nova_eng_internals structures.
Only the exception_manager property is non const, as it relies on atomics to update error states, so the render process stays thread safe.
  • Loading branch information
HamilcarR committed Sep 19, 2024
1 parent 09c181b commit b673623
Show file tree
Hide file tree
Showing 24 changed files with 170 additions and 163 deletions.
51 changes: 23 additions & 28 deletions corelib/nova/DrawEngine.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
#include "DrawEngine.h"
#include "GenericException.h"
#include "integrator/Integrator.h"
#include "manager/NovaResourceManager.h"
#include "Logger.h"
#include "engine/nova_engine.h"






#include "integrator/Integrator.h"
#include "manager/NovaResourceManager.h"

namespace exception {
class InvalidThreadpoolStateException final : public GenericException {
Expand All @@ -33,30 +27,34 @@ namespace nova {
* 3) Final state : render at full depth , full sample size , full resolution.
* Allows proper synchronization.
*/
void NovaRenderEngineLR::engine_render_tile(HdrBufferStruct *buffers, Tile &tile, const NovaResourceManager *nova_resources) {
integrator::integrator_dispatch(buffers, tile, nova_resources);
void NovaRenderEngineLR::engine_render_tile(HdrBufferStruct *buffers, Tile &tile, nova::nova_eng_internals &nova_internals) {
integrator::integrator_dispatch(buffers, tile, nova_internals);
}

static bool validate(HdrBufferStruct *buffers,
const unsigned width_resolution,
const unsigned height_resolution,
NovaRenderEngineInterface *engine_instance,
threading::ThreadPool *thread_pool,
const NovaResourceManager *nova_resources) {
nova::nova_eng_internals &nova_internals) {

bool keep_rendering = true;
const NovaResourceManager *nova_resources = nova_internals.resource_manager;
NovaExceptionManager *nova_exception = nova_internals.exception_manager;
if (!nova_resources)
throw ::exception::InvalidResourceManagerStateException("Resource manager reference is invalid (nullptr).");
if (!nova_exception)
throw ::exception::InvalidResourceManagerStateException("Exception manager reference is invalid (nullptr).");
if (!engine_instance) {
nova_resources->addError(nova::exception::INVALID_ENGINE_INSTANCE);
nova_exception->addError(nova::exception::INVALID_ENGINE_INSTANCE);
keep_rendering = false;
}
if (width_resolution == 0 || height_resolution == 0 || width_resolution > 65536 || height_resolution > 65536) {
nova_resources->addError(nova::exception::INVALID_RENDERBUFFER_DIM);
nova_exception->addError(nova::exception::INVALID_RENDERBUFFER_DIM);
keep_rendering = false;
}
if (!buffers) {
nova_resources->addError(nova::exception::INVALID_RENDERBUFFER_STATE);
nova_exception->addError(nova::exception::INVALID_RENDERBUFFER_STATE);
keep_rendering = false;
}
if (!thread_pool)
Expand All @@ -69,36 +67,33 @@ namespace nova {
const unsigned height_resolution,
NovaRenderEngineInterface *engine_instance,
threading::ThreadPool *thread_pool,
const NovaResourceManager *nova_resources) {
nova::nova_eng_internals &nova_internals) {

AX_ASSERT(nova_resources != nullptr, "Scene descriptor is not initialized.");
try {
if (!validate(buffers, width_resolution, height_resolution, engine_instance, thread_pool, nova_resources))
if (!validate(buffers, width_resolution, height_resolution, engine_instance, thread_pool, nova_internals))
return {};
} catch (const ::exception::GenericException &e) {
throw;
}

std::vector<std::future<void>> futs;
std::vector<Tile> tiles = divideByTiles(
width_resolution, height_resolution, nova_resources->getEngineData().getTilesWidth(), nova_resources->getEngineData().getTilesHeight());
std::vector<Tile> tiles = divideByTiles(width_resolution,
height_resolution,
nova_internals.resource_manager->getEngineData().getTilesWidth(),
nova_internals.resource_manager->getEngineData().getTilesHeight());
for (auto &elem : tiles) {
auto renderer_callback = [engine_instance](HdrBufferStruct *buffers, Tile &tile, const NovaResourceManager *resrc) {
engine_instance->engine_render_tile(buffers, tile, resrc);
auto renderer_callback = [engine_instance](HdrBufferStruct *buffers, Tile &tile, nova::nova_eng_internals &nova_internals) {
engine_instance->engine_render_tile(buffers, tile, nova_internals);
};
elem.sample_per_tile = nova_resources->getEngineData().getSampleIncrement();
elem.sample_per_tile = nova_internals.resource_manager->getEngineData().getSampleIncrement();
elem.image_total_height = height_resolution;
elem.image_total_width = width_resolution;
const std::string &tag = nova_resources->getEngineData().getTag();
futs.push_back(thread_pool->addTask(tag, renderer_callback, buffers, elem, nova_resources));
const std::string &tag = nova_internals.resource_manager->getEngineData().getTag();
futs.push_back(thread_pool->addTask(tag, renderer_callback, buffers, elem, nova_internals));
}

return futs;
}






} // namespace nova
7 changes: 3 additions & 4 deletions corelib/nova/DrawEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,25 @@

namespace nova {


class NovaRenderEngineLR final : public NovaRenderEngineInterface {
public:
CLASS_OCM(NovaRenderEngineLR)

void engine_render_tile(HdrBufferStruct *dest_buffer, Tile &tile, const NovaResourceManager *nova_resources) override;
void engine_render_tile(HdrBufferStruct *dest_buffer, Tile &tile, nova::nova_eng_internals &nova_internals) override;
};

std::vector<std::future<void>> draw(HdrBufferStruct *buffers,
unsigned width_resolution,
unsigned height_resolution,
NovaRenderEngineInterface *engine_instance,
threading::ThreadPool *thread_pool,
const NovaResourceManager *nova_resources);
nova::nova_eng_internals &nova_internals);

void gpu_draw(HdrBufferStruct *buffers,
unsigned width_resolution,
unsigned height_resolution,
NovaRenderEngineInterface *engine_interface,
const NovaResourceManager *nova_resources_manager);
nova::nova_eng_internals &nova_internals);

} // namespace nova
#endif
15 changes: 5 additions & 10 deletions corelib/nova/DrawEngine_GPU.cpp
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
#include "DrawEngine.h"
#include "Logger.h"
#include "PerformanceLogger.h"
#include "device_utils.h"
#include "engine/nova_exception.h"
#include "integrator/Integrator.h"
#include "manager/NovaResourceManager.h"
#include "Logger.h"
#if defined(AXOMAE_USE_CUDA)
#include "gpu/gpu.cuh"
# include "gpu/gpu.cuh"
#endif

namespace nova {



void gpu_draw(HdrBufferStruct *buffers,
unsigned width_resolution,
unsigned height_resolution,
NovaRenderEngineInterface *engine_interface,
const NovaResourceManager *nova_resources_manager) {
nova::nova_eng_internals &nova_internal_structs) {
#if defined(AXOMAE_USE_CUDA)
launch_gpu_kernel(buffers, width_resolution, height_resolution, engine_interface, nova_resources_manager);
launch_gpu_kernel(buffers, width_resolution, height_resolution, engine_interface, nova_internal_structs);
#else
LOG("Application built without CUDA. Enable AXOMAE_USE_CUDA in build if GPU is compatible.", LogLevel::ERROR);
#endif
}
}



} // namespace nova
11 changes: 2 additions & 9 deletions corelib/nova/NovaInterface.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
#ifndef NOVAINTERFACE_H
#define NOVAINTERFACE_H
#include "camera/nova_camera.h"
#include "engine/nova_engine.h"
#include "ray/Ray.h"
#include "scene/nova_scene.h"
#include "texturing/nova_texturing.h"

#include <map>
#include "manager/ManagerInternalStructs.h"
namespace nova {
struct Tile;
class NovaResourceManager;
Expand All @@ -15,9 +10,7 @@ namespace nova {
class NovaRenderEngineInterface {
public:
virtual ~NovaRenderEngineInterface() = default;
virtual void engine_render_tile(nova::HdrBufferStruct *out_buffers, nova::Tile &tile, const nova::NovaResourceManager *nova_resources) = 0;
virtual void engine_render_tile(nova::HdrBufferStruct *out_buffers, nova::Tile &tile, nova::nova_eng_internals &internal_structs) = 0;
};



#endif // NOVAINTERFACE_H
28 changes: 14 additions & 14 deletions corelib/nova/gpu/gpu.cu
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
#include "CudaDevice.h"
#include "DrawEngine.h"
#include "gpu.cuh"
#include "Logger.h"
#include "PerformanceLogger.h"
#include "device_utils.h"
#include "kernel_launch_interface.h"
#include "engine/nova_exception.h"
#include "gpu.cuh"
#include "integrator/Integrator.h"
#include "kernel_launch_interface.h"
#include "manager/NovaResourceManager.h"
#include "Logger.h"
namespace nova {
namespace gpu {

AX_KERNEL void test_func(float *ptr, unsigned width, unsigned height, const NovaResourceManager *nova_resource_manager) {
AX_KERNEL void test_func(float *ptr, unsigned width, unsigned height, nova::nova_eng_internals &nova_internals) {
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
int idx = y * width + x;
if(idx < width * height)
ptr[idx] = 1.f ;
nova_resource_manager->addError(exception::INVALID_INTEGRATOR);
if (idx < width * height)
ptr[idx] = 1.f;
nova_internals.exception_manager->addError(exception::INVALID_INTEGRATOR);
}
}
} // namespace gpu
void launch_gpu_kernel(HdrBufferStruct *buffers,
unsigned width_resolution,
unsigned height_resolution,
NovaRenderEngineInterface *engine_interface,
const NovaResourceManager *nova_resources_manager) {
nova::nova_eng_internals &nova_internals) {

if (ax_cuda::utils::cuda_info_device().empty()) {
LOGS("No suitable gpu detected.");
nova_resources_manager->addError(nova::exception::GENERAL_GPU_ERROR);
nova_internals.exception_manager->addError(nova::exception::GENERAL_GPU_ERROR);
return;
}
ax_cuda::CudaDevice device;
Expand All @@ -38,21 +38,21 @@ namespace nova {
float *device_buffer = nullptr, *host_buffer = buffers->accumulator_buffer;
AXCUDA_ERROR_CHECK(device.GPUHostRegister(host_buffer, width_resolution * height_resolution * sizeof(float) * 4, cudaHostAllocMapped));
AXCUDA_ERROR_CHECK(device.GPUHostGetDevicePointer((void **)&device_buffer, host_buffer, 0));
AXCUDA_ERROR_CHECK(device.GPUMallocManaged((void **)&nova_resources_manager, sizeof(NovaResourceManager), params));
AXCUDA_ERROR_CHECK(device.GPUMallocManaged((void **)&nova_internals, sizeof(NovaResourceManager), params));

kernel_argpack_t argpack{};
argpack.num_blocks.x = 4;
argpack.num_blocks.y = 4;
argpack.block_size = {10, 1, 1};
PerformanceLogger perf;
perf.startTimer();
exec_kernel(argpack, gpu::test_func, host_buffer, width_resolution, height_resolution, nova_resources_manager);
exec_kernel(argpack, gpu::test_func, host_buffer, width_resolution, height_resolution, nova_internals);
AXCUDA_ERROR_CHECK(device.GPUDeviceSynchronize());
perf.endTimer();
perf.print();

AXCUDA_ERROR_CHECK(device.GPUHostUnregister(host_buffer));
AXCUDA_ERROR_CHECK(device.GPUFree((void *)nova_resources_manager));
AXCUDA_ERROR_CHECK(device.GPUFree((void *)&nova_internals));
}

}
} // namespace nova
7 changes: 3 additions & 4 deletions corelib/nova/gpu/gpu.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@
#define GPU_CUH
#include "device_utils.h"


namespace nova {

class NovaResourceManager;
namespace gpu {
AX_KERNEL void test_func(float *ptr, unsigned width, unsigned height, const NovaResourceManager *nova_resource_manager);
AX_KERNEL void test_func(float *ptr, unsigned width, unsigned height, nova::nova_eng_internals &nova_internals);
}

void launch_gpu_kernel(HdrBufferStruct *buffers,
unsigned width_resolution,
unsigned height_resolution,
NovaRenderEngineInterface *engine_interface,
const NovaResourceManager *nova_resources_manager);
}
nova::nova_eng_internals &nova_internals);
} // namespace nova

#endif
13 changes: 5 additions & 8 deletions corelib/nova/integrator/DepthIntegrator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ namespace nova::integrator {
static float normalize_depth(float z, float near, float far) { return (2.0f * near * far) / (far + near - z * (far - near)); }

/* same as regular integrators , but sample pixels without random deviation and sample loop*/
void DepthIntegrator::render(RenderBuffers<float> *buffers, Tile &tile, const NovaResourceManager *nova_resource_manager) const {
void DepthIntegrator::render(RenderBuffers<float> *buffers, Tile &tile, nova_eng_internals &nova_internals) const {
static std::mutex mutex;
const NovaResourceManager *nova_resource_manager = nova_internals.resource_manager;
const camera::CameraResourcesHolder &camera = nova_resource_manager->getCameraData();
float near = camera.getNear();
float far = camera.getFar();
Expand All @@ -29,8 +30,7 @@ namespace nova::integrator {
Ray ray(r.near, r.far);
sampler::RandomSampler random_sampler = sampler::RandomSampler();
sampler::SamplerInterface sampler = &random_sampler;
glm::vec4 distance = Li(ray, nova_resource_manager, 0, sampler);

glm::vec4 distance = Li(ray, nova_internals, 0, sampler);
float depth = 1 - (distance.x - near) / (far - near);
depth = normalize_depth(depth, near, far) * 2.f - 1.f;
glm::vec3 rgb{depth / far};
Expand All @@ -49,11 +49,8 @@ namespace nova::integrator {
}

/* returns closest primitive distance (intersection) , and farthest primitive distance*/
glm::vec4 DepthIntegrator::Li(const Ray &ray,
const NovaResourceManager *nova_resources,
int /*depth*/,
sampler::SamplerInterface & /*sampler*/) const {
bvh_hit_data hit = bvh_hit(ray, nova_resources);
glm::vec4 DepthIntegrator::Li(const Ray &ray, nova_eng_internals &nova_internals, int /*depth*/, sampler::SamplerInterface & /*sampler*/) const {
bvh_hit_data hit = bvh_hit(ray, nova_internals);
if (hit.is_hit) {
glm::vec3 min_max_intersect{hit.hit_d.t, hit.prim_max_t, MAXFLOAT};
return {min_max_intersect, 1.f};
Expand Down
7 changes: 2 additions & 5 deletions corelib/nova/integrator/DepthIntegrator.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@
namespace nova::integrator {
class DepthIntegrator : public AbstractIntegrator<DepthIntegrator> {
public:
void render(RenderBuffers<float> *buffers, Tile &tile, const NovaResourceManager *nova_resource_manager) const;
[[nodiscard]] glm::vec4 Li(const Ray &ray,
const NovaResourceManager *nova_resource_manager,
int depth,
sampler::SamplerInterface &sampler) const;
void render(RenderBuffers<float> *buffers, Tile &tile, nova_eng_internals &nova_internals) const;
[[nodiscard]] glm::vec4 Li(const Ray &ray, nova_eng_internals &nova_internals, int depth, sampler::SamplerInterface &sampler) const;
};
} // namespace nova::integrator

Expand Down
Loading

0 comments on commit b673623

Please sign in to comment.