Create the output framebuffer

This commit is contained in:
Magnus Norddahl 2022-07-02 01:36:28 +02:00
parent 582cd7f7c0
commit 1bb8408b75
2 changed files with 162 additions and 124 deletions

View file

@ -42,8 +42,7 @@ void GPURaytracer2::Raytrace(LevelMesh* level)
printf("Ray tracing in progress...\n");
RunAsync([&]() {
});
if (device->renderdoc)
device->renderdoc->EndFrameCapture(0, 0);
@ -53,25 +52,35 @@ void GPURaytracer2::Raytrace(LevelMesh* level)
void GPURaytracer2::CreateVulkanObjects()
{
submitFence = std::make_unique<VulkanFence>(device.get());
cmdpool = std::make_unique<VulkanCommandPool>(device.get(), device->graphicsFamily);
cmdbuffer = cmdpool->createBuffer();
cmdbuffer->begin();
BeginCommands();
CreateVertexAndIndexBuffers();
CreateBottomLevelAccelerationStructure();
CreateTopLevelAccelerationStructure();
CreateShaders();
CreatePipeline();
CreateFrameBuffer();
CreateDescriptorSet();
PipelineBarrier()
.AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR)
.Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
FinishCommands();
}
void GPURaytracer2::SubmitCommands()
void GPURaytracer2::BeginCommands()
{
auto submitFence = std::make_unique<VulkanFence>(device.get());
cmdbuffer = cmdpool->createBuffer();
cmdbuffer->begin();
}
void GPURaytracer2::FinishCommands()
{
cmdbuffer->end();
QueueSubmit()
.AddCommandBuffer(cmdbuffer.get())
@ -88,73 +97,13 @@ void GPURaytracer2::SubmitCommands()
void GPURaytracer2::CreateVertexAndIndexBuffers()
{
std::vector<SurfaceInfo2> surfaces;
surfaces.reserve(mesh->surfaces.size());
for (const auto& surface : mesh->surfaces)
{
SurfaceLightDef* def = nullptr;
if (surface->type >= ST_MIDDLESIDE && surface->type <= ST_LOWERSIDE)
{
int lightdefidx = mesh->map->Sides[surface->typeIndex].lightdef;
if (lightdefidx != -1)
{
def = &mesh->map->SurfaceLights[lightdefidx];
}
}
else if (surface->type == ST_FLOOR || surface->type == ST_CEILING)
{
MapSubsectorEx* sub = &mesh->map->GLSubsectors[surface->typeIndex];
IntSector* sector = mesh->map->GetSectorFromSubSector(sub);
if (sector && surface->numVerts > 0)
{
if (sector->floorlightdef != -1 && surface->type == ST_FLOOR)
{
def = &mesh->map->SurfaceLights[sector->floorlightdef];
}
else if (sector->ceilinglightdef != -1 && surface->type == ST_CEILING)
{
def = &mesh->map->SurfaceLights[sector->ceilinglightdef];
}
}
}
SurfaceInfo2 info;
info.Sky = surface->bSky ? 1.0f : 0.0f;
info.Normal = surface->plane.Normal();
if (def)
{
info.EmissiveDistance = def->distance + def->distance;
info.EmissiveIntensity = def->intensity;
info.EmissiveColor = def->rgb;
}
else
{
info.EmissiveDistance = 0.0f;
info.EmissiveIntensity = 0.0f;
info.EmissiveColor = vec3(0.0f, 0.0f, 0.0f);
}
info.SamplingDistance = float(surface->sampleDimension);
surfaces.push_back(info);
}
std::vector<LightInfo2> lights;
for (ThingLight& light : mesh->map->ThingLights)
{
LightInfo2 info;
info.Origin = light.LightOrigin();
info.Radius = light.LightRadius();
info.Intensity = light.intensity;
info.InnerAngleCos = light.innerAngleCos;
info.OuterAngleCos = light.outerAngleCos;
info.SpotDir = light.SpotDir();
info.Color = light.rgb;
lights.push_back(info);
}
std::vector<SurfaceInfo2> surfaces = CreateSurfaceInfo();
std::vector<LightInfo2> lights = CreateLightInfo();
if (lights.empty()) // vulkan doesn't support zero byte buffers
lights.push_back(LightInfo2());
if (surfaces.empty())
surfaces.push_back(SurfaceInfo2());
size_t vertexbuffersize = (size_t)mesh->MeshVertices.Size() * sizeof(vec3);
size_t indexbuffersize = (size_t)mesh->MeshElements.Size() * sizeof(uint32_t);
@ -169,13 +118,23 @@ void GPURaytracer2::CreateVertexAndIndexBuffers()
size_t lightoffset = surfaceoffset + surfacebuffersize;
vertexBuffer = BufferBuilder()
.Usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
.Usage(
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
.Size(vertexbuffersize)
.DebugName("vertexBuffer")
.Create(device.get());
indexBuffer = BufferBuilder()
.Usage(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
.Usage(
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
.Size(indexbuffersize)
.DebugName("indexBuffer")
.Create(device.get());
@ -218,10 +177,9 @@ void GPURaytracer2::CreateVertexAndIndexBuffers()
cmdbuffer->copyBuffer(transferBuffer.get(), surfaceBuffer.get(), surfaceoffset);
cmdbuffer->copyBuffer(transferBuffer.get(), lightBuffer.get(), lightoffset);
VkMemoryBarrier barrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER };
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
cmdbuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, 0, 1, &barrier, 0, nullptr, 0, nullptr);
PipelineBarrier()
.AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR)
.Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
}
void GPURaytracer2::CreateBottomLevelAccelerationStructure()
@ -328,10 +286,9 @@ void GPURaytracer2::CreateTopLevelAccelerationStructure()
cmdbuffer->copyBuffer(tlTransferBuffer.get(), tlInstanceBuffer.get());
VkMemoryBarrier barrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER };
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
cmdbuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, 0, 1, &barrier, 0, nullptr, 0, nullptr);
PipelineBarrier()
.AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR)
.Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
VkBufferDeviceAddressInfo info = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO };
info.buffer = tlInstanceBuffer->buffer;
@ -423,6 +380,20 @@ void GPURaytracer2::CreatePipeline()
.Create(device.get());
renderPass = RenderPassBuilder()
.AddAttachment(
VK_FORMAT_R8G8B8A8_UNORM,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_STORE_OP_STORE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
.AddSubpass()
.AddSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
.AddExternalSubpassDependency(
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT)
.DebugName("renderpass")
.Create(device.get());
@ -431,10 +402,38 @@ void GPURaytracer2::CreatePipeline()
.RenderPass(renderPass.get())
.AddVertexShader(vertShader.get())
.AddFragmentShader(fragShader.get())
.Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
.Viewport(0.0f, 0.0f, 320.0f, 200.0f)
.Scissor(0, 0, 320, 200)
.DebugName("pipeline")
.Create(device.get());
}
void GPURaytracer2::CreateFrameBuffer()
{
framebufferImage = ImageBuilder()
.Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
.Format(VK_FORMAT_R8G8B8A8_UNORM)
.Size(320, 200)
.Create(device.get());
framebufferImageView = ImageViewBuilder()
.Image(framebufferImage.get(), VK_FORMAT_R8G8B8A8_UNORM)
.DebugName("framebufferImageView")
.Create(device.get());
framebuffer = FramebufferBuilder()
.RenderPass(renderPass.get())
.Size(320, 200)
.AddAttachment(framebufferImageView.get())
.DebugName("framebuffer")
.Create(device.get());
PipelineBarrier()
.AddImage(framebufferImage.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 0, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)
.Execute(cmdbuffer.get(), 0, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
}
void GPURaytracer2::CreateDescriptorSet()
{
VkDeviceSize align = device->physicalDevice.properties.limits.minUniformBufferOffsetAlignment;
@ -472,6 +471,79 @@ void GPURaytracer2::CreateDescriptorSet()
.Execute(device.get());
}
std::vector<SurfaceInfo2> GPURaytracer2::CreateSurfaceInfo()
{
std::vector<SurfaceInfo2> surfaces;
surfaces.reserve(mesh->surfaces.size());
for (const auto& surface : mesh->surfaces)
{
SurfaceLightDef* def = nullptr;
if (surface->type >= ST_MIDDLESIDE && surface->type <= ST_LOWERSIDE)
{
int lightdefidx = mesh->map->Sides[surface->typeIndex].lightdef;
if (lightdefidx != -1)
{
def = &mesh->map->SurfaceLights[lightdefidx];
}
}
else if (surface->type == ST_FLOOR || surface->type == ST_CEILING)
{
MapSubsectorEx* sub = &mesh->map->GLSubsectors[surface->typeIndex];
IntSector* sector = mesh->map->GetSectorFromSubSector(sub);
if (sector && surface->numVerts > 0)
{
if (sector->floorlightdef != -1 && surface->type == ST_FLOOR)
{
def = &mesh->map->SurfaceLights[sector->floorlightdef];
}
else if (sector->ceilinglightdef != -1 && surface->type == ST_CEILING)
{
def = &mesh->map->SurfaceLights[sector->ceilinglightdef];
}
}
}
SurfaceInfo2 info;
info.Sky = surface->bSky ? 1.0f : 0.0f;
info.Normal = surface->plane.Normal();
if (def)
{
info.EmissiveDistance = def->distance + def->distance;
info.EmissiveIntensity = def->intensity;
info.EmissiveColor = def->rgb;
}
else
{
info.EmissiveDistance = 0.0f;
info.EmissiveIntensity = 0.0f;
info.EmissiveColor = vec3(0.0f, 0.0f, 0.0f);
}
info.SamplingDistance = float(surface->sampleDimension);
surfaces.push_back(info);
}
return surfaces;
}
std::vector<LightInfo2> GPURaytracer2::CreateLightInfo()
{
std::vector<LightInfo2> lights;
for (ThingLight& light : mesh->map->ThingLights)
{
LightInfo2 info;
info.Origin = light.LightOrigin();
info.Radius = light.LightRadius();
info.Intensity = light.intensity;
info.InnerAngleCos = light.innerAngleCos;
info.OuterAngleCos = light.outerAngleCos;
info.SpotDir = light.SpotDir();
info.Color = light.rgb;
lights.push_back(info);
}
return lights;
}
void GPURaytracer2::PrintVulkanInfo()
{
const auto& props = device->physicalDevice.properties;
@ -494,44 +566,3 @@ void GPURaytracer2::PrintVulkanInfo()
printf("Vulkan device type: %s\n", deviceType.c_str());
printf("Vulkan version: %s (api) %s (driver)\n", apiVersion.c_str(), driverVersion.c_str());
}
void GPURaytracer2::RunAsync(std::function<void()> callback)
{
std::exception_ptr e;
std::condition_variable condvar;
std::mutex m;
bool stop;
{
std::unique_lock<std::mutex> lock(m);
stop = false;
}
std::thread t([&]() {
try
{
callback();
}
catch (...)
{
e = std::current_exception();
}
std::unique_lock<std::mutex> lock(m);
stop = true;
lock.unlock();
condvar.notify_all();
});
{
std::unique_lock<std::mutex> lock(m);
while (!stop)
{
condvar.wait_for(lock, std::chrono::milliseconds(500), [&]() { return stop; });
}
}
t.join();
if (e)
std::rethrow_exception(e);
}

View file

@ -62,13 +62,16 @@ private:
void CreateTopLevelAccelerationStructure();
void CreateShaders();
void CreatePipeline();
void CreateFrameBuffer();
void CreateDescriptorSet();
void SubmitCommands();
void BeginCommands();
void FinishCommands();
void PrintVulkanInfo();
static void RunAsync(std::function<void()> callback);
std::vector<SurfaceInfo2> CreateSurfaceInfo();
std::vector<LightInfo2> CreateLightInfo();
LevelMesh* mesh = nullptr;
@ -103,15 +106,19 @@ private:
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
std::unique_ptr<VulkanPipeline> pipeline;
std::unique_ptr<VulkanRenderPass> renderPass;
std::unique_ptr<VulkanImage> framebufferImage;
std::unique_ptr<VulkanImageView> framebufferImageView;
std::unique_ptr<VulkanFramebuffer> framebuffer;
std::unique_ptr<VulkanBuffer> uniformBuffer;
std::unique_ptr<VulkanBuffer> uniformTransferBuffer;
std::unique_ptr<VulkanDescriptorPool> descriptorPool;
std::unique_ptr<VulkanDescriptorSet> descriptorSet;
std::unique_ptr<VulkanFence> submitFence;
std::unique_ptr<VulkanCommandPool> cmdpool;
std::unique_ptr<VulkanCommandBuffer> cmdbuffer;
};