From cf8775a77e7199460fd082f791f8b70c553cb462 Mon Sep 17 00:00:00 2001 From: David Sleeper Date: Wed, 1 Jun 2022 10:35:58 -0400 Subject: [PATCH 1/2] - thread and image write --- src/InOneWeekend/main.cc | 97 ++++++++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 13 deletions(-) diff --git a/src/InOneWeekend/main.cc b/src/InOneWeekend/main.cc index 86576d345..d6abaf58c 100644 --- a/src/InOneWeekend/main.cc +++ b/src/InOneWeekend/main.cc @@ -18,9 +18,14 @@ #include "sphere.h" #include +#include +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "external/stb_image_write.h" -color ray_color(const ray& r, const hittable& world, int depth) { + +color ray_color(const ray& r, const hittable& world, int depth) +{ hit_record rec; // If we've exceeded the ray bounce limit, no more light is gathered. @@ -87,6 +92,44 @@ hittable_list random_scene() { return world; } +struct SimpleRGB +{ + uint8_t r; + uint8_t g; + uint8_t b; +}; + + +void write_simple_color(SimpleRGB& outColor, color pixel_color, int samples_per_pixel) +{ + auto r = pixel_color.x(); + auto g = pixel_color.y(); + auto b = pixel_color.z(); + + // Replace NaN components with zero. See explanation in Ray Tracing: The Rest of Your Life. + if (r != r) r = 0.0; + if (g != g) g = 0.0; + if (b != b) b = 0.0; + + // Divide the color by the number of samples and gamma-correct for gamma=2.0. + auto scale = 1.0 / samples_per_pixel; + r = sqrt(scale * r); + g = sqrt(scale * g); + b = sqrt(scale * b); + + outColor.r = static_cast(256 * clamp(r, 0.0, 0.999)); + outColor.g = static_cast(256 * clamp(g, 0.0, 0.999)); + outColor.b = static_cast(256 * clamp(b, 0.0, 0.999)); +} + +void Renderer(std::atomic_uint32_t &ScanLine, + int32_t image_height, + int32_t image_width, + int32_t samples_per_pixel, + std::vector< SimpleRGB > &colors) +{ + +} int main() { @@ -98,6 +141,9 @@ int main() { const int samples_per_pixel = 10; const int max_depth = 50; + std::vector< SimpleRGB > colors; + colors.resize(image_width * image_height); + // World auto world = random_scene(); @@ -113,22 +159,47 @@ int main() { camera cam(lookfrom, lookat, vup, 20, aspect_ratio, aperture, dist_to_focus); // Render - std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n"; - for (int j = image_height-1; j >= 0; --j) { - std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush; - for (int i = 0; i < image_width; ++i) { - color pixel_color(0,0,0); - for (int s = 0; s < samples_per_pixel; ++s) { - auto u = (i + random_double()) / (image_width-1); - auto v = (j + random_double()) / (image_height-1); - ray r = cam.get_ray(u, v); - pixel_color += ray_color(r, world, max_depth); + std::atomic_uint32_t ScanLine = 0; + + auto runThread = [&]() { + while (true) + { + auto currentLine = ScanLine.fetch_add(1); + if (currentLine >= image_height) + { + return; + } + auto actualLine = image_height - currentLine - 1; + std::cerr << "\rScanlines remaining: " << actualLine << std::endl;// << ' ' << std::flush; + for (int i = 0; i < image_width; ++i) { + color pixel_color(0, 0, 0); + for (int s = 0; s < samples_per_pixel; ++s) { + auto u = (i + random_double()) / (image_width - 1); + auto v = (currentLine + random_double()) / (image_height - 1); + ray r = cam.get_ray(u, v); + pixel_color += ray_color(r, world, max_depth); + } + uint32_t Idx = (actualLine * image_width) + i; + write_simple_color(colors[Idx], pixel_color, samples_per_pixel); } - write_color(std::cout, pixel_color, samples_per_pixel); } - } + }; + + const auto threadCount = std::max( std::thread::hardware_concurrency() - 1, 2 ); + + std::vector my_threads{}; + my_threads.reserve(threadCount); + + for (int i = 0; i < threadCount; i++) + my_threads.emplace_back(runThread); + + for (auto& thread : my_threads) + if (thread.joinable()) + thread.join(); + + stbi_write_bmp("test.bmp", image_width, image_height, 3, colors.data()); std::cerr << "\nDone.\n"; } From ad9329db149540f353ac8252bc99f576b30f8a87 Mon Sep 17 00:00:00 2001 From: David Sleeper Date: Wed, 1 Jun 2022 10:48:07 -0400 Subject: [PATCH 2/2] - various updates --- src/TheRestOfYourLife/main.cc | 88 ++++++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 12 deletions(-) diff --git a/src/TheRestOfYourLife/main.cc b/src/TheRestOfYourLife/main.cc index 6faa549ad..2703475aa 100644 --- a/src/TheRestOfYourLife/main.cc +++ b/src/TheRestOfYourLife/main.cc @@ -22,6 +22,11 @@ #include +#include + +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "external/stb_image_write.h" + color ray_color( const ray& r, const color& background, @@ -89,6 +94,35 @@ hittable_list cornell_box() { return objects; } +struct SimpleRGB +{ + uint8_t r; + uint8_t g; + uint8_t b; +}; + +void write_simple_color(SimpleRGB& outColor, color pixel_color, int samples_per_pixel) +{ + auto r = pixel_color.x(); + auto g = pixel_color.y(); + auto b = pixel_color.z(); + + // Replace NaN components with zero. See explanation in Ray Tracing: The Rest of Your Life. + if (!std::isfinite(r)) r = 0.0; + if (!std::isfinite(g)) g = 0.0; + if (!std::isfinite(b)) b = 0.0; + + // Divide the color by the number of samples and gamma-correct for gamma=2.0. + auto scale = 1.0 / samples_per_pixel; + r = sqrt(scale * r); + g = sqrt(scale * g); + b = sqrt(scale * b); + + outColor.r = static_cast(256 * clamp(r, 0.0, 0.999)); + outColor.g = static_cast(256 * clamp(g, 0.0, 0.999)); + outColor.b = static_cast(256 * clamp(b, 0.0, 0.999)); +} + int main() { // Image @@ -99,6 +133,10 @@ int main() { const int samples_per_pixel = 100; const int max_depth = 50; + + std::vector< SimpleRGB > colors; + colors.resize(image_width * image_height); + // World auto lights = make_shared(); @@ -125,20 +163,46 @@ int main() { // Render std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n"; - - for (int j = image_height-1; j >= 0; --j) { - std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush; - for (int i = 0; i < image_width; ++i) { - color pixel_color(0,0,0); - for (int s = 0; s < samples_per_pixel; ++s) { - auto u = (i + random_double()) / (image_width-1); - auto v = (j + random_double()) / (image_height-1); - ray r = cam.get_ray(u, v); - pixel_color += ray_color(r, background, world, lights, max_depth); + + std::atomic_uint32_t ScanLine = 0; + + auto runThread = [&]() { + while (true) + { + auto currentLine = ScanLine.fetch_add(1); + if (currentLine >= image_height) + { + return; + } + auto actualLine = image_height - currentLine - 1; + std::cerr << "\rScanlines remaining: " << actualLine << std::endl;// << ' ' << std::flush; + for (int i = 0; i < image_width; ++i) { + color pixel_color(0, 0, 0); + for (int s = 0; s < samples_per_pixel; ++s) { + auto u = (i + random_double()) / (image_width - 1); + auto v = (currentLine + random_double()) / (image_height - 1); + ray r = cam.get_ray(u, v); + pixel_color += ray_color(r, background, world, lights, max_depth); + } + uint32_t Idx = (actualLine * image_width) + i; + write_simple_color(colors[Idx], pixel_color, samples_per_pixel); } - write_color(std::cout, pixel_color, samples_per_pixel); } - } + }; + + const auto threadCount = std::max(std::thread::hardware_concurrency() - 1, 2); + + std::vector my_threads{}; + my_threads.reserve(threadCount); + + for (int i = 0; i < threadCount; i++) + my_threads.emplace_back(runThread); + + for (auto& thread : my_threads) + if (thread.joinable()) + thread.join(); + + stbi_write_bmp("test.bmp", image_width, image_height, 3, colors.data()); std::cerr << "\nDone.\n"; }