From 3fa51f71526f08e972c51b381dc84a03f9835d1c Mon Sep 17 00:00:00 2001 From: Dynamitos Date: Thu, 27 Feb 2025 20:25:53 +0900 Subject: [PATCH] i hate metal cpp --- .vscode/launch.json | 2 +- CMakeLists.txt | 13 ++- src/CMakeLists.txt | 1 - src/Minimal.h | 14 --- src/ThreadPool.h | 13 +++ src/cpu/CPURenderer.cpp | 118 ++++++++++++++++++++++++- src/cpu/CPURenderer.h | 26 +++++- src/gpu/GPURenderer.h | 5 +- src/main.cpp | 43 +++++---- src/metal/CMakeLists.txt | 4 +- src/metal/Compute.metal | 10 ++- src/metal/MetalRenderer.cpp | 96 -------------------- src/metal/MetalRenderer.h | 72 +++++++++------ src/metal/MetalRenderer.mm | 172 ++++++++++++++++++++++++++++++++++++ src/metal/MetalScene.cpp | 109 ----------------------- src/metal/MetalScene.mm | 107 ++++++++++++++++++++++ src/metal/PrivateImpl.mm | 2 +- src/scene/Renderer.cpp | 2 - src/scene/Renderer.h | 9 +- src/window/CMakeLists.txt | 4 - src/window/Window.cpp | 114 ------------------------ src/window/Window.h | 24 ----- vcpkg.json | 2 +- 23 files changed, 525 insertions(+), 437 deletions(-) delete mode 100644 src/metal/MetalRenderer.cpp create mode 100644 src/metal/MetalRenderer.mm delete mode 100644 src/metal/MetalScene.cpp create mode 100644 src/metal/MetalScene.mm delete mode 100644 src/window/CMakeLists.txt delete mode 100644 src/window/Window.cpp delete mode 100644 src/window/Window.h diff --git a/.vscode/launch.json b/.vscode/launch.json index 275a9eb..46796ab 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,7 +11,7 @@ "program": "${workspaceFolder}/build/Debug/RayTracer", "args": [], "stopAtEntry": false, - "cwd": "${workspaceFolder}/build", + "cwd": "${workspaceFolder}/build/Debug", "environment": [], "externalConsole": false, "MIMode": "lldb" diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e9ebb0..1336c17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,9 +19,6 @@ find_package(glfw3 CONFIG REQUIRED) find_package(glm CONFIG REQUIRED) find_package(Ktx CONFIG REQUIRED) find_package(imgui CONFIG REQUIRED) -find_library(APPLE_FWK_FOUNDATION Foundation REQUIRED) -find_library(APPLE_FWK_QUARTZ_CORE QuartzCore REQUIRED) -find_library(APPLE_FWK_METAL Metal REQUIRED) add_executable(RayTracer "") target_include_directories(RayTracer PUBLIC src/) @@ -40,12 +37,14 @@ target_link_libraries(RayTracer PUBLIC ${VCPKG_INSTALLED_DIR}/x64-windows/lib/sl elseif(APPLE) target_include_directories(RayTracer PUBLIC ${VCPKG_INSTALLED_DIR}/arm64-osx/include) target_include_directories(RayTracer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/external/metal-cpp) -SET(CMAKE_OSX_DEPLOYMENT_TARGET 15.0) +SET(CMAKE_OSX_DEPLOYMENT_TARGET 15.3.1) target_link_libraries(RayTracer PUBLIC - ${APPLE_FWK_FOUNDATION} - ${APPLE_FWK_QUARTZ_CORE} - ${APPLE_FWK_METAL} + "-framework Metal" + "-framework MetalKit" + "-framework AppKit" + "-framework Foundation" + "-framework QuartzCore" ) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4bea1ca..7522e5c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,5 +11,4 @@ if(APPLE) add_subdirectory(metal/) endif() add_subdirectory(scene/) -add_subdirectory(window/) add_subdirectory(util/) diff --git a/src/Minimal.h b/src/Minimal.h index 65b3c69..03fd89b 100644 --- a/src/Minimal.h +++ b/src/Minimal.h @@ -1,6 +1,4 @@ #pragma once -#include -#include #define DEFINE_REF(x) typedef ::std::unique_ptr P##x; @@ -8,15 +6,3 @@ class x; \ typedef ::std::unique_ptr P##x; -struct Task -{ - struct promise_type - { - Task get_return_object() { return {std::coroutine_handle::from_promise(*this)}; } - std::suspend_always initial_suspend() noexcept { return {}; } - std::suspend_never final_suspend() noexcept { return {}; } - void return_void() {} - void unhandled_exception() {} - }; - std::coroutine_handle handle; -}; diff --git a/src/ThreadPool.h b/src/ThreadPool.h index abf2c50..89523f4 100644 --- a/src/ThreadPool.h +++ b/src/ThreadPool.h @@ -4,7 +4,20 @@ #include #include #include "Minimal.h" +#include +struct Task +{ + struct promise_type + { + Task get_return_object() { return {std::coroutine_handle::from_promise(*this)}; } + std::suspend_always initial_suspend() noexcept { return {}; } + std::suspend_never final_suspend() noexcept { return {}; } + void return_void() {} + void unhandled_exception() {} + }; + std::coroutine_handle handle; +}; struct Batch { std::list jobs; diff --git a/src/cpu/CPURenderer.cpp b/src/cpu/CPURenderer.cpp index 972add1..537131a 100644 --- a/src/cpu/CPURenderer.cpp +++ b/src/cpu/CPURenderer.cpp @@ -1,5 +1,95 @@ #include "CPURenderer.h" #include "scene/Renderer.h" +#include +#include +#include + +#define GLSL(...) "#version 400\n" #__VA_ARGS__ + +CPURenderer::CPURenderer() +{ + glewExperimental = true; + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We don't want the old OpenGL + window = glfwCreateWindow(width, height, "RayTracer", nullptr, nullptr); + glfwSwapInterval(1); + glfwMakeContextCurrent(window); + + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + + ImGui_ImplGlfw_InitForOpenGL(window, + true); // Second param install_callback=true will install GLFW callbacks and chain to existing ones. + ImGui_ImplOpenGL3_Init(); + + glewInit(); + + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + program = glCreateProgram(); + vertShader = glCreateShader(GL_VERTEX_SHADER); + fragShader = glCreateShader(GL_FRAGMENT_SHADER); + int logLen = 0; + const char* vertCode = + GLSL(out vec2 texcoords; // texcoords are in the normalized [0,1] range for the viewport-filling quad part of the triangle + void main() { + vec2 vertices[3] = vec2[3](vec2(-1, -1), vec2(3, -1), vec2(-1, 3)); + gl_Position = vec4(vertices[gl_VertexID], 0, 1); + texcoords = 0.5 * gl_Position.xy + vec2(0.5); + }); + const char* fragCode = GLSL(in vec2 texcoords; out vec4 color; + + uniform sampler2D tex; + + void main() { color = texture(tex, vec2(texcoords.x, -texcoords.y)); }); + glShaderSource(vertShader, 1, &vertCode, nullptr); + glCompileShader(vertShader); + int success; + char infoLog[1024]; + glGetShaderiv(vertShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(vertShader, 1024, NULL, infoLog); + std::cout << "ERROR::SHADER_COMPILATION_ERROR\n" + << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; + } + + glShaderSource(fragShader, 1, &fragCode, nullptr); + glCompileShader(fragShader); + glGetShaderiv(fragShader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(fragShader, 1024, NULL, infoLog); + std::cout << "ERROR::SHADER_COMPILATION_ERROR\n" + << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; + } + + glAttachShader(program, vertShader); + glAttachShader(program, fragShader); + + glLinkProgram(program); + glGetProgramiv(program, GL_LINK_STATUS, &logLen); + if (logLen > 0) + { + std::vector log(logLen); + glGetProgramInfoLog(program, logLen, &logLen, log.data()); + std::cout << log.data() << std::endl; + } + glDeleteShader(vertShader); + glDeleteShader(fragShader); + glClearColor(0, 0, 0, 0); +} glm::vec3 rand01(glm::uvec3 x) { // pseudo-random number generator @@ -8,10 +98,32 @@ glm::vec3 rand01(glm::uvec3 x) return glm::vec3(x) * (1.0f / float(0xffffffffU)); } +void CPURenderer::beginFrame() +{ + glClear(GL_COLOR_BUFFER_BIT); + glfwPollEvents(); + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); +} + +void CPURenderer::update() +{ + glBindTexture(GL_TEXTURE_2D, texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_FLOAT, image.data()); + glUseProgram(program); + glDrawArrays(GL_TRIANGLES, 0, 3); + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + glfwSwapBuffers(window); +} + void CPURenderer::render(Camera camera, RenderParameter params) { - accumulator.clear(); - accumulator.resize(params.width * params.height); + image.clear(); + image.resize(params.width * params.height); + accumulator.clear(); + accumulator.resize(params.width * params.height); for (int samp = 0; samp < params.numSamples; ++samp) { if (!running) @@ -64,7 +176,7 @@ void CPURenderer::render(Camera camera, RenderParameter params) scene->traceRay(r, payload, 1e-4, 1e20); - float resolver = float(params.numSamples) / float(samp+1); + float resolver = float(params.numSamples) / float(samp + 1); accumulator[w + h * params.width] += payload.accumulatedRadiance / float(params.numSamples); image[w + h * params.width] = glm::pow(glm::max(accumulator[w + h * params.width] * resolver, 0.0f), glm::vec3(0.45f)); } diff --git a/src/cpu/CPURenderer.h b/src/cpu/CPURenderer.h index 44bf6e9..483bb41 100644 --- a/src/cpu/CPURenderer.h +++ b/src/cpu/CPURenderer.h @@ -2,14 +2,38 @@ #include "cpu/CPUScene.h" #include "scene/Renderer.h" #include "util/Camera.h" +#include "ThreadPool.h" +#include +#include class CPURenderer : public Renderer { public: + CPURenderer(); + virtual ~CPURenderer(); + + virtual void addPointLight(PointLight point) override { scene->addPointLight(point); } + virtual void addDirectionalLight(DirectionalLight dir) override { scene->addDirectionalLight(dir); } + virtual void addModel(PModel model, glm::mat4 transform) override { scene->addModel(std::move(model), transform); } + virtual void addModels(std::vector models, glm::mat4 transform) override { scene->addModels(std::move(models), transform); } + virtual void generate() override { scene->generate(); } + + virtual void beginFrame() override; + virtual void update() override; +protected: virtual void render(Camera camera, RenderParameter params) override; -private: CPUScene* scene; ThreadPool threadPool; // radiance accumulator std::vector accumulator; + // the thing being displayed + std::vector image; + int width; + int height; + GLuint vao; + GLuint texture; + GLuint program; + GLuint vertShader; + GLuint fragShader; + GLFWwindow* window; }; \ No newline at end of file diff --git a/src/gpu/GPURenderer.h b/src/gpu/GPURenderer.h index ab57035..a93616a 100644 --- a/src/gpu/GPURenderer.h +++ b/src/gpu/GPURenderer.h @@ -11,7 +11,7 @@ struct GPURenderer : public Renderer { public: GPURenderer(); - virtual ~GPURenderer(); + virtual ~GPURenderer(); virtual void addPointLight(PointLight point) override { scene->addPointLight(point); } virtual void addDirectionalLight(DirectionalLight dir) override { scene->addDirectionalLight(dir); } virtual void addModel(PModel model, glm::mat4 transform) override { scene->addModel(std::move(model), transform); } @@ -19,6 +19,9 @@ public: virtual void generate() override { scene->generate(); } virtual void render(Camera cam, RenderParameter param) override; + virtual void beginFrame() override; + virtual void update() override; + private: struct GPUCamera { diff --git a/src/main.cpp b/src/main.cpp index 12eeb7c..b5f0b24 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,26 +1,24 @@ -#include "scene/Renderer.h" #include "metal/MetalRenderer.h" -#include "window/Window.h" +#include "scene/Renderer.h" #include "util/ModelLoader.h" #include int main() { - std::unique_ptr scene = std::make_unique(); + std::unique_ptr renderer = std::make_unique(); - scene->addDirectionalLight(DirectionalLight{ - .direction = glm::normalize(glm::vec3(-0.4f, -0.3f, -0.2f)), - .color = glm::vec3(1, 1, 1), + renderer->addDirectionalLight(DirectionalLight{ + .direction = glm::normalize(glm::vec3(-0.4f, -0.3f, -0.2f)), + .color = glm::vec3(1, 1, 1), }); - scene->addPointLight(PointLight{}); - scene->addModels(ModelLoader::loadModel("../../res/models/cube.fbx"), - glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), - glm::vec4(0.0f, 0.0f, 0.0f, 1.0f))); - scene->addModels(ModelLoader::loadModel("../../res/models/cube.fbx"), - glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), - glm::vec4(0.0f, 0.0f, 0.0f, 1.0f))); - scene->generate(); - Window window(1920, 1080); + renderer->addPointLight(PointLight{}); + renderer->addModels(ModelLoader::loadModel("../../res/models/cube.fbx"), + glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), + glm::vec4(0.0f, 0.0f, 0.0f, 1.0f))); + renderer->addModels(ModelLoader::loadModel("../../res/models/cube.fbx"), + glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), + glm::vec4(0.0f, 0.0f, 0.0f, 1.0f))); + renderer->generate(); Camera camera = Camera{ .position = glm::vec3(5, 1, 2), .target = glm::vec3(0, 0, 0), @@ -31,11 +29,11 @@ int main() .height = 1080, .numSamples = 10000, }; - scene->startRender(camera, render); + renderer->startRender(camera, render); while (true) { - window.beginFrame(); + renderer->beginFrame(); ImGui::Text("Camera Parameters"); ImGui::InputFloat3("Position", &camera.position.x); ImGui::InputFloat3("Target", &camera.target.x); @@ -47,13 +45,14 @@ int main() ImGui::InputInt("Samples", (int*)&render.numSamples); if (ImGui::Button("Render")) { - scene->startRender(camera, render); + renderer->startRender(camera, render); } ImGui::Text("Render Stats"); - ImGui::Text("Last Sample Time: %.3f ms", scene->getLastSampleTime()); - ImGui::Text("Average Sample Time: %.3f ms", scene->getAverageSampleTime()); - ImGui::PlotLines("Sample Times", scene->getSampleTimes().data(), scene->getSampleTimes().size(), 0, 0, FLT_MAX, FLT_MAX, ImVec2(0, 40)); - window.update(scene->getImage()); + ImGui::Text("Last Sample Time: %.3f ms", renderer->getLastSampleTime()); + ImGui::Text("Average Sample Time: %.3f ms", renderer->getAverageSampleTime()); + ImGui::PlotLines("Sample Times", renderer->getSampleTimes().data(), renderer->getSampleTimes().size(), 0, 0, FLT_MAX, FLT_MAX, + ImVec2(0, 40)); + renderer->update(); } return 0; } diff --git a/src/metal/CMakeLists.txt b/src/metal/CMakeLists.txt index e0dddbd..776e3b9 100644 --- a/src/metal/CMakeLists.txt +++ b/src/metal/CMakeLists.txt @@ -1,8 +1,8 @@ target_sources(RayTracer PRIVATE MetalRenderer.h - MetalRenderer.cpp + MetalRenderer.mm MetalScene.h - MetalScene.cpp + MetalScene.mm Compute.metal PrivateImpl.mm) \ No newline at end of file diff --git a/src/metal/Compute.metal b/src/metal/Compute.metal index 9905e94..c2cf0f8 100644 --- a/src/metal/Compute.metal +++ b/src/metal/Compute.metal @@ -133,8 +133,8 @@ kernel void computeKernel( constant PointLight* pointLights [[buffer(6)]], constant MTLAccelerationStructureInstanceDescriptor* instances [[buffer(7)]], instance_acceleration_structure accelerationStructure [[buffer(8)]], - device packed_float3* accumulator [[buffer(9)]], - device packed_float3* image [[buffer(10)]] + texture2d accumulator [[texture(0)]], + texture2d image [[texture(1)]] ) { Payload payload; @@ -267,6 +267,8 @@ kernel void computeKernel( payload.depth++; } float resolver = float(sample.samplesPerPixel) / float(sample.pass+1); - accumulator[threadId.x + threadId.y * camera.width] += payload.accumulatedRadiance / float(sample.samplesPerPixel); - image[threadId.x + threadId.y * camera.width] = pow(max(accumulator[threadId.x + threadId.y * camera.width] * resolver, 0), float3(0.45f)); + float4 previous = accumulator.read(threadId); + float4 result = previous + float4(payload.accumulatedRadiance / float(sample.samplesPerPixel), 0); + accumulator.write(result, threadId); + image.write(pow(max(result * resolver, 0), float4(0.45f)), threadId); } diff --git a/src/metal/MetalRenderer.cpp b/src/metal/MetalRenderer.cpp deleted file mode 100644 index eead738..0000000 --- a/src/metal/MetalRenderer.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "MetalRenderer.h" -#include "metal/MetalScene.h" -#include "scene/Renderer.h" -#include "util/Camera.h" -#include -#include -#include - -MetalRenderer::MetalRenderer() -{ - device = MTL::CreateSystemDefaultDevice(); - - library = device->newDefaultLibrary(); - - queue = device->newCommandQueue(); - - scene = new MetalScene(device, queue); - - function = library->newFunction(NS::String::string("computeKernel", NS::ASCIIStringEncoding)); - - NS::Error* error; - computePipeline = device->newComputePipelineState(function, &error); -} - -MetalRenderer::~MetalRenderer() {} - -void MetalRenderer::render(Camera camera, RenderParameter parameter) -{ - MTL::Buffer* cameraBuffer = device->newBuffer(sizeof(GPUCamera), 0); - *(GPUCamera*)cameraBuffer->contents() = GPUCamera { - .cameraPosition = camera.position, - .A = camera.A, - .cameraForward = camera.target - camera.position, - .f = camera.f, - .S_O = camera.S_O, - .sensorSize = camera.sensorSize, - .width = parameter.width, - .height = parameter.height, - }; - - SampleParams sample = { - .samplesPerPixel = parameter.numSamples, - .numDirectionalLights = scene->getNumDirLights(), - .numPointLights = scene->getNumPointLights(), - }; - accumulator = device->newBuffer(parameter.width * parameter.height * sizeof(glm::vec3), 0); - resultTexture = device->newBuffer(parameter.width * parameter.height * sizeof(glm::vec3), 0); - for (uint i = 0; i < parameter.numSamples; ++i) - { - MTL::CommandBuffer* cmdBuffer = queue->commandBuffer(); - MTL::ComputeCommandEncoder* encoder = cmdBuffer->computeCommandEncoder(); - //cmdBuffer->addCompletedHandler([this](MTL::CommandBuffer* cmdBuffer) - // { std::memcpy(image.data(), resultTexture->buffer(), image.size() * sizeof(glm::vec3)); }); - sample.pass = i; - MTL::Buffer* sampleBuffer = device->newBuffer(sizeof(SampleParams), 0); - *(SampleParams*)sampleBuffer->contents() = sample; - encoder->setComputePipelineState(computePipeline); - encoder->setBuffer(scene->indicesBuffer, 0, 0); - encoder->setBuffer(scene->positionBuffer, 0, 1); - encoder->setBuffer(scene->texCoordsBuffer, 0, 2); - encoder->setBuffer(scene->normalBuffer, 0, 3); - encoder->setBuffer(scene->modelRefsBuffer, 0, 4); - encoder->setBuffer(scene->directionalLightBuffer, 0, 5); - encoder->setBuffer(scene->pointLightBuffer, 0, 6); - encoder->setBuffer(scene->instanceBuffer, 0, 7); - encoder->setAccelerationStructure(scene->accelerationStructure, 8); - encoder->setBuffer(accumulator, 0, 9); - encoder->setBuffer(resultTexture, 0, 10); - encoder->setBuffer(cameraBuffer, 0, 11); - encoder->setBuffer(sampleBuffer, 0, 12); - encoder->useResource(scene->instanceBuffer, MTL::ResourceUsageRead); - encoder->useResource(scene->positionBuffer, MTL::ResourceUsageRead); - encoder->useResource(scene->texCoordsBuffer, MTL::ResourceUsageRead); - encoder->useResource(scene->normalBuffer, MTL::ResourceUsageRead); - encoder->useResource(scene->modelRefsBuffer, MTL::ResourceUsageRead); - if(scene->getNumDirLights() > 0) - { - encoder->useResource(scene->directionalLightBuffer, MTL::ResourceUsageRead);} - if(scene->getNumPointLights() > 0) - {encoder->useResource(scene->pointLightBuffer, MTL::ResourceUsageRead);} - encoder->useResource(scene->instanceBuffer, MTL::ResourceUsageRead); - encoder->useResource(scene->accelerationStructure, MTL::ResourceUsageRead); - encoder->useResource(accumulator, MTL::ResourceUsageWrite); - encoder->useResource(resultTexture, MTL::ResourceUsageWrite); - NS::UInteger width = (NS::UInteger)parameter.width; - NS::UInteger height = (NS::UInteger)parameter.height; - MTL::Size threadsPerThreadgroup = MTL::Size(8, 8, 1); - MTL::Size threadgroups = MTL::Size((width + threadsPerThreadgroup.width - 1) / threadsPerThreadgroup.width, - (height + threadsPerThreadgroup.height - 1) / threadsPerThreadgroup.height, 1); - encoder->dispatchThreadgroups(threadgroups, threadsPerThreadgroup); - encoder->endEncoding(); - cmdBuffer->commit(); - cmdBuffer->waitUntilCompleted(); - std::memcpy(image.data(), resultTexture->contents(), image.size() * sizeof(glm::vec3)); - } -} diff --git a/src/metal/MetalRenderer.h b/src/metal/MetalRenderer.h index 883662f..17e310e 100644 --- a/src/metal/MetalRenderer.h +++ b/src/metal/MetalRenderer.h @@ -2,8 +2,14 @@ #include "metal/MetalScene.h" #include "scene/Renderer.h" #include "util/Camera.h" -#include + +#define GLFW_INCLUDE_NONE +#include +#define GLFW_EXPOSE_NATIVE_COCOA +#include + #include +#include #include struct GPUCamera @@ -17,38 +23,54 @@ struct GPUCamera float A; float ka; glm::vec2 sensorSize; - uint width; - uint height; + uint width; + uint height; }; struct SampleParams { - uint pass; - uint samplesPerPixel; - uint numDirectionalLights; - uint numPointLights; + uint pass; + uint samplesPerPixel; + uint numDirectionalLights; + uint numPointLights; }; class MetalRenderer : public Renderer { public: - MetalRenderer(); - virtual ~MetalRenderer(); - virtual void addPointLight(PointLight point) override { scene->addPointLight(point); } - virtual void addDirectionalLight(DirectionalLight dir) override { scene->addDirectionalLight(dir); } - virtual void addModel(PModel model, glm::mat4 transform) override { scene->addModel(std::move(model), transform); } - virtual void addModels(std::vector models, glm::mat4 transform) override { scene->addModels(std::move(models), transform); } - virtual void generate() override { scene->generate(); } - virtual void render(Camera camera, RenderParameter params) override; - -private: - MTL::Device* device; - MTL::Library* library; - MTL::CommandQueue* queue; - MTL::Function* function; - MTL::ComputePipelineState* computePipeline; - MTL::Buffer* accumulator; - MTL::Buffer* resultTexture; + MetalRenderer(); + virtual ~MetalRenderer(); + virtual void addPointLight(PointLight point) override { scene->addPointLight(point); } + virtual void addDirectionalLight(DirectionalLight dir) override { scene->addDirectionalLight(dir); } + virtual void addModel(PModel model, glm::mat4 transform) override { scene->addModel(std::move(model), transform); } + virtual void addModels(std::vector models, glm::mat4 transform) override { scene->addModels(std::move(models), transform); } + virtual void generate() override { scene->generate(); } + virtual void render(Camera camera, RenderParameter params) override; - MetalScene* scene; + virtual void beginFrame() override; + virtual void update() override; + +private: + uint width; + uint height; + uint framebufferWidth; + uint framebufferHeight; + GLFWwindow* handle; + CA::MetalLayer* metalLayer; + CA::MetalDrawable* drawable; + + MTL::Device* device; + MTL::Library* library; + MTL::CommandQueue* queue; + MTL::Function* function; + MTL::ComputePipelineState* computePipeline; + MTL::Texture* accumulator; + MTL::Texture* resultTexture; + + MTL::RenderPassDescriptor* renderPass; + MTL::RenderCommandEncoder* renderEncoder; + MTL::CommandBuffer* renderCmd; + + MetalScene* scene; }; + diff --git a/src/metal/MetalRenderer.mm b/src/metal/MetalRenderer.mm new file mode 100644 index 0000000..6ba82b0 --- /dev/null +++ b/src/metal/MetalRenderer.mm @@ -0,0 +1,172 @@ +#include "MetalRenderer.h" +#include "Foundation/NSSharedPtr.hpp" +#include "Metal/MTLBlitCommandEncoder.hpp" +#include "Metal/MTLDrawable.hpp" +#include "Metal/MTLRenderPass.hpp" +#include "QuartzCore/CAMetalLayer.hpp" +#include "metal/MetalScene.h" +#include "scene/Renderer.h" +#include "util/Camera.h" +#include +#include +#include +#include +#include +#include +#include +#include + +MetalRenderer::MetalRenderer() +{ + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + + width = 1920; + height = 1080; + device = MTL::CreateSystemDefaultDevice(); + + library = device->newDefaultLibrary(); + + queue = device->newCommandQueue(); + + scene = new MetalScene(device, queue); + + function = library->newFunction(NS::String::string("computeKernel", NS::ASCIIStringEncoding)); + + NS::Error* error; + computePipeline = device->newComputePipelineState(function, &error); + + glfwInit(); + float xscale = 1, yscale = 1; + glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, &yscale); + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + handle = glfwCreateWindow(width / xscale, height / yscale, "RayTracer", nullptr, nullptr); + + int w, h; + glfwGetFramebufferSize(handle, &w, &h); + framebufferWidth = width; + framebufferHeight = height; + + ImGui_ImplGlfw_InitForOpenGL(handle, false); + ImGui_ImplMetal_Init((__bridge id)device); + + metalLayer = CA::MetalLayer::layer(); + metalLayer->setDevice(device); + metalLayer->setPixelFormat(MTL::PixelFormatBGRA8Unorm); + metalLayer->setDrawableSize(CGSizeMake(w, h)); + metalLayer->setFramebufferOnly(true); + CAMetalLayer* native_layer = (__bridge CAMetalLayer*)metalLayer; + NSWindow* cocoaWindow = glfwGetCocoaWindow(handle); + [[cocoaWindow contentView] setLayer:native_layer]; + [[cocoaWindow contentView] setWantsLayer:YES]; + [[cocoaWindow contentView] setNeedsLayout:YES]; + + renderPass= MTL::RenderPassDescriptor::alloc()->init(); +} + +MetalRenderer::~MetalRenderer() {} + +void MetalRenderer::beginFrame() +{ + drawable = metalLayer->nextDrawable(); + renderCmd = queue->commandBuffer(); + MTL::RenderPassColorAttachmentDescriptor* colorAttachment = MTL::RenderPassColorAttachmentDescriptor::alloc()->init(); + colorAttachment->setClearColor(MTL::ClearColor(0, 0, 0, 0)); + colorAttachment->setTexture(drawable->texture()); + colorAttachment->setLoadAction(MTL::LoadActionClear); + colorAttachment->setStoreAction(MTL::StoreActionStore); + renderPass->colorAttachments()->setObject(colorAttachment, 0); + renderEncoder = renderCmd->renderCommandEncoder(renderPass); + ImGui_ImplMetal_NewFrame((__bridge id)renderPass); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); +} + +void MetalRenderer::update() +{ + ImGui::Render(); + ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), (__bridge id)renderCmd, (__bridge id)renderEncoder); + renderCmd->presentDrawable((const MTL::Drawable*)drawable); + renderCmd->commit(); +} + +void MetalRenderer::render(Camera camera, RenderParameter parameter) +{ + GPUCamera gpuCam = { + .cameraPosition = camera.position, + .A = camera.A, + .cameraForward = camera.target - camera.position, + .f = camera.f, + .S_O = camera.S_O, + .sensorSize = camera.sensorSize, + .width = parameter.width, + .height = parameter.height, + }; + + MTL::TextureDescriptor* texDescriptor = MTL::TextureDescriptor::alloc()->init(); + texDescriptor->setWidth(parameter.width); + texDescriptor->setHeight(parameter.height); + texDescriptor->setPixelFormat(MTL::PixelFormatRGBA32Float); + texDescriptor->setUsage(MTL::TextureUsageShaderWrite | MTL::TextureUsageShaderRead); + accumulator = device->newTexture(texDescriptor); + resultTexture = device->newTexture(texDescriptor); + for (uint i = 0; i < parameter.numSamples; ++i) + { + MTL::CommandBuffer* cmdBuffer = queue->commandBuffer(); + MTL::ComputeCommandEncoder* encoder = cmdBuffer->computeCommandEncoder(); + // cmdBuffer->addCompletedHandler([this](MTL::CommandBuffer* cmdBuffer) + // { std::memcpy(image.data(), resultTexture->buffer(), image.size() * sizeof(glm::vec3)); }); + + SampleParams sample = { + .pass = i, + .samplesPerPixel = parameter.numSamples, + .numDirectionalLights = scene->getNumDirLights(), + .numPointLights = scene->getNumPointLights(), + }; + encoder->setComputePipelineState(computePipeline); + encoder->setBuffer(scene->indicesBuffer, 0, 0); + encoder->setBuffer(scene->positionBuffer, 0, 1); + encoder->setBuffer(scene->texCoordsBuffer, 0, 2); + encoder->setBuffer(scene->normalBuffer, 0, 3); + encoder->setBuffer(scene->modelRefsBuffer, 0, 4); + encoder->setBuffer(scene->directionalLightBuffer, 0, 5); + encoder->setBuffer(scene->pointLightBuffer, 0, 6); + encoder->setBuffer(scene->instanceBuffer, 0, 7); + encoder->setAccelerationStructure(scene->accelerationStructure, 8); + encoder->setTexture(accumulator, 0); + encoder->setTexture(resultTexture, 1); + encoder->setBytes(&gpuCam, sizeof(GPUCamera), 9); + encoder->setBytes(&sample, sizeof(SampleParams), 10); + encoder->useResource(scene->instanceBuffer, MTL::ResourceUsageRead); + encoder->useResource(scene->positionBuffer, MTL::ResourceUsageRead); + encoder->useResource(scene->texCoordsBuffer, MTL::ResourceUsageRead); + encoder->useResource(scene->normalBuffer, MTL::ResourceUsageRead); + encoder->useResource(scene->modelRefsBuffer, MTL::ResourceUsageRead); + if (scene->getNumDirLights() > 0) + { + encoder->useResource(scene->directionalLightBuffer, MTL::ResourceUsageRead); + } + if (scene->getNumPointLights() > 0) + { + encoder->useResource(scene->pointLightBuffer, MTL::ResourceUsageRead); + } + encoder->useResource(scene->instanceBuffer, MTL::ResourceUsageRead); + encoder->useResource(scene->accelerationStructure, MTL::ResourceUsageRead); + encoder->useResource(accumulator, MTL::ResourceUsageWrite); + encoder->useResource(resultTexture, MTL::ResourceUsageWrite); + NS::UInteger width = (NS::UInteger)parameter.width; + NS::UInteger height = (NS::UInteger)parameter.height; + MTL::Size threadsPerThreadgroup = MTL::Size(8, 8, 1); + MTL::Size threadgroups = MTL::Size((width + threadsPerThreadgroup.width - 1) / threadsPerThreadgroup.width, + (height + threadsPerThreadgroup.height - 1) / threadsPerThreadgroup.height, 1); + encoder->dispatchThreadgroups(threadgroups, threadsPerThreadgroup); + encoder->endEncoding(); + MTL::BlitCommandEncoder* blitCommandEncoder = cmdBuffer->blitCommandEncoder(); + blitCommandEncoder->copyFromTexture(resultTexture, 0, 0, MTL::Origin(), MTL::Size(parameter.width, parameter.height, 1), drawable->texture(), 0, 0, MTL::Origin()); + cmdBuffer->commit(); + cmdBuffer->waitUntilCompleted(); + } +} diff --git a/src/metal/MetalScene.cpp b/src/metal/MetalScene.cpp deleted file mode 100644 index 6ad840c..0000000 --- a/src/metal/MetalScene.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "MetalScene.h" - -MetalScene::MetalScene(MTL::Device* device, MTL::CommandQueue* queue) - : device(device), queue(queue) -{ -} - -MetalScene::~MetalScene() -{ - -} - -void MetalScene::createRayTracingHierarchy() -{ - indicesBuffer = device->newBuffer(indicesPool.size() * sizeof(decltype(indicesPool)::value_type), MTL::ResourceStorageModeShared); - positionBuffer = device->newBuffer(positionPool.size() * sizeof(decltype(positionPool)::value_type), MTL::ResourceStorageModeShared); - texCoordsBuffer = device->newBuffer(texCoordsPool.size() * sizeof(decltype(texCoordsPool)::value_type), MTL::ResourceStorageModeShared); - normalBuffer = device->newBuffer(normalsPool.size() * sizeof(decltype(normalsPool)::value_type), MTL::ResourceStorageModeShared); - modelRefsBuffer = device->newBuffer(refs.size() * sizeof(decltype(refs)::value_type), MTL::ResourceStorageModeShared); - if(directionalLights.size() > 0) - { - directionalLightBuffer = device->newBuffer(directionalLights.size() * sizeof(decltype(directionalLights)::value_type), MTL::ResourceStorageModeShared); - std::memcpy(directionalLightBuffer->contents(), directionalLights.data(), directionalLights.size() * sizeof(decltype(directionalLights)::value_type)); - } - if(pointLights.size() > 0) - { - pointLightBuffer = device->newBuffer(pointLights.size() * sizeof(decltype(pointLights)::value_type), MTL::ResourceStorageModeShared); - std::memcpy(pointLightBuffer->contents(), pointLights.data(), pointLights.size() * sizeof(decltype(pointLights)::value_type)); - } - - std::memcpy(indicesBuffer->contents(), indicesPool.data(), indicesPool.size() * sizeof(decltype(indicesPool)::value_type)); - std::memcpy(positionBuffer->contents(), positionPool.data(), positionPool.size() * sizeof(decltype(positionPool)::value_type)); - std::memcpy(texCoordsBuffer->contents(), texCoordsPool.data(), texCoordsPool.size() * sizeof(decltype(texCoordsPool)::value_type)); - std::memcpy(normalBuffer->contents(), normalsPool.data(), normalsPool.size() * sizeof(decltype(normalsPool)::value_type)); - std::memcpy(modelRefsBuffer->contents(), refs.data(), refs.size() * sizeof(decltype(refs)::value_type)); - - MTL::AccelerationStructure** primitiveAccelerationStructures = new MTL::AccelerationStructure*[refs.size()]; - for(uint i = 0; i < refs.size(); ++i) - { - MTL::AccelerationStructureTriangleGeometryDescriptor* descriptor = MTL::AccelerationStructureTriangleGeometryDescriptor::descriptor(); - descriptor->setTriangleCount(refs[i].numIndices / 3); - descriptor->setIndexBuffer(indicesBuffer); - descriptor->setIndexBufferOffset(refs[i].indicesOffset * sizeof(glm::uvec3)); - descriptor->setIndexType(MTL::IndexTypeUInt32); - descriptor->setVertexBuffer(positionBuffer); - descriptor->setVertexBufferOffset(refs[i].positionOffset * sizeof(glm::vec3)); - - MTL::PrimitiveAccelerationStructureDescriptor* primitiveDescriptor = MTL::PrimitiveAccelerationStructureDescriptor::descriptor(); - primitiveDescriptor->setGeometryDescriptors(NS::Array::array(descriptor)); - - primitiveAccelerationStructures[i] = device->newAccelerationStructure(primitiveDescriptor); - primitiveAccelerationStructures[i]->setLabel(NS::String::string("Primitive Structure", NS::ASCIIStringEncoding)); - std::cout << primitiveAccelerationStructures[i]->debugDescription()->cString(NS::ASCIIStringEncoding) << std::endl; - } - NS::Array* primitiveArray = NS::Array::array((const NS::Object* const*)primitiveAccelerationStructures, refs.size()); - std::cout << primitiveArray->debugDescription()->cString(NS::ASCIIStringEncoding) << std::endl; - instanceBuffer = device->newBuffer(sizeof(MTL::AccelerationStructureInstanceDescriptor) * refs.size(), MTL::ResourceOptionCPUCacheModeDefault); - - MTL::AccelerationStructureInstanceDescriptor* instanceDescriptors = (MTL::AccelerationStructureInstanceDescriptor*)instanceBuffer->contents(); - for(uint i = 0; i < refs.size(); ++i) - { - instanceDescriptors[i].transformationMatrix[0][0] = 1.0f; - instanceDescriptors[i].transformationMatrix[1][0] = 0.0f; - instanceDescriptors[i].transformationMatrix[2][0] = 0.0f; - instanceDescriptors[i].transformationMatrix[3][0] = 0.0f; - - instanceDescriptors[i].transformationMatrix[0][1] = 0.0f; - instanceDescriptors[i].transformationMatrix[1][1] = 1.0f; - instanceDescriptors[i].transformationMatrix[2][1] = 0.0f; - instanceDescriptors[i].transformationMatrix[3][1] = 0.0f; - - instanceDescriptors[i].transformationMatrix[0][2] = 0.0f; - instanceDescriptors[i].transformationMatrix[1][2] = 0.0f; - instanceDescriptors[i].transformationMatrix[2][2] = 1.0f; - instanceDescriptors[i].transformationMatrix[3][2] = 0.0f; - - instanceDescriptors[i].accelerationStructureIndex = i; - - instanceDescriptors[i].options = MTL::AccelerationStructureInstanceOptionOpaque; - instanceDescriptors[i].mask = 0xff; - } - - MTL::InstanceAccelerationStructureDescriptor* accelDesc = MTL::InstanceAccelerationStructureDescriptor::descriptor(); - accelDesc->setInstancedAccelerationStructures(primitiveArray); - accelDesc->setInstanceDescriptorBuffer(instanceBuffer); - accelDesc->setInstanceCount(refs.size()); - - MTL::AccelerationStructureSizes accelSizes = device->accelerationStructureSizes(accelDesc); - MTL::AccelerationStructure* tempStructure = device->newAccelerationStructure(accelSizes.accelerationStructureSize); - tempStructure->setLabel(NS::String::string("Temporary AS", NS::ASCIIStringEncoding)); - MTL::Buffer* scratchBuffer = device->newBuffer(accelSizes.buildScratchBufferSize, MTL::StorageModeManaged); - MTL::CommandBuffer* cmdBuffer = queue->commandBuffer(); - MTL::AccelerationStructureCommandEncoder* encoder = cmdBuffer->accelerationStructureCommandEncoder(); - MTL::Buffer* compactedBuffer = device->newBuffer(sizeof(uint), MTL::ResourceOptionCPUCacheModeDefault); - encoder->buildAccelerationStructure(tempStructure, accelDesc, scratchBuffer, 0); - encoder->writeCompactedAccelerationStructureSize(tempStructure, compactedBuffer, 0); - encoder->endEncoding(); - cmdBuffer->commit(); - cmdBuffer->waitUntilCompleted(); - uint compactedSize = *(uint*)compactedBuffer->contents(); - accelerationStructure = device->newAccelerationStructure(compactedSize); - accelerationStructure->setLabel(NS::String::string("Instance AS", NS::ASCIIStringEncoding)); - cmdBuffer = queue->commandBuffer(); - encoder = cmdBuffer->accelerationStructureCommandEncoder(); - encoder->copyAndCompactAccelerationStructure(tempStructure, accelerationStructure); - encoder->endEncoding(); - cmdBuffer->commit(); - cmdBuffer->waitUntilCompleted(); -} diff --git a/src/metal/MetalScene.mm b/src/metal/MetalScene.mm new file mode 100644 index 0000000..d2726ba --- /dev/null +++ b/src/metal/MetalScene.mm @@ -0,0 +1,107 @@ +#include "MetalScene.h" + +MetalScene::MetalScene(MTL::Device* device, MTL::CommandQueue* queue) : device(device), queue(queue) {} + +MetalScene::~MetalScene() {} + +void MetalScene::createRayTracingHierarchy() +{ + indicesBuffer = device->newBuffer(indicesPool.size() * sizeof(decltype(indicesPool)::value_type), MTL::ResourceStorageModeShared); + positionBuffer = device->newBuffer(positionPool.size() * sizeof(decltype(positionPool)::value_type), MTL::ResourceStorageModeShared); + texCoordsBuffer = device->newBuffer(texCoordsPool.size() * sizeof(decltype(texCoordsPool)::value_type), MTL::ResourceStorageModeShared); + normalBuffer = device->newBuffer(normalsPool.size() * sizeof(decltype(normalsPool)::value_type), MTL::ResourceStorageModeShared); + modelRefsBuffer = device->newBuffer(refs.size() * sizeof(decltype(refs)::value_type), MTL::ResourceStorageModeShared); + if (directionalLights.size() > 0) + { + directionalLightBuffer = + device->newBuffer(directionalLights.size() * sizeof(decltype(directionalLights)::value_type), MTL::ResourceStorageModeShared); + std::memcpy(directionalLightBuffer->contents(), directionalLights.data(), + directionalLights.size() * sizeof(decltype(directionalLights)::value_type)); + } + if (pointLights.size() > 0) + { + pointLightBuffer = device->newBuffer(pointLights.size() * sizeof(decltype(pointLights)::value_type), MTL::ResourceStorageModeShared); + std::memcpy(pointLightBuffer->contents(), pointLights.data(), pointLights.size() * sizeof(decltype(pointLights)::value_type)); + } + + std::memcpy(indicesBuffer->contents(), indicesPool.data(), indicesPool.size() * sizeof(decltype(indicesPool)::value_type)); + std::memcpy(positionBuffer->contents(), positionPool.data(), positionPool.size() * sizeof(decltype(positionPool)::value_type)); + std::memcpy(texCoordsBuffer->contents(), texCoordsPool.data(), texCoordsPool.size() * sizeof(decltype(texCoordsPool)::value_type)); + std::memcpy(normalBuffer->contents(), normalsPool.data(), normalsPool.size() * sizeof(decltype(normalsPool)::value_type)); + std::memcpy(modelRefsBuffer->contents(), refs.data(), refs.size() * sizeof(decltype(refs)::value_type)); + + CFTypeRef* descriptors = new CFTypeRef[refs.size()]; + MTL::AccelerationStructure** primitiveAccelerationStructures = new MTL::AccelerationStructure*[refs.size()]; + for (uint i = 0; i < refs.size(); ++i) + { + MTL::AccelerationStructureTriangleGeometryDescriptor* descriptor = MTL::AccelerationStructureTriangleGeometryDescriptor::descriptor(); + descriptor->setTriangleCount(refs[i].numIndices / 3); + descriptor->setIndexBuffer(indicesBuffer); + descriptor->setIndexBufferOffset(refs[i].indicesOffset * sizeof(glm::uvec3)); + descriptor->setIndexType(MTL::IndexTypeUInt32); + descriptor->setVertexBuffer(positionBuffer); + descriptor->setVertexBufferOffset(refs[i].positionOffset * sizeof(glm::vec3)); + + MTL::PrimitiveAccelerationStructureDescriptor* primitiveDescriptor = MTL::PrimitiveAccelerationStructureDescriptor::descriptor(); + primitiveDescriptor->setGeometryDescriptors(NS::Array::array(descriptor)); + + primitiveAccelerationStructures[i] = device->newAccelerationStructure(primitiveDescriptor); + primitiveAccelerationStructures[i]->setLabel(NS::String::string("Primitive Structure", NS::ASCIIStringEncoding)); + std::cout << primitiveAccelerationStructures[i]->debugDescription()->cString(NS::ASCIIStringEncoding) << std::endl; + descriptors[i] = (CFTypeRef)primitiveAccelerationStructures[i]; + } + instanceBuffer = + device->newBuffer(sizeof(MTL::AccelerationStructureInstanceDescriptor) * refs.size(), MTL::ResourceOptionCPUCacheModeDefault); + + MTL::AccelerationStructureInstanceDescriptor* instanceDescriptors = + (MTL::AccelerationStructureInstanceDescriptor*)instanceBuffer->contents(); + for (uint i = 0; i < refs.size(); ++i) + { + instanceDescriptors[i].transformationMatrix[0][0] = 1.0f; + instanceDescriptors[i].transformationMatrix[1][0] = 0.0f; + instanceDescriptors[i].transformationMatrix[2][0] = 0.0f; + instanceDescriptors[i].transformationMatrix[3][0] = 0.0f; + + instanceDescriptors[i].transformationMatrix[0][1] = 0.0f; + instanceDescriptors[i].transformationMatrix[1][1] = 1.0f; + instanceDescriptors[i].transformationMatrix[2][1] = 0.0f; + instanceDescriptors[i].transformationMatrix[3][1] = 0.0f; + + instanceDescriptors[i].transformationMatrix[0][2] = 0.0f; + instanceDescriptors[i].transformationMatrix[1][2] = 0.0f; + instanceDescriptors[i].transformationMatrix[2][2] = 1.0f; + instanceDescriptors[i].transformationMatrix[3][2] = 0.0f; + + instanceDescriptors[i].accelerationStructureIndex = i; + + instanceDescriptors[i].options = MTL::AccelerationStructureInstanceOptionOpaque; + instanceDescriptors[i].mask = 0xff; + } + NS::Array* pGeoDescriptors = ( NS::Array* )( CFArrayCreate( kCFAllocatorDefault, descriptors, refs.size(), &kCFTypeArrayCallBacks ) ); + MTL::InstanceAccelerationStructureDescriptor* accelDesc = MTL::InstanceAccelerationStructureDescriptor::descriptor(); + accelDesc->setInstancedAccelerationStructures(pGeoDescriptors); + accelDesc->setInstanceDescriptorBuffer(instanceBuffer); + accelDesc->setInstanceCount(refs.size()); + + MTL::AccelerationStructureSizes accelSizes = device->accelerationStructureSizes(accelDesc); + MTL::AccelerationStructure* tempStructure = device->newAccelerationStructure(accelSizes.accelerationStructureSize); + tempStructure->setLabel(NS::String::string("Temporary AS", NS::ASCIIStringEncoding)); + MTL::Buffer* scratchBuffer = device->newBuffer(accelSizes.buildScratchBufferSize, MTL::StorageModeManaged); + MTL::CommandBuffer* cmdBuffer = queue->commandBuffer(); + MTL::AccelerationStructureCommandEncoder* encoder = cmdBuffer->accelerationStructureCommandEncoder(); + MTL::Buffer* compactedBuffer = device->newBuffer(sizeof(uint), MTL::ResourceOptionCPUCacheModeDefault); + encoder->buildAccelerationStructure(tempStructure, accelDesc, scratchBuffer, 0); + encoder->writeCompactedAccelerationStructureSize(tempStructure, compactedBuffer, 0); + encoder->endEncoding(); + cmdBuffer->commit(); + cmdBuffer->waitUntilCompleted(); + uint compactedSize = *(uint*)compactedBuffer->contents(); + accelerationStructure = device->newAccelerationStructure(compactedSize); + accelerationStructure->setLabel(NS::String::string("Instance AS", NS::ASCIIStringEncoding)); + cmdBuffer = queue->commandBuffer(); + encoder = cmdBuffer->accelerationStructureCommandEncoder(); + encoder->copyAndCompactAccelerationStructure(tempStructure, accelerationStructure); + encoder->endEncoding(); + cmdBuffer->commit(); + cmdBuffer->waitUntilCompleted(); +} diff --git a/src/metal/PrivateImpl.mm b/src/metal/PrivateImpl.mm index 63a9ca6..7fa7137 100644 --- a/src/metal/PrivateImpl.mm +++ b/src/metal/PrivateImpl.mm @@ -3,4 +3,4 @@ #define MTL_PRIVATE_IMPLEMENTATION #include #include -#include \ No newline at end of file +#include diff --git a/src/scene/Renderer.cpp b/src/scene/Renderer.cpp index 79bba4e..eae468d 100644 --- a/src/scene/Renderer.cpp +++ b/src/scene/Renderer.cpp @@ -16,8 +16,6 @@ void Renderer::startRender(Camera cam, RenderParameter params) worker.join(); } sampleTimes.clear(); - image.clear(); - image.resize(params.width * params.height); running = true; worker = std::thread(&Renderer::render, this, cam, params); } \ No newline at end of file diff --git a/src/scene/Renderer.h b/src/scene/Renderer.h index ca136b8..7acf44b 100644 --- a/src/scene/Renderer.h +++ b/src/scene/Renderer.h @@ -1,8 +1,7 @@ #pragma once #include "Scene.h" -#include "ThreadPool.h" #include "util/Camera.h" -#include "window/Window.h" +#include #include struct RenderParameter @@ -23,13 +22,15 @@ public: virtual void addModels(std::vector models, glm::mat4 transform) = 0; virtual void generate() = 0; void startRender(Camera cam, RenderParameter params); - constexpr const std::vector& getImage() const { return image; } constexpr const std::vector& getSampleTimes() const { return sampleTimes; } constexpr const float getLastSampleTime() const { return sampleTimes.empty() ? 0 : sampleTimes.back(); } constexpr const float getAverageSampleTime() const { return std::accumulate(sampleTimes.begin(), sampleTimes.end(), 0.0f) / sampleTimes.size(); } + // main thread + virtual void beginFrame() = 0; + virtual void update() = 0; protected: virtual void render(Camera cam, RenderParameter params) = 0; @@ -38,6 +39,4 @@ protected: std::vector sampleTimes; float lastSampleTime; float averageSampleTime; - // the thing being displayed - std::vector image; }; \ No newline at end of file diff --git a/src/window/CMakeLists.txt b/src/window/CMakeLists.txt deleted file mode 100644 index ddcf5a0..0000000 --- a/src/window/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -target_sources(RayTracer - PRIVATE - Window.h - Window.cpp) \ No newline at end of file diff --git a/src/window/Window.cpp b/src/window/Window.cpp deleted file mode 100644 index e6a5f5a..0000000 --- a/src/window/Window.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "Window.h" -#include -#include -#include -#include - -#define GLSL(...) "#version 400\n" #__VA_ARGS__ - -Window::Window(int width, int height) : width(width), height(height) -{ - glewExperimental = true; - glfwInit(); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We don't want the old OpenGL - window = glfwCreateWindow(width, height, "RayTracer", nullptr, nullptr); - glfwSwapInterval(1); - glfwMakeContextCurrent(window); - - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls - - ImGui_ImplGlfw_InitForOpenGL(window, - true); // Second param install_callback=true will install GLFW callbacks and chain to existing ones. - ImGui_ImplOpenGL3_Init(); - - glewInit(); - - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - program = glCreateProgram(); - vertShader = glCreateShader(GL_VERTEX_SHADER); - fragShader = glCreateShader(GL_FRAGMENT_SHADER); - int logLen = 0; - const char* vertCode = - GLSL(out vec2 texcoords; // texcoords are in the normalized [0,1] range for the viewport-filling quad part of the triangle - void main() { - vec2 vertices[3] = vec2[3](vec2(-1, -1), vec2(3, -1), vec2(-1, 3)); - gl_Position = vec4(vertices[gl_VertexID], 0, 1); - texcoords = 0.5 * gl_Position.xy + vec2(0.5); - }); - const char* fragCode = GLSL(in vec2 texcoords; out vec4 color; - - uniform sampler2D tex; - - void main() { color = texture(tex, vec2(texcoords.x, -texcoords.y)); }); - glShaderSource(vertShader, 1, &vertCode, nullptr); - glCompileShader(vertShader); - int success; - char infoLog[1024]; - glGetShaderiv(vertShader, GL_COMPILE_STATUS, &success); - if (!success) - { - glGetShaderInfoLog(vertShader, 1024, NULL, infoLog); - std::cout << "ERROR::SHADER_COMPILATION_ERROR\n" - << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; - } - - glShaderSource(fragShader, 1, &fragCode, nullptr); - glCompileShader(fragShader); - glGetShaderiv(fragShader, GL_COMPILE_STATUS, &success); - if (!success) - { - glGetShaderInfoLog(fragShader, 1024, NULL, infoLog); - std::cout << "ERROR::SHADER_COMPILATION_ERROR\n" - << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; - } - - glAttachShader(program, vertShader); - glAttachShader(program, fragShader); - - glLinkProgram(program); - glGetProgramiv(program, GL_LINK_STATUS, &logLen); - if (logLen > 0) - { - std::vector log(logLen); - glGetProgramInfoLog(program, logLen, &logLen, log.data()); - std::cout << log.data() << std::endl; - } - glDeleteShader(vertShader); - glDeleteShader(fragShader); - glClearColor(0, 0, 0, 0); -} - -Window::~Window() {} - -void Window::beginFrame() -{ - glClear(GL_COLOR_BUFFER_BIT); - glfwPollEvents(); - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); -} - -void Window::update(const std::vector& textureData) -{ - glBindTexture(GL_TEXTURE_2D, texture); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_FLOAT, textureData.data()); - glUseProgram(program); - glDrawArrays(GL_TRIANGLES, 0, 3); - ImGui::Render(); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - glfwSwapBuffers(window); -} diff --git a/src/window/Window.h b/src/window/Window.h deleted file mode 100644 index c31d48b..0000000 --- a/src/window/Window.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include -#include -#include -#include - -class Window -{ - public: - Window(int width, int height); - ~Window(); - void beginFrame(); - void update(const std::vector& textureData); - - private: - int width; - int height; - GLuint vao; - GLuint texture; - GLuint program; - GLuint vertShader; - GLuint fragShader; - GLFWwindow* window; -}; \ No newline at end of file diff --git a/vcpkg.json b/vcpkg.json index 0a8b6aa..d1ee63f 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -2,7 +2,7 @@ "dependencies": [ { "name": "imgui", - "features": [ "glfw-binding", "opengl3-binding" ] + "features": [ "glfw-binding", "opengl3-binding", "metal-binding" ] }, "vulkan", "vulkan-memory-allocator",