pretty much works now

This commit is contained in:
Dynamitos
2025-02-28 12:46:01 +09:00
parent 4976e3bdcd
commit df3af75801
7 changed files with 192 additions and 145 deletions
+1
View File
@@ -10,5 +10,6 @@ target_sources(RayTracer
if(APPLE) if(APPLE)
add_subdirectory(metal/) add_subdirectory(metal/)
endif() endif()
add_subdirectory(cpu/)
add_subdirectory(scene/) add_subdirectory(scene/)
add_subdirectory(util/) add_subdirectory(util/)
+2 -2
View File
@@ -2,5 +2,5 @@ target_sources(RayTracer
PUBLIC PUBLIC
CPURenderer.h CPURenderer.h
CPURenderer.cpp CPURenderer.cpp
CPURenderer.h CPUScene.h
CPURenderer.cpp) CPUScene.cpp)
+19 -2
View File
@@ -1,21 +1,31 @@
#include "CPURenderer.h" #include "CPURenderer.h"
#include "scene/Renderer.h" #include "scene/Renderer.h"
#include "CPUScene.h"
#include <imgui.h> #include <imgui.h>
#include <imgui_impl_glfw.h> #include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h> #include <imgui_impl_opengl3.h>
#define GLSL(...) "#version 400\n" #__VA_ARGS__ #define GLSL(...) "#version 400\n" #__VA_ARGS__
static void glfw_error_callback(int error, const char* description)
{
fprintf(stderr, "Glfw Error %d: %s\n", error, description);
}
CPURenderer::CPURenderer() CPURenderer::CPURenderer()
{ {
width = 1920;
height = 1080;
glewExperimental = true; glewExperimental = true;
glfwSetErrorCallback(glfw_error_callback);
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We don't want the old OpenGL glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We don't want the old OpenGL
window = glfwCreateWindow(width, height, "RayTracer", nullptr, nullptr); float xscale = 1, yscale = 1;
glfwSwapInterval(1); glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, &yscale);
window = glfwCreateWindow(width / xscale, height / yscale, "RayTracer", nullptr, nullptr);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
glfwSwapInterval(1);
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
@@ -28,6 +38,8 @@ CPURenderer::CPURenderer()
ImGui_ImplOpenGL3_Init(); ImGui_ImplOpenGL3_Init();
glewInit(); glewInit();
scene = new CPUScene();
glGenVertexArrays(1, &vao); glGenVertexArrays(1, &vao);
glBindVertexArray(vao); glBindVertexArray(vao);
@@ -91,6 +103,11 @@ CPURenderer::CPURenderer()
glClearColor(0, 0, 0, 0); glClearColor(0, 0, 0, 0);
} }
CPURenderer::~CPURenderer()
{
}
glm::vec3 rand01(glm::uvec3 x) glm::vec3 rand01(glm::uvec3 x)
{ // pseudo-random number generator { // pseudo-random number generator
for (int i = 3; i-- > 0;) for (int i = 3; i-- > 0;)
+25 -28
View File
@@ -1,12 +1,11 @@
#include "scene/Renderer.h" #include "scene/Renderer.h"
#include "cpu/CPURenderer.h"
#include "util/ModelLoader.h" #include "util/ModelLoader.h"
#include "metal/MetalRenderer.h"
#include <imgui.h> #include <imgui.h>
int main() int main()
{ {
std::unique_ptr<Renderer> renderer = std::make_unique<MetalRenderer>(); std::unique_ptr<Renderer> renderer = std::make_unique<CPURenderer>();
renderer->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),
@@ -15,13 +14,12 @@ int main()
renderer->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)));
renderer->addModels(ModelLoader::loadModel("../../res/models/cube.fbx"), renderer->generate();
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{ 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),
.f = 0,
.A = 0,
.S_O = 6, .S_O = 6,
}; };
RenderParameter render = RenderParameter{ RenderParameter render = RenderParameter{
@@ -33,27 +31,26 @@ int main()
while (true) while (true)
{ {
renderer->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);
ImGui::InputFloat("Focal Length", &camera.f); ImGui::InputFloat("Focal Length", &camera.f);
ImGui::InputFloat("Aperture", &camera.A); ImGui::InputFloat("Aperture", &camera.A);
ImGui::InputFloat("S_O", &camera.S_O); ImGui::InputFloat("S_O", &camera.S_O);
ImGui::Text("Render Parameters"); ImGui::Text("Render Parameters");
ImGui::InputInt2("Dimensions", (int*)&render.width); ImGui::InputInt2("Dimensions", (int*)&render.width);
ImGui::InputInt("Samples", (int*)&render.numSamples); ImGui::InputInt("Samples", (int*)&render.numSamples);
if (ImGui::Button("Render")) if (ImGui::Button("Render"))
{ {
std::cout << "Test" << std::endl; renderer->startRender(camera, render);
renderer->startRender(camera, render); }
ImGui::Text("Render Stats");
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();
} }
ImGui::Text("Render Stats");
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; return 0;
} }
+18 -13
View File
@@ -68,7 +68,7 @@ struct BRDF
float3 albedo = float3(1, 1, 1); float3 albedo = float3(1, 1, 1);
float alpha = 1; float alpha = 1;
float3 specularColor = float3(1, 1, 1); float3 specularColor = float3(1, 1, 1);
float shininess = 0.04; float shininess = 0.004;
float3 emissive = float3(0, 0, 0); float3 emissive = float3(0, 0, 0);
MaterialType materialType; MaterialType materialType;
float3 evaluate(HitInfo hit, float3 viewDir, float3 lightDir, float3 lightColor) float3 evaluate(HitInfo hit, float3 viewDir, float3 lightDir, float3 lightColor)
@@ -76,7 +76,7 @@ struct BRDF
float3 normal = hit.normal; float3 normal = hit.normal;
float diffuse = max(dot(normal, lightDir), 0.0f); float diffuse = max(dot(normal, lightDir), 0.0f);
float3 h = normalize(lightDir + viewDir); float3 h = normalize(lightDir + viewDir);
float specular = pow(min(max(dot(normal, h), 0.0f), 1.0f), shininess); float specular = pow(clamp(dot(normal, h), 0.0f, 1.0f), shininess);
return (albedo * diffuse * lightColor) + float3(0.03, 0.03, 0.03); return (albedo * diffuse * lightColor) + float3(0.03, 0.03, 0.03);
} }
@@ -117,7 +117,7 @@ inline T interpolateVertexAttribute(constant T *attributes,
// Compute the sum of the vertex attributes weighted by the barycentric coordinates. // Compute the sum of the vertex attributes weighted by the barycentric coordinates.
// The barycentric coordinates sum to one. // The barycentric coordinates sum to one.
return (1.0f - uv.x - uv.y) * T0 + uv.x * T1 + uv.y * T2; return (1.0f - uv.x - uv.y) * T2 + uv.x * T0 + uv.y * T1;
} }
kernel void computeKernel( kernel void computeKernel(
@@ -129,10 +129,11 @@ kernel void computeKernel(
constant packed_float2* texCoords [[buffer(2)]], constant packed_float2* texCoords [[buffer(2)]],
constant packed_float3* normals [[buffer(3)]], constant packed_float3* normals [[buffer(3)]],
constant ModelReference* modelRefs [[buffer(4)]], constant ModelReference* modelRefs [[buffer(4)]],
constant DirectionalLight* directionalLights [[buffer(5)]], constant BRDF* materials [[buffer(5)]],
constant PointLight* pointLights [[buffer(6)]], constant DirectionalLight* directionalLights [[buffer(6)]],
constant MTLAccelerationStructureInstanceDescriptor* instances [[buffer(7)]], constant PointLight* pointLights [[buffer(7)]],
instance_acceleration_structure accelerationStructure [[buffer(8)]], constant MTLAccelerationStructureInstanceDescriptor* instances [[buffer(8)]],
instance_acceleration_structure accelerationStructure [[buffer(9)]],
texture2d<float, access::read_write> accumulator [[texture(0)]], texture2d<float, access::read_write> accumulator [[texture(0)]],
texture2d<float, access::read_write> image [[texture(1)]] texture2d<float, access::read_write> image [[texture(1)]]
) )
@@ -201,11 +202,11 @@ kernel void computeKernel(
const auto indices = indexBuffer[ref.indicesOffset + intersection.primitive_id]; const auto indices = indexBuffer[ref.indicesOffset + intersection.primitive_id];
info.position = interpolateVertexAttribute(positions, ref.positionOffset, indices.x, indices.y, indices.z, intersection.triangle_barycentric_coord); info.position = interpolateVertexAttribute(positions, ref.positionOffset, indices.x, indices.y, indices.z, intersection.triangle_barycentric_coord);
info.texCoords = interpolateVertexAttribute(texCoords, ref.positionOffset, indices.x, indices.y, indices.z, intersection.triangle_barycentric_coord); info.texCoords = interpolateVertexAttribute(texCoords, ref.positionOffset, indices.x, indices.y, indices.z, intersection.triangle_barycentric_coord);
info.normal = interpolateVertexAttribute(normals, ref.positionOffset, indices.x, indices.y, indices.z, intersection.triangle_barycentric_coord); info.normal = normalize(interpolateVertexAttribute(normals, ref.positionOffset, indices.x, indices.y, indices.z, intersection.triangle_barycentric_coord));
info.normalLight = dot(info.normal, cam.direction) < 0 ? info.normal : -info.normal; info.normalLight = dot(info.normal, cam.direction) < 0 ? info.normal : -info.normal;
BRDF brdf; BRDF brdf;
brdf.albedo = float3(0, 1, 0); brdf.albedo = float3(0, 1, 0);
float p = max(max(brdf.albedo.x, brdf.albedo.y), brdf.albedo.z); float p = max(max(brdf.albedo.x, brdf.albedo.y), brdf.albedo.z);
if (payload.depth > 5) if (payload.depth > 5)
@@ -229,9 +230,9 @@ kernel void computeKernel(
shadowRay.max_distance = INFINITY; shadowRay.max_distance = INFINITY;
i.accept_any_intersection(true); i.accept_any_intersection(true);
intersection = i.intersect(shadowRay, accelerationStructure, 0xff); intersection = i.intersect(shadowRay, accelerationStructure, 0xff);
if(intersection.type != intersection_type::none) if(intersection.type == intersection_type::none)
{ {
payload.accumulatedRadiance += brdf.evaluate(info, -cam.direction, shadowRay.direction, directionalLights[l].color); payload.accumulatedRadiance += brdf.evaluate(info, -cam.direction, normalize(shadowRay.direction), directionalLights[l].color);
} }
} }
for (uint l = 0; l < sample.numPointLights; ++l) for (uint l = 0; l < sample.numPointLights; ++l)
@@ -243,7 +244,7 @@ kernel void computeKernel(
shadowRay.max_distance = 1; shadowRay.max_distance = 1;
i.accept_any_intersection(true); i.accept_any_intersection(true);
intersection = i.intersect(shadowRay, accelerationStructure, 0xff); intersection = i.intersect(shadowRay, accelerationStructure, 0xff);
if (intersection.type != intersection_type::none) if (intersection.type == intersection_type::none)
{ {
float d = length(lightDir); float d = length(lightDir);
float illuminance = max(1 - d / pointLights[l].attenuation, 0.0f); float illuminance = max(1 - d / pointLights[l].attenuation, 0.0f);
@@ -267,7 +268,11 @@ 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);
float4 previous = accumulator.read(threadId); float4 previous = float4(0);
if(sample.pass != 0)
{
previous = accumulator.read(threadId);
}
float4 result = previous + float4(payload.accumulatedRadiance / float(sample.samplesPerPixel), 0); float4 result = previous + float4(payload.accumulatedRadiance / float(sample.samplesPerPixel), 0);
accumulator.write(result, threadId); accumulator.write(result, threadId);
image.write(pow(max(result * resolver, 0), float4(0.45f)), threadId); image.write(pow(max(result * resolver, 0), float4(0.45f)), threadId);
+110 -84
View File
@@ -14,11 +14,10 @@ id<CAMetalDrawable> drawable;
id<MTLDevice> device; id<MTLDevice> device;
id<MTLLibrary> library; id<MTLLibrary> library;
id<MTLCommandQueue> queue; id<MTLCommandQueue> queue;
id<MTLCommandQueue> renderQueue;
id<MTLFunction> function; id<MTLFunction> function;
id<MTLComputePipelineState> computePipeline; id<MTLComputePipelineState> computePipeline;
id<MTLTexture> accumulator; id<MTLTexture> accumulator = nullptr;
id<MTLTexture> resultTexture; id<MTLTexture> resultTexture = nullptr;
MTLRenderPassDescriptor* renderPass; MTLRenderPassDescriptor* renderPass;
id<MTLRenderCommandEncoder> renderEncoder; id<MTLRenderCommandEncoder> renderEncoder;
@@ -34,54 +33,56 @@ MetalRenderer::MetalRenderer()
width = 1920; width = 1920;
height = 1080; height = 1080;
device = MTLCreateSystemDefaultDevice(); device = MTLCreateSystemDefaultDevice();
library = [device newDefaultLibrary]; library = [device newDefaultLibrary];
queue = [device newCommandQueue]; queue = [device newCommandQueue];
renderQueue = [device newCommandQueue];
scene = new MetalScene(device, queue); scene = new MetalScene(device, queue);
function = [library newFunctionWithName:@"computeKernel"]; function = [library newFunctionWithName:@"computeKernel"];
NSError* error; NSError* error;
computePipeline = [device newComputePipelineStateWithFunction:function error:&error]; computePipeline = [device newComputePipelineStateWithFunction:function error:&error];
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
glfwSetErrorCallback(glfw_error_callback); glfwSetErrorCallback(glfw_error_callback);
glfwInit(); glfwInit();
float xscale = 1, yscale = 1; float xscale = 1, yscale = 1;
glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, &yscale); glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, &yscale);
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
handle = glfwCreateWindow(width / xscale, height / yscale, "RayTracer", nullptr, nullptr); handle = glfwCreateWindow(width / xscale, height / yscale, "RayTracer", nullptr, nullptr);
ImGui_ImplGlfw_InitForOpenGL(handle, true);
ImGui_ImplGlfw_InitForOpenGL(handle, false);
ImGui_ImplMetal_Init(device); ImGui_ImplMetal_Init(device);
NSWindow* cocoaWindow = glfwGetCocoaWindow(handle); NSWindow* cocoaWindow = glfwGetCocoaWindow(handle);
metalLayer = [CAMetalLayer layer]; metalLayer = [CAMetalLayer layer];
metalLayer.device = device; metalLayer.device = device;
metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm; metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
[[cocoaWindow contentView] setLayer:metalLayer]; [[cocoaWindow contentView] setLayer:metalLayer];
[[cocoaWindow contentView] setWantsLayer:true]; [[cocoaWindow contentView] setWantsLayer:true];
renderPass = [[MTLRenderPassDescriptor alloc] init]; renderPass = [[MTLRenderPassDescriptor alloc] init];
MTLRenderPipelineDescriptor *renderDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; MTLRenderPipelineDescriptor *renderDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
renderDescriptor.vertexFunction = [library newFunctionWithName:@"copyVertex"]; renderDescriptor.vertexFunction = [library newFunctionWithName:@"copyVertex"];
renderDescriptor.fragmentFunction = [library newFunctionWithName:@"copyFragment"]; renderDescriptor.fragmentFunction = [library newFunctionWithName:@"copyFragment"];
renderDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm; renderDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
pipelineState = [device newRenderPipelineStateWithDescriptor:renderDescriptor error:&error]; pipelineState = [device newRenderPipelineStateWithDescriptor:renderDescriptor error:&error];
[renderDescriptor release];
} }
MetalRenderer::~MetalRenderer() {} MetalRenderer::~MetalRenderer() {
[renderPass release];
}
void MetalRenderer::addPointLight(PointLight point) { scene->addPointLight(point); } void MetalRenderer::addPointLight(PointLight point) { scene->addPointLight(point); }
void MetalRenderer::addDirectionalLight(DirectionalLight dir) { scene->addDirectionalLight(dir); } void MetalRenderer::addDirectionalLight(DirectionalLight dir) { scene->addDirectionalLight(dir); }
@@ -91,14 +92,16 @@ void MetalRenderer::generate() { scene->generate(); }
void MetalRenderer::beginFrame() void MetalRenderer::beginFrame()
{ {
glfwPollEvents(); @autoreleasepool {
glfwPollEvents();
int w, h; int w, h;
glfwGetFramebufferSize(handle, &w, &h); glfwGetFramebufferSize(handle, &w, &h);
framebufferWidth = width; framebufferWidth = width;
framebufferHeight = height; framebufferHeight = height;
metalLayer.drawableSize = CGSizeMake(framebufferWidth, framebufferHeight); metalLayer.drawableSize = CGSizeMake(framebufferWidth, framebufferHeight);
drawable = [metalLayer nextDrawable]; drawable = [metalLayer nextDrawable];
renderCmd = [renderQueue commandBuffer]; renderCmd = [queue commandBuffer];
renderPass.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 0); renderPass.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 0);
renderPass.colorAttachments[0].texture = drawable.texture; renderPass.colorAttachments[0].texture = drawable.texture;
renderPass.colorAttachments[0].loadAction = MTLLoadActionClear; renderPass.colorAttachments[0].loadAction = MTLLoadActionClear;
@@ -113,18 +116,25 @@ drawable = [metalLayer nextDrawable];
// Draw a quad which fills the screen. // Draw a quad which fills the screen.
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6]; [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:6];
[renderEncoder retain];
[renderCmd retain];
[drawable retain];
}
} }
void MetalRenderer::update() void MetalRenderer::update()
{ {
@autoreleasepool {
ImGui::Render(); ImGui::Render();
ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), renderCmd, renderEncoder); ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), renderCmd, renderEncoder);
[renderEncoder endEncoding]; [renderEncoder endEncoding];
[renderEncoder release];
[renderCmd presentDrawable:drawable]; [renderCmd presentDrawable:drawable];
[renderCmd commit]; [renderCmd commit];
[renderCmd release]; [renderCmd release];
[renderEncoder release]; [drawable release];
[drawable release]; }
} }
void MetalRenderer::render(Camera camera, RenderParameter parameter) void MetalRenderer::render(Camera camera, RenderParameter parameter)
@@ -140,6 +150,11 @@ void MetalRenderer::render(Camera camera, RenderParameter parameter)
.height = parameter.height, .height = parameter.height,
}; };
if(accumulator != nullptr)
{
[accumulator release];
[resultTexture release];
}
MTLTextureDescriptor* texDescriptor = [[MTLTextureDescriptor alloc] init]; MTLTextureDescriptor* texDescriptor = [[MTLTextureDescriptor alloc] init];
[texDescriptor setWidth:parameter.width]; [texDescriptor setWidth:parameter.width];
[texDescriptor setHeight:parameter.height]; [texDescriptor setHeight:parameter.height];
@@ -147,58 +162,69 @@ void MetalRenderer::render(Camera camera, RenderParameter parameter)
[texDescriptor setUsage:MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead]; [texDescriptor setUsage:MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead];
accumulator = [device newTextureWithDescriptor:texDescriptor]; accumulator = [device newTextureWithDescriptor:texDescriptor];
resultTexture = [device newTextureWithDescriptor:texDescriptor]; resultTexture = [device newTextureWithDescriptor:texDescriptor];
[texDescriptor release];
for (uint i = 0; i < parameter.numSamples; ++i) for (uint i = 0; i < parameter.numSamples; ++i)
{ {
id<MTLCommandBuffer> cmdBuffer = [queue commandBuffer]; if(!running)
id<MTLComputeCommandEncoder> encoder = [cmdBuffer computeCommandEncoder]; return;
// cmdBuffer->addCompletedHandler([this](MTL::CommandBuffer* cmdBuffer) @autoreleasepool{
// { std::memcpy(image.data(), resultTexture->buffer(), image.size() * sizeof(glm::vec3)); }); id<MTLCommandBuffer> cmdBuffer = [queue commandBuffer];
id<MTLComputeCommandEncoder> encoder = [cmdBuffer computeCommandEncoder];
// cmdBuffer->addCompletedHandler([this](MTL::CommandBuffer* cmdBuffer)
// { std::memcpy(image.data(), resultTexture->buffer(), image.size() * sizeof(glm::vec3)); });
SampleParams sample = { SampleParams sample = {
.pass = i, .pass = i,
.samplesPerPixel = parameter.numSamples, .samplesPerPixel = parameter.numSamples,
.numDirectionalLights = scene->getNumDirLights(), .numDirectionalLights = scene->getNumDirLights(),
.numPointLights = scene->getNumPointLights(), .numPointLights = scene->getNumPointLights(),
}; };
[encoder setComputePipelineState:computePipeline]; [encoder setComputePipelineState:computePipeline];
[encoder setBuffer:scene->indicesBuffer offset:0 atIndex:0]; [encoder setBuffer:scene->indicesBuffer offset:0 atIndex:0];
[encoder setBuffer:scene->positionBuffer offset:0 atIndex:1]; [encoder setBuffer:scene->positionBuffer offset:0 atIndex:1];
[encoder setBuffer:scene->texCoordsBuffer offset:0 atIndex:2]; [encoder setBuffer:scene->texCoordsBuffer offset:0 atIndex:2];
[encoder setBuffer:scene->normalBuffer offset:0 atIndex:3]; [encoder setBuffer:scene->normalBuffer offset:0 atIndex:3];
[encoder setBuffer:scene->modelRefsBuffer offset:0 atIndex:4]; [encoder setBuffer:scene->modelRefsBuffer offset:0 atIndex:4];
[encoder setBuffer:scene->directionalLightBuffer offset:0 atIndex:5]; [encoder setBuffer:scene->directionalLightBuffer offset:0 atIndex:6];
[encoder setBuffer:scene->pointLightBuffer offset:0 atIndex:6]; [encoder setBuffer:scene->pointLightBuffer offset:0 atIndex:7];
[encoder setBuffer:scene->instanceBuffer offset:0 atIndex:7]; [encoder setBuffer:scene->instanceBuffer offset:0 atIndex:8];
[encoder setAccelerationStructure:scene->accelerationStructure atBufferIndex:8]; [encoder setAccelerationStructure:scene->accelerationStructure atBufferIndex:9];
[encoder setTexture:accumulator atIndex:0]; [encoder setTexture:accumulator atIndex:0];
[encoder setTexture:resultTexture atIndex:1]; [encoder setTexture:resultTexture atIndex:1];
[encoder setBytes:&gpuCam length:sizeof(GPUCamera) atIndex:9]; [encoder setBytes:&gpuCam length:sizeof(GPUCamera) atIndex:10];
[encoder setBytes:&sample length:sizeof(SampleParams) atIndex:10]; [encoder setBytes:&sample length:sizeof(SampleParams) atIndex:11];
[encoder useResource:scene->instanceBuffer usage:MTLResourceUsageRead]; [encoder useResource:scene->instanceBuffer usage:MTLResourceUsageRead];
[encoder useResource:scene->positionBuffer usage:MTLResourceUsageRead]; [encoder useResource:scene->positionBuffer usage:MTLResourceUsageRead];
[encoder useResource:scene->texCoordsBuffer usage:MTLResourceUsageRead]; [encoder useResource:scene->texCoordsBuffer usage:MTLResourceUsageRead];
[encoder useResource:scene->normalBuffer usage:MTLResourceUsageRead]; [encoder useResource:scene->normalBuffer usage:MTLResourceUsageRead];
[encoder useResource:scene->modelRefsBuffer usage:MTLResourceUsageRead]; [encoder useResource:scene->modelRefsBuffer usage:MTLResourceUsageRead];
if (scene->getNumDirLights() > 0) if (scene->getNumDirLights() > 0)
{ {
[encoder useResource:scene->directionalLightBuffer usage:MTLResourceUsageRead]; [encoder useResource:scene->directionalLightBuffer usage:MTLResourceUsageRead];
} }
if (scene->getNumPointLights() > 0) if (scene->getNumPointLights() > 0)
{ {
[encoder useResource:scene->pointLightBuffer usage:MTLResourceUsageRead]; [encoder useResource:scene->pointLightBuffer usage:MTLResourceUsageRead];
}
[encoder useResource:scene->instanceBuffer usage:MTLResourceUsageRead];
[encoder useResource:scene->accelerationStructure usage:MTLResourceUsageRead];
[encoder useResource:accumulator usage:MTLResourceUsageWrite];
[encoder useResource:resultTexture usage:MTLResourceUsageWrite];
NSUInteger width = (NSUInteger)parameter.width;
NSUInteger height = (NSUInteger)parameter.height;
MTLSize threadsPerThreadgroup = MTLSizeMake(8, 8, 1);
MTLSize threadgroups = MTLSizeMake((width + threadsPerThreadgroup.width - 1) / threadsPerThreadgroup.width,
(height + threadsPerThreadgroup.height - 1) / threadsPerThreadgroup.height, 1);
[encoder dispatchThreadgroups:threadgroups threadsPerThreadgroup:threadsPerThreadgroup];
[encoder endEncoding];
[cmdBuffer commit];
[cmdBuffer addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull cmd) {
sampleTimes.push_back((cmd.GPUEndTime - cmd.GPUStartTime) * 1000.f);
if(sampleTimes.size() > 200)
{
sampleTimes.erase(sampleTimes.begin());
}
}];
} }
[encoder useResource:scene->instanceBuffer usage:MTLResourceUsageRead];
[encoder useResource:scene->accelerationStructure usage:MTLResourceUsageRead];
[encoder useResource:accumulator usage:MTLResourceUsageWrite];
[encoder useResource:resultTexture usage:MTLResourceUsageWrite];
NSUInteger width = (NSUInteger)parameter.width;
NSUInteger height = (NSUInteger)parameter.height;
MTLSize threadsPerThreadgroup = MTLSizeMake(8, 8, 1);
MTLSize threadgroups = MTLSizeMake((width + threadsPerThreadgroup.width - 1) / threadsPerThreadgroup.width,
(height + threadsPerThreadgroup.height - 1) / threadsPerThreadgroup.height, 1);
[encoder dispatchThreadgroups:threadgroups threadsPerThreadgroup:threadsPerThreadgroup];
[encoder endEncoding];
[cmdBuffer commit];
sampleTimes.push_back(0);
} }
} }
+17 -16
View File
@@ -6,24 +6,25 @@
class MetalScene : public Scene class MetalScene : public Scene
{ {
public: public:
MetalScene(id<MTLDevice> device, id<MTLCommandQueue> queue); MetalScene(id<MTLDevice> device, id<MTLCommandQueue> queue);
virtual ~MetalScene(); virtual ~MetalScene();
virtual void createRayTracingHierarchy() override; virtual void createRayTracingHierarchy() override;
id<MTLAccelerationStructure> newAccelerationStructureWithDescriptor(MTLAccelerationStructureDescriptor* descriptor); id<MTLAccelerationStructure> newAccelerationStructureWithDescriptor(MTLAccelerationStructureDescriptor* descriptor);
id<MTLDevice> device; id<MTLDevice> device;
id<MTLCommandQueue> queue; id<MTLCommandQueue> queue;
id<MTLBuffer> indicesBuffer; id<MTLBuffer> indicesBuffer;
id<MTLBuffer> positionBuffer; id<MTLBuffer> positionBuffer;
id<MTLBuffer> texCoordsBuffer; id<MTLBuffer> texCoordsBuffer;
id<MTLBuffer> normalBuffer; id<MTLBuffer> normalBuffer;
id<MTLBuffer> modelRefsBuffer; id<MTLBuffer> modelRefsBuffer;
id<MTLBuffer> directionalLightBuffer; id<MTLBuffer> materialsBuffer;
id<MTLBuffer> pointLightBuffer; id<MTLBuffer> directionalLightBuffer;
id<MTLBuffer> instanceBuffer; id<MTLBuffer> pointLightBuffer;
id<MTLBuffer> instanceBuffer;
id<MTLAccelerationStructure> accelerationStructure; id<MTLAccelerationStructure> accelerationStructure;
}; };