Added class to handle allocation and creation of Buffers and Image, as well as Timers.
No memory leaks detected yet. (Fingers crossed).
This commit is contained in:
parent
952176f4c9
commit
e077eeaf5d
30
Memory/Buffer.cpp
Normal file
30
Memory/Buffer.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include <Memory/Buffer.hpp>
|
||||
#include <Memory/Memory.hpp>
|
||||
|
||||
Buffer::Buffer(vk::PhysicalDevice phys_dev, vk::Device dev, vk::DeviceSize sz, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags mem_flags, vk::SharingMode sharing) : dev(dev), size(sz) {
|
||||
auto info = vk::BufferCreateInfo {
|
||||
.size = sz,
|
||||
.usage = usage,
|
||||
.sharingMode = sharing,
|
||||
};
|
||||
buffer = dev.createBuffer(info);
|
||||
|
||||
auto reqs = dev.getBufferMemoryRequirements(buffer);
|
||||
auto alloc_info = vk::MemoryAllocateInfo{
|
||||
.allocationSize = reqs.size,
|
||||
.memoryTypeIndex = mem::choose_heap(phys_dev, reqs, mem_flags),
|
||||
};
|
||||
memory = dev.allocateMemory(alloc_info);
|
||||
}
|
||||
|
||||
void Buffer::map(const uint8_t* data, vk::DeviceSize size) {
|
||||
auto p = dev.mapMemory(memory, 0, size);
|
||||
std::memcpy(p, data, size);
|
||||
dev.unmapMemory(memory);
|
||||
}
|
||||
|
||||
Buffer::~Buffer() {
|
||||
dev.freeMemory(memory);
|
||||
dev.destroyBuffer(buffer);
|
||||
}
|
||||
|
||||
27
Memory/Buffer.hpp
Normal file
27
Memory/Buffer.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
struct Buffer {
|
||||
Buffer(vk::PhysicalDevice phys_dev, vk::Device dev, vk::DeviceSize sz, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags mem_flags, vk::SharingMode sharing = vk::SharingMode::eExclusive);
|
||||
|
||||
vk::DeviceSize size;
|
||||
vk::Device dev;
|
||||
vk::DeviceMemory memory;
|
||||
vk::Buffer buffer;
|
||||
|
||||
void map(const uint8_t* data, vk::DeviceSize size);
|
||||
inline void map(const uint8_t* data) {
|
||||
map(data, size);
|
||||
}
|
||||
inline void map(const std::vector<uint8_t>& data) {
|
||||
map(data.data(), size);
|
||||
}
|
||||
|
||||
operator vk::Buffer& () {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
~Buffer();
|
||||
};
|
||||
44
Memory/Image.cpp
Normal file
44
Memory/Image.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <Memory/Image.hpp>
|
||||
#include <Memory/Memory.hpp>
|
||||
|
||||
|
||||
Image::Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Image _image, vk::MemoryPropertyFlags memory_flags) : dev(dev), image(_image) {
|
||||
|
||||
auto reqs = dev.getImageMemoryRequirements(image);
|
||||
|
||||
auto alloc = vk::MemoryAllocateInfo{
|
||||
.allocationSize = reqs.size,
|
||||
.memoryTypeIndex = mem::choose_heap(phys_dev, reqs, memory_flags),
|
||||
};
|
||||
memory = dev.allocateMemory(alloc);
|
||||
dev.bindImageMemory(image, memory, 0);
|
||||
|
||||
}
|
||||
|
||||
Image::Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::ImageCreateInfo info, vk::MemoryPropertyFlags memory_flags) : dev(dev) {
|
||||
image = dev.createImage(info);
|
||||
|
||||
*this = Image(phys_dev, dev, image, memory_flags);
|
||||
}
|
||||
|
||||
Image::Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Extent3D extent, vk::Format format, vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags memory_flags) : dev(dev) {
|
||||
auto info = vk::ImageCreateInfo{
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = format,
|
||||
.extent = extent,
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.tiling = tiling,
|
||||
.usage = usage,
|
||||
.sharingMode = vk::SharingMode::eExclusive,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
};
|
||||
|
||||
*this = Image(phys_dev, dev, info, memory_flags);
|
||||
}
|
||||
|
||||
void Image::cleanup() {
|
||||
dev.destroyImage(image);
|
||||
dev.freeMemory(memory);
|
||||
}
|
||||
20
Memory/Image.hpp
Normal file
20
Memory/Image.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include <util/log.hpp>
|
||||
|
||||
struct Image {
|
||||
vk::Device dev;
|
||||
vk::Extent3D extent;
|
||||
vk::Format format;
|
||||
vk::Image image;
|
||||
vk::DeviceMemory memory;
|
||||
|
||||
Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Image image, vk::MemoryPropertyFlags memory_flags);
|
||||
Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::ImageCreateInfo info, vk::MemoryPropertyFlags memory_flags);
|
||||
Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Extent3D extent, vk::Format format, vk::ImageTiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags memory_flags);
|
||||
|
||||
void cleanup();
|
||||
};
|
||||
@ -1,6 +1,8 @@
|
||||
#include <Renderer/CommandBuffer.hpp>
|
||||
#include <Renderer/Pipeline.hpp>
|
||||
|
||||
#include <Memory/Buffer.hpp>
|
||||
#include <Memory/Image.hpp>
|
||||
|
||||
#include <util/log.hpp>
|
||||
|
||||
@ -32,8 +34,27 @@ void CommandBuffer::begin() {
|
||||
command_buffer.begin(begin_info);
|
||||
}
|
||||
|
||||
void CommandBuffer::copy(vk::Buffer in, vk::Buffer out, vk::ArrayProxy<const vk::BufferCopy> regions) {
|
||||
command_buffer.copyBuffer(in, out, regions);
|
||||
void CommandBuffer::copy(vk::Buffer src, vk::Buffer dst, vk::ArrayProxy<const vk::BufferCopy> regions) {
|
||||
command_buffer.copyBuffer(src, dst, regions);
|
||||
}
|
||||
|
||||
void CommandBuffer::copy(Buffer& src, Image& dst, vk::ImageLayout layout) {
|
||||
auto region = vk::BufferImageCopy{
|
||||
.bufferOffset = 0,
|
||||
/* RowLength and ImageHeight are automatically set to imageExtent dimensions if set to 0 */
|
||||
.bufferRowLength = 0,
|
||||
.bufferImageHeight = 0,
|
||||
.imageSubresource = {
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 0,
|
||||
},
|
||||
.imageOffset = { 0, 0, 0 },
|
||||
.imageExtent = dst.extent,
|
||||
};
|
||||
|
||||
command_buffer.copyBufferToImage(src, dst.image, layout, region);
|
||||
}
|
||||
|
||||
void CommandBuffer::bind(const GraphicsPipeline& pipeline) {
|
||||
|
||||
@ -5,6 +5,9 @@
|
||||
|
||||
#include <util/int.hpp>
|
||||
|
||||
|
||||
struct Buffer;
|
||||
struct Image;
|
||||
struct GraphicsPipeline;
|
||||
struct ComputePipeline;
|
||||
|
||||
@ -18,6 +21,8 @@ struct CommandBuffer {
|
||||
|
||||
/* copy between buffer */
|
||||
void copy(vk::Buffer in, vk::Buffer out, vk::ArrayProxy<const vk::BufferCopy> regions);
|
||||
/* copy buffer to image */
|
||||
void copy(Buffer& in, Image& out, vk::ImageLayout layout = vk::ImageLayout::eTransferDstOptimal);
|
||||
|
||||
void bind(const GraphicsPipeline& pipeline);
|
||||
void bind(const ComputePipeline& pipeline);
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
#include <Renderer/Pipeline.hpp>
|
||||
|
||||
#include <Renderer/Shader.hpp>
|
||||
|
||||
ComputePipeline::ComputePipeline(vk::Device dev, const Shader& shader) {
|
||||
auto shader_info = vk::PipelineShaderStageCreateInfo {
|
||||
.stage = vk::ShaderStageFlagBits::eCompute,
|
||||
.module = shader,
|
||||
.pName = "main",
|
||||
};
|
||||
|
||||
auto layout = vk::PipelineLayoutCreateInfo {
|
||||
|
||||
};
|
||||
|
||||
auto create_info = vk::ComputePipelineCreateInfo {
|
||||
.stage = shader_info,
|
||||
};
|
||||
}
|
||||
@ -5,15 +5,16 @@
|
||||
|
||||
#include <Memory/Memory.hpp>
|
||||
|
||||
#include <util/Timer.hpp>
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
Renderer::Renderer(Window& win) : win(win) {
|
||||
/* Create Instance object */
|
||||
auto app_info = vk::ApplicationInfo {
|
||||
.pApplicationName = "Pl<EFBFBD>ascach Demo",
|
||||
.pApplicationName = "Pléascach Demo",
|
||||
.applicationVersion = VK_MAKE_API_VERSION(0, 0, 1, 0),
|
||||
.pEngineName = "Pl<EFBFBD>ascach",
|
||||
.pEngineName = "Pléascach",
|
||||
.engineVersion = VK_MAKE_API_VERSION(0, 0, 1, 0),
|
||||
.apiVersion = VK_API_VERSION_1_1,
|
||||
};
|
||||
@ -162,7 +163,6 @@ Renderer::Renderer(Window& win) : win(win) {
|
||||
}
|
||||
|
||||
void Renderer::draw() {
|
||||
Log::debug("draw() called \n");
|
||||
|
||||
if(dev.waitForFences(render_fence, true, UINT64_MAX) != vk::Result::eSuccess) {
|
||||
Log::error("Failed to wait for fences in draw()\n");
|
||||
@ -240,7 +240,6 @@ void Renderer::draw() {
|
||||
}
|
||||
|
||||
void Renderer::present() {
|
||||
Log::debug("present() called \n");
|
||||
auto present_info = vk::PresentInfoKHR{
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &render_wait_semaphore,
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include <Window/Window.hpp>
|
||||
|
||||
#include <Memory/Memory.hpp>
|
||||
#include <Memory/Image.hpp>
|
||||
|
||||
#include <util/log.hpp>
|
||||
|
||||
@ -66,38 +67,11 @@ void Swapchain::create(vk::SwapchainKHR old_swapchain) {
|
||||
|
||||
images = dev.getSwapchainImagesKHR(swapchain);
|
||||
|
||||
auto depth_image_info = vk::ImageCreateInfo{
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = vk::Format::eD16Unorm,
|
||||
.extent = {
|
||||
.width = extent.width,
|
||||
.height = extent.height,
|
||||
.depth = 1,
|
||||
},
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment,
|
||||
.sharingMode = vk::SharingMode::eExclusive,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = NULL,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
};
|
||||
|
||||
depth_image = dev.createImage(depth_image_info);
|
||||
|
||||
auto depth_mem_reqs = dev.getImageMemoryRequirements(depth_image);
|
||||
|
||||
auto depth_alloc_info = vk::MemoryAllocateInfo{
|
||||
.allocationSize = depth_mem_reqs.size,
|
||||
.memoryTypeIndex = mem::choose_heap(phys_dev, depth_mem_reqs, vk::MemoryPropertyFlagBits::eDeviceLocal),
|
||||
};
|
||||
|
||||
depth_alloc = dev.allocateMemory(depth_alloc_info);
|
||||
dev.bindImageMemory(depth_image, depth_alloc, 0);
|
||||
depth_image = std::make_unique<Image>(phys_dev, dev, vk::Extent3D { extent.width, extent.height, 1 }, vk::Format::eD16Unorm,
|
||||
vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eDepthStencilAttachment, vk::MemoryPropertyFlagBits::eDeviceLocal);
|
||||
|
||||
auto depth_view_info = vk::ImageViewCreateInfo {
|
||||
.image = depth_image,
|
||||
.image = depth_image->image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = vk::Format::eD16Unorm,
|
||||
.components = {
|
||||
@ -152,7 +126,6 @@ void Swapchain::create(vk::SwapchainKHR old_swapchain) {
|
||||
|
||||
framebuffers[i] = dev.createFramebuffer(framebuffer_info);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -172,8 +145,7 @@ void Swapchain::cleanup() {
|
||||
dev.destroyImageView(view);
|
||||
|
||||
dev.destroyImageView(depth_image_view);
|
||||
dev.destroyImage(depth_image);
|
||||
dev.freeMemory(depth_alloc);
|
||||
depth_image->cleanup();
|
||||
}
|
||||
|
||||
Swapchain::~Swapchain() {
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <Renderer/RenderPass.hpp>
|
||||
|
||||
struct Window;
|
||||
struct Image;
|
||||
|
||||
struct Swapchain {
|
||||
Swapchain(Window& win, vk::Device dev, vk::PhysicalDevice phys_dev, const vk::SurfaceKHR& surface, RenderPass render_pass);
|
||||
@ -34,9 +35,8 @@ struct Swapchain {
|
||||
std::vector<vk::ImageView> views;
|
||||
std::vector<vk::Framebuffer> framebuffers;
|
||||
|
||||
vk::Image depth_image;
|
||||
std::unique_ptr<Image> depth_image;
|
||||
vk::ImageView depth_image_view;
|
||||
vk::DeviceMemory depth_alloc;
|
||||
|
||||
vk::Format format;
|
||||
|
||||
|
||||
@ -1,46 +1,34 @@
|
||||
#include <Resources/Texture.hpp>
|
||||
#include <Memory/Buffer.hpp>
|
||||
#include <Memory/Memory.hpp>
|
||||
|
||||
#include <Renderer/CommandBuffer.hpp>
|
||||
|
||||
#include <util/file.hpp>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
|
||||
Texture::Texture(vk::Device dev, vk::PhysicalDevice phys_dev, const std::string& fname) {
|
||||
Texture::Texture(vk::PhysicalDevice phys_dev, vk::Device dev, CommandBuffer command_buffer, const std::string& fname) {
|
||||
int n_channels;
|
||||
vk::Extent3D extent;
|
||||
auto image_data = stbi_load(fname.c_str(), reinterpret_cast<int*>(&extent.width), reinterpret_cast<int*>(&extent.height), NULL, NULL);
|
||||
|
||||
auto image_data = stbi_load(fname.c_str(), reinterpret_cast<int*>(&extent.width), reinterpret_cast<int*>(&extent.height), &n_channels, STBI_rgb_alpha);
|
||||
extent.depth = 1;
|
||||
|
||||
auto image_info = vk::ImageCreateInfo{
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = vk::Format::eR8G8B8A8Unorm,
|
||||
.extent = extent,
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.tiling = vk::ImageTiling::eOptimal,
|
||||
.usage = vk::ImageUsageFlagBits::eSampled,
|
||||
.sharingMode = vk::SharingMode::eExclusive,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
};
|
||||
image = std::make_unique<Image>(phys_dev, dev, extent, vk::Format::eR8G8B8A8Srgb,
|
||||
vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eSampled,
|
||||
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
|
||||
|
||||
image = dev.createImage(image_info);
|
||||
vk::DeviceSize sz = extent.width * extent.height * sizeof(uint32_t);
|
||||
|
||||
auto reqs = dev.getImageMemoryRequirements(image);
|
||||
/* staging buffer to hold image data from the CPU */
|
||||
Buffer staging(phys_dev, dev, sz, vk::BufferUsageFlagBits::eTransferSrc,
|
||||
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
|
||||
|
||||
staging.map(image_data);
|
||||
stbi_image_free(image_data);
|
||||
|
||||
auto image_alloc_info = vk::MemoryAllocateInfo{
|
||||
.allocationSize = reqs.size,
|
||||
.memoryTypeIndex = mem::choose_heap(phys_dev, reqs, vk::MemoryPropertyFlagBits::eHostVisible),
|
||||
};
|
||||
|
||||
image_alloc = dev.allocateMemory(image_alloc_info);
|
||||
dev.bindImageMemory(image, image_alloc, 0);
|
||||
|
||||
/* TODO: Copy memory into image using buffers */
|
||||
}
|
||||
|
||||
void Texture::cleanup(vk::Device dev) {
|
||||
dev.freeMemory(image_alloc);
|
||||
command_buffer.copy(staging, *image);
|
||||
}
|
||||
@ -3,9 +3,11 @@
|
||||
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include <Memory/Image.hpp>
|
||||
|
||||
struct CommandBuffer;
|
||||
|
||||
struct Texture {
|
||||
vk::Image image;
|
||||
vk::DeviceMemory image_alloc;
|
||||
Texture(vk::Device dev, vk::PhysicalDevice phys_dev, const std::string& fname);
|
||||
void cleanup(vk::Device dev);
|
||||
std::unique_ptr<Image> image;
|
||||
Texture(vk::PhysicalDevice phys_dev, vk::Device dev, CommandBuffer command_buffer, const std::string& fname);
|
||||
};
|
||||
@ -3,6 +3,8 @@
|
||||
#include <Renderer/Renderer.hpp>
|
||||
|
||||
#include <util/log.hpp>
|
||||
#include <util/Timer.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
@ -12,6 +14,7 @@ int main(int argc, char* argv[]) {
|
||||
Renderer ren(win);
|
||||
|
||||
while (!in->shouldClose()) {
|
||||
Timer frame_timer;
|
||||
in->poll();
|
||||
|
||||
while (in->queue.size()) {
|
||||
@ -39,6 +42,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
ren.draw();
|
||||
ren.present();
|
||||
Log::debug("Frame: %lf milliseconds (60fps ~ 16.67)\n", frame_timer.stop());
|
||||
}
|
||||
|
||||
} catch (const std::string& e) {
|
||||
|
||||
38
util/Timer.hpp
Normal file
38
util/Timer.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
/* get the time in milliseconds */
|
||||
struct Timer {
|
||||
std::chrono::time_point<std::chrono::steady_clock> start_time, end_time;
|
||||
bool running = false;
|
||||
|
||||
|
||||
Timer() {
|
||||
start();
|
||||
}
|
||||
|
||||
inline void start() {
|
||||
start_time = std::chrono::steady_clock::now();
|
||||
running = true;
|
||||
}
|
||||
|
||||
inline void reset() {
|
||||
start();
|
||||
}
|
||||
|
||||
inline double read() {
|
||||
if (running) {
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(end - start_time).count() / 1000.0;
|
||||
}
|
||||
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time).count() / 1000.0;
|
||||
}
|
||||
|
||||
inline double stop() {
|
||||
end_time = std::chrono::steady_clock::now();
|
||||
running = false;
|
||||
return read();
|
||||
}
|
||||
};
|
||||
@ -12,7 +12,7 @@ namespace Log {
|
||||
return static_cast<MessageLevelBit>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
|
||||
}
|
||||
|
||||
static const MessageLevelBit log_mask = ERROR | INFO;
|
||||
static const MessageLevelBit log_mask = ERROR | INFO | DEBUG;
|
||||
|
||||
template<typename ...Args>
|
||||
static void print(MessageLevelBit level, const std::string& fmt, Args... args) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user