i hate metal cpp

This commit is contained in:
Dynamitos
2025-02-27 20:25:53 +09:00
parent 961cb527af
commit 3fa51f7152
23 changed files with 525 additions and 437 deletions
+1 -1
View File
@@ -11,7 +11,7 @@
"program": "${workspaceFolder}/build/Debug/RayTracer", "program": "${workspaceFolder}/build/Debug/RayTracer",
"args": [], "args": [],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}/build", "cwd": "${workspaceFolder}/build/Debug",
"environment": [], "environment": [],
"externalConsole": false, "externalConsole": false,
"MIMode": "lldb" "MIMode": "lldb"
+6 -7
View File
@@ -19,9 +19,6 @@ find_package(glfw3 CONFIG REQUIRED)
find_package(glm CONFIG REQUIRED) find_package(glm CONFIG REQUIRED)
find_package(Ktx CONFIG REQUIRED) find_package(Ktx CONFIG REQUIRED)
find_package(imgui 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 "") add_executable(RayTracer "")
target_include_directories(RayTracer PUBLIC src/) target_include_directories(RayTracer PUBLIC src/)
@@ -40,12 +37,14 @@ target_link_libraries(RayTracer PUBLIC ${VCPKG_INSTALLED_DIR}/x64-windows/lib/sl
elseif(APPLE) elseif(APPLE)
target_include_directories(RayTracer PUBLIC ${VCPKG_INSTALLED_DIR}/arm64-osx/include) target_include_directories(RayTracer PUBLIC ${VCPKG_INSTALLED_DIR}/arm64-osx/include)
target_include_directories(RayTracer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/external/metal-cpp) 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 target_link_libraries(RayTracer PUBLIC
${APPLE_FWK_FOUNDATION} "-framework Metal"
${APPLE_FWK_QUARTZ_CORE} "-framework MetalKit"
${APPLE_FWK_METAL} "-framework AppKit"
"-framework Foundation"
"-framework QuartzCore"
) )
endif() endif()
-1
View File
@@ -11,5 +11,4 @@ if(APPLE)
add_subdirectory(metal/) add_subdirectory(metal/)
endif() endif()
add_subdirectory(scene/) add_subdirectory(scene/)
add_subdirectory(window/)
add_subdirectory(util/) add_subdirectory(util/)
-14
View File
@@ -1,6 +1,4 @@
#pragma once #pragma once
#include <coroutine>
#include <memory>
#define DEFINE_REF(x) typedef ::std::unique_ptr<x> P##x; #define DEFINE_REF(x) typedef ::std::unique_ptr<x> P##x;
@@ -8,15 +6,3 @@
class x; \ class x; \
typedef ::std::unique_ptr<x> P##x; typedef ::std::unique_ptr<x> P##x;
struct Task
{
struct promise_type
{
Task get_return_object() { return {std::coroutine_handle<promise_type>::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<promise_type> handle;
};
+13
View File
@@ -4,7 +4,20 @@
#include <list> #include <list>
#include <thread> #include <thread>
#include "Minimal.h" #include "Minimal.h"
#include <coroutine>
struct Task
{
struct promise_type
{
Task get_return_object() { return {std::coroutine_handle<promise_type>::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<promise_type> handle;
};
struct Batch struct Batch
{ {
std::list<Task> jobs; std::list<Task> jobs;
+115 -3
View File
@@ -1,5 +1,95 @@
#include "CPURenderer.h" #include "CPURenderer.h"
#include "scene/Renderer.h" #include "scene/Renderer.h"
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#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<char> 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) glm::vec3 rand01(glm::uvec3 x)
{ // pseudo-random number generator { // pseudo-random number generator
@@ -8,10 +98,32 @@ glm::vec3 rand01(glm::uvec3 x)
return glm::vec3(x) * (1.0f / float(0xffffffffU)); 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) void CPURenderer::render(Camera camera, RenderParameter params)
{ {
accumulator.clear(); image.clear();
accumulator.resize(params.width * params.height); image.resize(params.width * params.height);
accumulator.clear();
accumulator.resize(params.width * params.height);
for (int samp = 0; samp < params.numSamples; ++samp) for (int samp = 0; samp < params.numSamples; ++samp)
{ {
if (!running) if (!running)
@@ -64,7 +176,7 @@ void CPURenderer::render(Camera camera, RenderParameter params)
scene->traceRay(r, payload, 1e-4, 1e20); 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); 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)); image[w + h * params.width] = glm::pow(glm::max(accumulator[w + h * params.width] * resolver, 0.0f), glm::vec3(0.45f));
} }
+25 -1
View File
@@ -2,14 +2,38 @@
#include "cpu/CPUScene.h" #include "cpu/CPUScene.h"
#include "scene/Renderer.h" #include "scene/Renderer.h"
#include "util/Camera.h" #include "util/Camera.h"
#include "ThreadPool.h"
#include <GL/glew.h>
#include <glfw/glfw3.h>
class CPURenderer : public Renderer class CPURenderer : public Renderer
{ {
public: 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<PModel> 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; virtual void render(Camera camera, RenderParameter params) override;
private:
CPUScene* scene; CPUScene* scene;
ThreadPool threadPool; ThreadPool threadPool;
// radiance accumulator // radiance accumulator
std::vector<glm::vec3> accumulator; std::vector<glm::vec3> accumulator;
// the thing being displayed
std::vector<glm::vec3> image;
int width;
int height;
GLuint vao;
GLuint texture;
GLuint program;
GLuint vertShader;
GLuint fragShader;
GLFWwindow* window;
}; };
+3
View File
@@ -19,6 +19,9 @@ public:
virtual void generate() override { scene->generate(); } virtual void generate() override { scene->generate(); }
virtual void render(Camera cam, RenderParameter param) override; virtual void render(Camera cam, RenderParameter param) override;
virtual void beginFrame() override;
virtual void update() override;
private: private:
struct GPUCamera struct GPUCamera
{ {
+21 -22
View File
@@ -1,26 +1,24 @@
#include "scene/Renderer.h"
#include "metal/MetalRenderer.h" #include "metal/MetalRenderer.h"
#include "window/Window.h" #include "scene/Renderer.h"
#include "util/ModelLoader.h" #include "util/ModelLoader.h"
#include <imgui.h> #include <imgui.h>
int main() int main()
{ {
std::unique_ptr<Renderer> scene = std::make_unique<MetalRenderer>(); std::unique_ptr<Renderer> renderer = std::make_unique<MetalRenderer>();
scene->addDirectionalLight(DirectionalLight{ renderer->addDirectionalLight(DirectionalLight{
.direction = glm::normalize(glm::vec3(-0.4f, -0.3f, -0.2f)), .direction = glm::normalize(glm::vec3(-0.4f, -0.3f, -0.2f)),
.color = glm::vec3(1, 1, 1), .color = glm::vec3(1, 1, 1),
}); });
scene->addPointLight(PointLight{}); renderer->addPointLight(PointLight{});
scene->addModels(ModelLoader::loadModel("../../res/models/cube.fbx"), 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::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))); glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)));
scene->addModels(ModelLoader::loadModel("../../res/models/cube.fbx"), 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::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))); glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)));
scene->generate(); renderer->generate();
Window window(1920, 1080);
Camera camera = Camera{ Camera camera = Camera{
.position = glm::vec3(5, 1, 2), .position = glm::vec3(5, 1, 2),
.target = glm::vec3(0, 0, 0), .target = glm::vec3(0, 0, 0),
@@ -31,11 +29,11 @@ int main()
.height = 1080, .height = 1080,
.numSamples = 10000, .numSamples = 10000,
}; };
scene->startRender(camera, render); renderer->startRender(camera, render);
while (true) while (true)
{ {
window.beginFrame(); renderer->beginFrame();
ImGui::Text("Camera Parameters"); ImGui::Text("Camera Parameters");
ImGui::InputFloat3("Position", &camera.position.x); ImGui::InputFloat3("Position", &camera.position.x);
ImGui::InputFloat3("Target", &camera.target.x); ImGui::InputFloat3("Target", &camera.target.x);
@@ -47,13 +45,14 @@ int main()
ImGui::InputInt("Samples", (int*)&render.numSamples); ImGui::InputInt("Samples", (int*)&render.numSamples);
if (ImGui::Button("Render")) if (ImGui::Button("Render"))
{ {
scene->startRender(camera, render); renderer->startRender(camera, render);
} }
ImGui::Text("Render Stats"); ImGui::Text("Render Stats");
ImGui::Text("Last Sample Time: %.3f ms", scene->getLastSampleTime()); ImGui::Text("Last Sample Time: %.3f ms", renderer->getLastSampleTime());
ImGui::Text("Average Sample Time: %.3f ms", scene->getAverageSampleTime()); ImGui::Text("Average Sample Time: %.3f ms", renderer->getAverageSampleTime());
ImGui::PlotLines("Sample Times", scene->getSampleTimes().data(), scene->getSampleTimes().size(), 0, 0, FLT_MAX, FLT_MAX, ImVec2(0, 40)); ImGui::PlotLines("Sample Times", renderer->getSampleTimes().data(), renderer->getSampleTimes().size(), 0, 0, FLT_MAX, FLT_MAX,
window.update(scene->getImage()); ImVec2(0, 40));
renderer->update();
} }
return 0; return 0;
} }
+2 -2
View File
@@ -1,8 +1,8 @@
target_sources(RayTracer target_sources(RayTracer
PRIVATE PRIVATE
MetalRenderer.h MetalRenderer.h
MetalRenderer.cpp MetalRenderer.mm
MetalScene.h MetalScene.h
MetalScene.cpp MetalScene.mm
Compute.metal Compute.metal
PrivateImpl.mm) PrivateImpl.mm)
+6 -4
View File
@@ -133,8 +133,8 @@ kernel void computeKernel(
constant PointLight* pointLights [[buffer(6)]], constant PointLight* pointLights [[buffer(6)]],
constant MTLAccelerationStructureInstanceDescriptor* instances [[buffer(7)]], constant MTLAccelerationStructureInstanceDescriptor* instances [[buffer(7)]],
instance_acceleration_structure accelerationStructure [[buffer(8)]], instance_acceleration_structure accelerationStructure [[buffer(8)]],
device packed_float3* accumulator [[buffer(9)]], texture2d<float, access::read_write> accumulator [[texture(0)]],
device packed_float3* image [[buffer(10)]] texture2d<float, access::read_write> image [[texture(1)]]
) )
{ {
Payload payload; Payload payload;
@@ -267,6 +267,8 @@ kernel void computeKernel(
payload.depth++; payload.depth++;
} }
float resolver = float(sample.samplesPerPixel) / float(sample.pass+1); float resolver = float(sample.samplesPerPixel) / float(sample.pass+1);
accumulator[threadId.x + threadId.y * camera.width] += payload.accumulatedRadiance / float(sample.samplesPerPixel); float4 previous = accumulator.read(threadId);
image[threadId.x + threadId.y * camera.width] = pow(max(accumulator[threadId.x + threadId.y * camera.width] * resolver, 0), float3(0.45f)); 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);
} }
-96
View File
@@ -1,96 +0,0 @@
#include "MetalRenderer.h"
#include "metal/MetalScene.h"
#include "scene/Renderer.h"
#include "util/Camera.h"
#include <Foundation/Foundation.hpp>
#include <Metal/Metal.hpp>
#include <QuartzCore/QuartzCore.hpp>
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));
}
}
+45 -23
View File
@@ -2,8 +2,14 @@
#include "metal/MetalScene.h" #include "metal/MetalScene.h"
#include "scene/Renderer.h" #include "scene/Renderer.h"
#include "util/Camera.h" #include "util/Camera.h"
#include <Foundation/Foundation.hpp>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#define GLFW_EXPOSE_NATIVE_COCOA
#include <GLFW/glfw3native.h>
#include <Metal/Metal.hpp> #include <Metal/Metal.hpp>
#include <QuartzCore/CAMetalLayer.hpp>
#include <QuartzCore/QuartzCore.hpp> #include <QuartzCore/QuartzCore.hpp>
struct GPUCamera struct GPUCamera
@@ -17,38 +23,54 @@ struct GPUCamera
float A; float A;
float ka; float ka;
glm::vec2 sensorSize; glm::vec2 sensorSize;
uint width; uint width;
uint height; uint height;
}; };
struct SampleParams struct SampleParams
{ {
uint pass; uint pass;
uint samplesPerPixel; uint samplesPerPixel;
uint numDirectionalLights; uint numDirectionalLights;
uint numPointLights; uint numPointLights;
}; };
class MetalRenderer : public Renderer class MetalRenderer : public Renderer
{ {
public: public:
MetalRenderer(); MetalRenderer();
virtual ~MetalRenderer(); virtual ~MetalRenderer();
virtual void addPointLight(PointLight point) override { scene->addPointLight(point); } virtual void addPointLight(PointLight point) override { scene->addPointLight(point); }
virtual void addDirectionalLight(DirectionalLight dir) override { scene->addDirectionalLight(dir); } 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 addModel(PModel model, glm::mat4 transform) override { scene->addModel(std::move(model), transform); }
virtual void addModels(std::vector<PModel> models, glm::mat4 transform) override { scene->addModels(std::move(models), transform); } virtual void addModels(std::vector<PModel> models, glm::mat4 transform) override { scene->addModels(std::move(models), transform); }
virtual void generate() override { scene->generate(); } virtual void generate() override { scene->generate(); }
virtual void render(Camera camera, RenderParameter params) override; virtual void render(Camera camera, RenderParameter params) override;
virtual void beginFrame() override;
virtual void update() override;
private: private:
MTL::Device* device; uint width;
MTL::Library* library; uint height;
MTL::CommandQueue* queue; uint framebufferWidth;
MTL::Function* function; uint framebufferHeight;
MTL::ComputePipelineState* computePipeline; GLFWwindow* handle;
MTL::Buffer* accumulator; CA::MetalLayer* metalLayer;
MTL::Buffer* resultTexture; CA::MetalDrawable* drawable;
MetalScene* scene; 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;
}; };
+172
View File
@@ -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 <Foundation/Foundation.hpp>
#include <GLFW/glfw3.h>
#include <Metal/Metal.hpp>
#include <QuartzCore/QuartzCore.hpp>
#include <QuartzCore/CAMetalLayer.h>
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_metal.h>
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();
}
}
-109
View File
@@ -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();
}
+107
View File
@@ -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();
}
-2
View File
@@ -16,8 +16,6 @@ void Renderer::startRender(Camera cam, RenderParameter params)
worker.join(); worker.join();
} }
sampleTimes.clear(); sampleTimes.clear();
image.clear();
image.resize(params.width * params.height);
running = true; running = true;
worker = std::thread(&Renderer::render, this, cam, params); worker = std::thread(&Renderer::render, this, cam, params);
} }
+4 -5
View File
@@ -1,8 +1,7 @@
#pragma once #pragma once
#include "Scene.h" #include "Scene.h"
#include "ThreadPool.h"
#include "util/Camera.h" #include "util/Camera.h"
#include "window/Window.h" #include <thread>
#include <numeric> #include <numeric>
struct RenderParameter struct RenderParameter
@@ -23,13 +22,15 @@ public:
virtual void addModels(std::vector<PModel> models, glm::mat4 transform) = 0; virtual void addModels(std::vector<PModel> models, glm::mat4 transform) = 0;
virtual void generate() = 0; virtual void generate() = 0;
void startRender(Camera cam, RenderParameter params); void startRender(Camera cam, RenderParameter params);
constexpr const std::vector<glm::vec3>& getImage() const { return image; }
constexpr const std::vector<float>& getSampleTimes() const { return sampleTimes; } constexpr const std::vector<float>& getSampleTimes() const { return sampleTimes; }
constexpr const float getLastSampleTime() const { return sampleTimes.empty() ? 0 : sampleTimes.back(); } constexpr const float getLastSampleTime() const { return sampleTimes.empty() ? 0 : sampleTimes.back(); }
constexpr const float getAverageSampleTime() const constexpr const float getAverageSampleTime() const
{ {
return std::accumulate(sampleTimes.begin(), sampleTimes.end(), 0.0f) / sampleTimes.size(); return std::accumulate(sampleTimes.begin(), sampleTimes.end(), 0.0f) / sampleTimes.size();
} }
// main thread
virtual void beginFrame() = 0;
virtual void update() = 0;
protected: protected:
virtual void render(Camera cam, RenderParameter params) = 0; virtual void render(Camera cam, RenderParameter params) = 0;
@@ -38,6 +39,4 @@ protected:
std::vector<float> sampleTimes; std::vector<float> sampleTimes;
float lastSampleTime; float lastSampleTime;
float averageSampleTime; float averageSampleTime;
// the thing being displayed
std::vector<glm::vec3> image;
}; };
-4
View File
@@ -1,4 +0,0 @@
target_sources(RayTracer
PRIVATE
Window.h
Window.cpp)
-114
View File
@@ -1,114 +0,0 @@
#include "Window.h"
#include <iostream>
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#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<char> 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<glm::vec3>& 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);
}
-24
View File
@@ -1,24 +0,0 @@
#pragma once
#include <GL/glew.h>
#include <glfw/glfw3.h>
#include <vector>
#include <glm/glm.hpp>
class Window
{
public:
Window(int width, int height);
~Window();
void beginFrame();
void update(const std::vector<glm::vec3>& textureData);
private:
int width;
int height;
GLuint vao;
GLuint texture;
GLuint program;
GLuint vertShader;
GLuint fragShader;
GLFWwindow* window;
};
+1 -1
View File
@@ -2,7 +2,7 @@
"dependencies": [ "dependencies": [
{ {
"name": "imgui", "name": "imgui",
"features": [ "glfw-binding", "opengl3-binding" ] "features": [ "glfw-binding", "opengl3-binding", "metal-binding" ]
}, },
"vulkan", "vulkan",
"vulkan-memory-allocator", "vulkan-memory-allocator",