From 2629a58c2a9e8031509ccc3895ca1badb9a4aa6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20=C5=81oboda?= Date: Sun, 14 Apr 2024 11:47:15 +0200 Subject: [PATCH 1/7] adding glfw window wrapper and basic renderer --- CMakeLists.txt | 5 +-- src/LocalRenderer/Renderer.cpp | 23 +++++++++++ src/LocalRenderer/Renderer.h | 22 ++++++++++ src/LocalRenderer/Utils.h | 35 ++++++++++++++++ src/LocalRenderer/Window.cpp | 75 ++++++++++++++++++++++++++++++++++ src/LocalRenderer/Window.h | 37 +++++++++++++++++ src/main.cu | 18 ++++++++ 7 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 src/LocalRenderer/Renderer.cpp create mode 100644 src/LocalRenderer/Renderer.h create mode 100644 src/LocalRenderer/Utils.h create mode 100644 src/LocalRenderer/Window.cpp create mode 100644 src/LocalRenderer/Window.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cc00e21..e50a877 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,8 +18,7 @@ find_package(OpenGL REQUIRED) find_package(GLEW REQUIRED) find_package(assimp REQUIRED) -file(GLOB SOURCES "src/*.cpp" "src/*.cu") - -add_executable(cuda_project src/main.cu) +file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS "src/*.cpp" "src/*.cu") +add_executable(cuda_project ${SOURCES}) target_link_libraries(cuda_project PRIVATE glfw OpenGL::GL GLEW::GLEW assimp::assimp) diff --git a/src/LocalRenderer/Renderer.cpp b/src/LocalRenderer/Renderer.cpp new file mode 100644 index 0000000..4319fd9 --- /dev/null +++ b/src/LocalRenderer/Renderer.cpp @@ -0,0 +1,23 @@ + +#include "Renderer.h" +#include "Utils.h" + +Renderer::Renderer(Window& window) + : window_(window) + , width_(window.getWidth()) + , height_(window.getHeight()) { + + CheckedGLCall(glGenTextures(1, &texId_)); + CheckedGLCall(glGenFramebuffers(1, &fboId_)); +} + +void Renderer::renderFrame(const std::vector &frame) { + CheckedGLCall(glBindTexture(GL_TEXTURE_2D, texId_)); + CheckedGLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width_, height_, 0, GL_RGB, GL_UNSIGNED_BYTE, frame.data())); + + CheckedGLCall(glBindFramebuffer(GL_READ_FRAMEBUFFER, fboId_)); + CheckedGLCall(glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId_, 0)); + + CheckedGLCall(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); + CheckedGLCall(glBlitFramebuffer(0, 0, width_, height_, 0, 0, width_, height_, GL_COLOR_BUFFER_BIT, GL_NEAREST)); +} diff --git a/src/LocalRenderer/Renderer.h b/src/LocalRenderer/Renderer.h new file mode 100644 index 0000000..b27c31c --- /dev/null +++ b/src/LocalRenderer/Renderer.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include +#include "Window.h" +#include +#include + +class Renderer +{ +public: + Renderer(Window& window); + ~Renderer() = default; + void renderFrame(const std::vector &frame); +private: + Window& window_; + std::uint32_t width_; + std::uint32_t height_; + GLuint fboId_; + GLuint texId_; +}; \ No newline at end of file diff --git a/src/LocalRenderer/Utils.h b/src/LocalRenderer/Utils.h new file mode 100644 index 0000000..cfe05be --- /dev/null +++ b/src/LocalRenderer/Utils.h @@ -0,0 +1,35 @@ + +#pragma once +#include +#include +#include +#include + +#define CheckedGLCall(x) do { printOpenGLErrors(">>BEFORE<< "#x, __FILE__, __LINE__); (x); printOpenGLErrors(#x, __FILE__, __LINE__); } while (0) +#define CheckedGLResult(x) (x); printOpenGLErrors(#x, __FILE__, __LINE__); +#define CheckExistingErrors(x) printOpenGLErrors(">>BEFORE<< "#x, __FILE__, __LINE__); + +void printOpenGLErrors(char const * const function, char const * const file, int const line) { + bool succeeded = true; + GLenum error = glGetError(); + if (error != GL_NO_ERROR) { + char const *errorString = (char const *) gluErrorString(error); + throw std::runtime_error( + "OpenGL Error in " + std::string(file) + + " at line" + std::to_string(line) + + " calling function " + std::string(function) + + ": " + std::string(errorString)); + } +} + +void printShaderInfoLog(GLint const shader) { + int infoLogLength = 0; + int charsWritten = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); + if (infoLogLength > 0) { + GLchar * infoLog = new GLchar[infoLogLength]; + glGetShaderInfoLog(shader, infoLogLength, &charsWritten, infoLog); + std::cout << "Shader Info Log:" << std::endl << infoLog << std::endl; + delete [] infoLog; + } +} \ No newline at end of file diff --git a/src/LocalRenderer/Window.cpp b/src/LocalRenderer/Window.cpp new file mode 100644 index 0000000..ce22eeb --- /dev/null +++ b/src/LocalRenderer/Window.cpp @@ -0,0 +1,75 @@ +#include +#include +#include "Window.h" +#include +#include + +Window::Window(std::uint32_t width, std::uint32_t height, const std::string& title) + : window_(nullptr, glfwDestroyWindow) + , width_(width) + , height_(height) { + + if (!glfwInit()) { + throw std::runtime_error("glfwInit() failed"); + } + + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + window_.reset(glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr)); + if (!window_.get()) { + throw std::runtime_error("Failed to create GLFW window!"); + } + + glfwMakeContextCurrent(window_.get()); + glfwSetWindowUserPointer(window_.get(), this); + glfwSetScrollCallback(window_.get(), scrollCallback); + + GLenum glew_status = glewInit(); + + if (glew_status != GLEW_OK) { + fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status)); + throw std::runtime_error("Failed to init GLEW"); + } +} + +Window::~Window() { + glfwTerminate(); +} + +std::uint32_t Window::getWidth() const { + return width_; +} + +std::uint32_t Window::getHeight() const { + return height_; +} + +void Window::pollEvents() { + glfwPollEvents(); +} + +bool Window::shouldClose() const { + return glfwWindowShouldClose(window_.get()); +} + +void Window::getMousePos(int& x, int& y) const { + double xpos, ypos; + glfwGetCursorPos(window_.get(), &xpos, &ypos); + x = static_cast(xpos); + y = static_cast(ypos); +} + +void Window::setMousePos(int x, int y) const { + glfwSetCursorPos(window_.get(), (double)x, (double)y); +} + +void Window::swapBuffers(){ + glfwSwapBuffers(window_.get()); +} + +void Window::scrollCallback(GLFWwindow* window, double xoffset, double yoffset) { + Window* this_window = (Window*)glfwGetWindowUserPointer(window); + for (auto callback : this_window->scroll_callbacks_) + { + callback(yoffset); + } +} \ No newline at end of file diff --git a/src/LocalRenderer/Window.h b/src/LocalRenderer/Window.h new file mode 100644 index 0000000..df9a777 --- /dev/null +++ b/src/LocalRenderer/Window.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +class Window +{ +public: + Window(Window const&) = delete; + Window& operator=(Window const&) = delete; + + Window(std::uint32_t width, std::uint32_t height, const std::string& title); + ~Window(); + + void getMousePos(int& x, int& y) const; + void setMousePos(int x, int y) const; + void pollEvents(); + bool shouldClose() const; + void swapBuffers(); + void addScrollCallback(std::function callback) { scroll_callbacks_.push_back(callback); } + std::uint32_t getWidth() const; + std::uint32_t getHeight() const; + + +private: + static void scrollCallback(GLFWwindow* window, double xoffset, double yoffset); + + std::unique_ptr window_; + std::vector> scroll_callbacks_; + std::uint32_t width_ = 0u; + std::uint32_t height_ = 0u; +}; \ No newline at end of file diff --git a/src/main.cu b/src/main.cu index a60762d..c87cb86 100644 --- a/src/main.cu +++ b/src/main.cu @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -13,6 +15,8 @@ #include "obj_loader.h" #include "object3d.h" #include "triangle.h" +#include "LocalRenderer/Window.h" +#include "LocalRenderer/Renderer.h" #define checkCudaErrors(val) check_cuda( (val), #val, __FILE__, __LINE__ ) void check_cuda(cudaError_t result, char const *const func, const char *const file, int const line) { @@ -213,6 +217,8 @@ int main() checkCudaErrors(cudaDeviceSynchronize()); // Save result to a PPM image + std::vector frame(nx * ny * 3); + int current = 0; std::ofstream myfile; myfile.open("out.ppm"); myfile << "P3\n" << nx << " " << ny << "\n255\n"; @@ -221,10 +227,22 @@ int main() size_t pixel_index = j*nx + i; int3 color = make_int3(255.99*fb[pixel_index].x, 255.99*fb[pixel_index].y, 255.99*fb[pixel_index].z); myfile << color.x << " " << color.y << " " << color.z << "\n"; + frame[current++] = color.x; + frame[current++] = color.y; + frame[current++] = color.z; } } myfile.close(); checkCudaErrors(cudaFree(fb)); + Window window(nx, ny, "Hello"); + Renderer renderer(window); + + while (!window.shouldClose()) { + window.pollEvents(); + renderer.renderFrame(frame); + window.swapBuffers(); + } + return 0; } From 75ac8f130bb00d8cd8f49619b20cd85aa22da31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20=C5=81oboda?= Date: Sun, 14 Apr 2024 13:27:34 +0200 Subject: [PATCH 2/7] unifing ray tracer and renderer --- src/LocalRenderer/Renderer.cpp | 4 ++-- src/LocalRenderer/Renderer.h | 4 +++- src/main.cu | 27 +++++++++++---------------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/LocalRenderer/Renderer.cpp b/src/LocalRenderer/Renderer.cpp index 4319fd9..14be5e7 100644 --- a/src/LocalRenderer/Renderer.cpp +++ b/src/LocalRenderer/Renderer.cpp @@ -11,9 +11,9 @@ Renderer::Renderer(Window& window) CheckedGLCall(glGenFramebuffers(1, &fboId_)); } -void Renderer::renderFrame(const std::vector &frame) { +void Renderer::renderFrame(const uint8_t *frame) { CheckedGLCall(glBindTexture(GL_TEXTURE_2D, texId_)); - CheckedGLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width_, height_, 0, GL_RGB, GL_UNSIGNED_BYTE, frame.data())); + CheckedGLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width_, height_, 0, GL_RGB, GL_UNSIGNED_BYTE, frame)); CheckedGLCall(glBindFramebuffer(GL_READ_FRAMEBUFFER, fboId_)); CheckedGLCall(glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId_, 0)); diff --git a/src/LocalRenderer/Renderer.h b/src/LocalRenderer/Renderer.h index b27c31c..744d754 100644 --- a/src/LocalRenderer/Renderer.h +++ b/src/LocalRenderer/Renderer.h @@ -6,13 +6,15 @@ #include "Window.h" #include #include +#include "cuda_runtime.h" +#include class Renderer { public: Renderer(Window& window); ~Renderer() = default; - void renderFrame(const std::vector &frame); + void renderFrame(const uint8_t *frame); private: Window& window_; std::uint32_t width_; diff --git a/src/main.cu b/src/main.cu index c87cb86..1ca57ab 100644 --- a/src/main.cu +++ b/src/main.cu @@ -66,7 +66,7 @@ __global__ void render_init(int nx, int ny, curandState *rand_state) { * @param world An array of hitable pointers representing the scene. * @param rand_state The random state for each thread. */ -__global__ void render(float3 *fb, int max_x, int max_y,int sample_per_pixel, camera **cam,hitable **world, curandState *rand_state) { +__global__ void render(uint8_t *fb, int max_x, int max_y,int sample_per_pixel, camera **cam,hitable **world, curandState *rand_state) { int i = threadIdx.x + blockIdx.x * blockDim.x; int j = threadIdx.y + blockIdx.y * blockDim.y; if((i >= max_x) || (j >= max_y)) return; @@ -80,8 +80,10 @@ __global__ void render(float3 *fb, int max_x, int max_y,int sample_per_pixel, ca ray r = (*cam)->get_ray(u, v); col += (*cam)->ray_color(r, world, &local_rand_state); } - - fb[pixel_index] = col/float(sample_per_pixel); //average color of samples + int3 color = make_int3(255.99 * col/float(sample_per_pixel)); //average color of samples + fb[3 * pixel_index] = color.x; + fb[3 * pixel_index + 1] = color.y; + fb[3 * pixel_index + 2] = color.z; } /** @@ -145,15 +147,14 @@ int main() float aspect_ratio = float(nx) / float(ny); int num_pixels = nx*ny; - size_t fb_size = num_pixels*sizeof(float3); dim3 blocks(nx/tx+1,ny/ty+1); dim3 threads(tx,ty); + size_t fb_size = num_pixels*sizeof(uint8_t) * 3; curandState *d_rand_state; checkCudaErrors(cudaMalloc((void **)&d_rand_state, num_pixels*sizeof(curandState))); - // allocate FB - float3 *fb; + uint8_t *fb; checkCudaErrors(cudaMallocManaged((void **)&fb, fb_size)); //create_world @@ -217,32 +218,26 @@ int main() checkCudaErrors(cudaDeviceSynchronize()); // Save result to a PPM image - std::vector frame(nx * ny * 3); - int current = 0; std::ofstream myfile; myfile.open("out.ppm"); myfile << "P3\n" << nx << " " << ny << "\n255\n"; for (int j = ny-1; j >= 0; j--) { for (int i = 0; i < nx; i++) { - size_t pixel_index = j*nx + i; - int3 color = make_int3(255.99*fb[pixel_index].x, 255.99*fb[pixel_index].y, 255.99*fb[pixel_index].z); - myfile << color.x << " " << color.y << " " << color.z << "\n"; - frame[current++] = color.x; - frame[current++] = color.y; - frame[current++] = color.z; + size_t pixel_index = 3 * (j*nx + i); + myfile << fb[pixel_index] << " " << fb[pixel_index + 1] << " " << fb[pixel_index + 2] << "\n"; } } myfile.close(); - checkCudaErrors(cudaFree(fb)); Window window(nx, ny, "Hello"); Renderer renderer(window); while (!window.shouldClose()) { window.pollEvents(); - renderer.renderFrame(frame); + renderer.renderFrame(fb); window.swapBuffers(); } + checkCudaErrors(cudaFree(fb)); return 0; } From 2c3bc7420f7bd233ca11ed388a2b881d0af9c19a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20=C5=81oboda?= Date: Sun, 14 Apr 2024 13:46:05 +0200 Subject: [PATCH 3/7] adding mouse key getter for window --- src/LocalRenderer/Renderer.h | 3 +-- src/LocalRenderer/Window.cpp | 16 +++++++++++++--- src/LocalRenderer/Window.h | 13 +++++++++---- src/main.cu | 2 +- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/LocalRenderer/Renderer.h b/src/LocalRenderer/Renderer.h index 744d754..0b902a3 100644 --- a/src/LocalRenderer/Renderer.h +++ b/src/LocalRenderer/Renderer.h @@ -9,8 +9,7 @@ #include "cuda_runtime.h" #include -class Renderer -{ +class Renderer { public: Renderer(Window& window); ~Renderer() = default; diff --git a/src/LocalRenderer/Window.cpp b/src/LocalRenderer/Window.cpp index ce22eeb..35becc0 100644 --- a/src/LocalRenderer/Window.cpp +++ b/src/LocalRenderer/Window.cpp @@ -4,6 +4,12 @@ #include #include +const std::unordered_map mouseButtonToGlfwButton = { + { MouseButton::Left, GLFW_MOUSE_BUTTON_LEFT }, + { MouseButton::Right, GLFW_MOUSE_BUTTON_RIGHT }, + { MouseButton::Middle, GLFW_MOUSE_BUTTON_MIDDLE }, +}; + Window::Window(std::uint32_t width, std::uint32_t height, const std::string& title) : window_(nullptr, glfwDestroyWindow) , width_(width) @@ -12,8 +18,7 @@ Window::Window(std::uint32_t width, std::uint32_t height, const std::string& tit if (!glfwInit()) { throw std::runtime_error("glfwInit() failed"); } - - glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + // glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); window_.reset(glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr)); if (!window_.get()) { throw std::runtime_error("Failed to create GLFW window!"); @@ -51,6 +56,11 @@ bool Window::shouldClose() const { return glfwWindowShouldClose(window_.get()); } +bool Window::getMouseButton(MouseButton button) const { + auto b = mouseButtonToGlfwButton.find(button); + return glfwGetMouseButton(window_.get(), b->second) == GLFW_PRESS; +} + void Window::getMousePos(int& x, int& y) const { double xpos, ypos; glfwGetCursorPos(window_.get(), &xpos, &ypos); @@ -62,7 +72,7 @@ void Window::setMousePos(int x, int y) const { glfwSetCursorPos(window_.get(), (double)x, (double)y); } -void Window::swapBuffers(){ +void Window::swapBuffers() { glfwSwapBuffers(window_.get()); } diff --git a/src/LocalRenderer/Window.h b/src/LocalRenderer/Window.h index df9a777..60f7531 100644 --- a/src/LocalRenderer/Window.h +++ b/src/LocalRenderer/Window.h @@ -8,8 +8,14 @@ #include #include -class Window -{ +enum class MouseButton { + Left, + Right, + Middle, +}; + + +class Window { public: Window(Window const&) = delete; Window& operator=(Window const&) = delete; @@ -25,11 +31,10 @@ class Window void addScrollCallback(std::function callback) { scroll_callbacks_.push_back(callback); } std::uint32_t getWidth() const; std::uint32_t getHeight() const; - + bool getMouseButton(MouseButton button) const; private: static void scrollCallback(GLFWwindow* window, double xoffset, double yoffset); - std::unique_ptr window_; std::vector> scroll_callbacks_; std::uint32_t width_ = 0u; diff --git a/src/main.cu b/src/main.cu index 1ca57ab..34b95b3 100644 --- a/src/main.cu +++ b/src/main.cu @@ -229,7 +229,7 @@ int main() } myfile.close(); - Window window(nx, ny, "Hello"); + Window window(nx, ny, "MultiGPU-PathTracer"); Renderer renderer(window); while (!window.shouldClose()) { From b15c96099c56e5ee0cf914a2a257dbf7615b8658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20=C5=81oboda?= <46354460+wojciechloboda@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:40:38 +0200 Subject: [PATCH 4/7] Update src/LocalRenderer/Utils.h Co-authored-by: Patryk Klatka --- src/LocalRenderer/Utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LocalRenderer/Utils.h b/src/LocalRenderer/Utils.h index cfe05be..3187252 100644 --- a/src/LocalRenderer/Utils.h +++ b/src/LocalRenderer/Utils.h @@ -13,7 +13,7 @@ void printOpenGLErrors(char const * const function, char const * const file, int bool succeeded = true; GLenum error = glGetError(); if (error != GL_NO_ERROR) { - char const *errorString = (char const *) gluErrorString(error); + char const *errorString = (char const *) gluErrorString(error); throw std::runtime_error( "OpenGL Error in " + std::string(file) + " at line" + std::to_string(line) + From c5e38de5d4a6c1ddc8e7eae02e7d609b1c55853e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20=C5=81oboda?= <46354460+wojciechloboda@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:40:58 +0200 Subject: [PATCH 5/7] Update src/LocalRenderer/Window.cpp Co-authored-by: Patryk Klatka --- src/LocalRenderer/Window.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/LocalRenderer/Window.cpp b/src/LocalRenderer/Window.cpp index 35becc0..1f47d89 100644 --- a/src/LocalRenderer/Window.cpp +++ b/src/LocalRenderer/Window.cpp @@ -30,7 +30,9 @@ Window::Window(std::uint32_t width, std::uint32_t height, const std::string& tit GLenum glew_status = glewInit(); - if (glew_status != GLEW_OK) { + // GLEW_ERROR_NO_GLX_DISPLAY occurs when running the program on a WSL system. + // This error is not critical and can be ignored. + if (glew_status != GLEW_OK && glew_status != GLEW_ERROR_NO_GLX_DISPLAY) { fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status)); throw std::runtime_error("Failed to init GLEW"); } From 91d29ef6ec8d51ef37d8c312d17284764f4bc4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20=C5=81oboda?= <46354460+wojciechloboda@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:41:12 +0200 Subject: [PATCH 6/7] Update src/main.cu Co-authored-by: Patryk Klatka --- src/main.cu | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cu b/src/main.cu index 34b95b3..3d231b8 100644 --- a/src/main.cu +++ b/src/main.cu @@ -235,7 +235,8 @@ int main() while (!window.shouldClose()) { window.pollEvents(); renderer.renderFrame(fb); - window.swapBuffers(); + window.swapBuffers(); + } checkCudaErrors(cudaFree(fb)); From a96cf5fd74c877dc2d53468abbddd9d05e8cdabf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20=C5=81oboda?= Date: Tue, 23 Apr 2024 11:01:31 +0200 Subject: [PATCH 7/7] removing unecessary inputs --- src/LocalRenderer/Renderer.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/LocalRenderer/Renderer.h b/src/LocalRenderer/Renderer.h index 0b902a3..2a16c6e 100644 --- a/src/LocalRenderer/Renderer.h +++ b/src/LocalRenderer/Renderer.h @@ -6,8 +6,6 @@ #include "Window.h" #include #include -#include "cuda_runtime.h" -#include class Renderer { public: