diff --git a/Memory/Image.cpp b/Memory/Image.cpp index 116f66d..7060d09 100644 --- a/Memory/Image.cpp +++ b/Memory/Image.cpp @@ -2,7 +2,7 @@ #include -Image::Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Image _image, vk::MemoryPropertyFlags memory_flags) : dev(dev), image(_image) { +Image::Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Image _image, vk::MemoryPropertyFlags memory_flags, vk::Extent3D& extent) : dev(dev), image(_image) { auto reqs = dev.getImageMemoryRequirements(image); @@ -12,13 +12,14 @@ Image::Image(vk::PhysicalDevice phys_dev, vk::Device dev, vk::Image _image, vk:: }; memory = dev.allocateMemory(alloc); dev.bindImageMemory(image, memory, 0); + this->extent = extent; + Log::debug("Image memory: %p\n", memory); } 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); + *this = Image(phys_dev, dev, image, memory_flags, info.extent); } 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) { diff --git a/Memory/Image.hpp b/Memory/Image.hpp index 8510d93..b3fc557 100644 --- a/Memory/Image.hpp +++ b/Memory/Image.hpp @@ -12,9 +12,13 @@ struct Image { 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::Image image, vk::MemoryPropertyFlags memory_flags, vk::Extent3D& extent); 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); + operator vk::Image&() { + return image; + } + void cleanup(); }; diff --git a/README.md b/README.md index 598c6cb..27fb8a2 100644 --- a/README.md +++ b/README.md @@ -4,5 +4,6 @@ - Add more comments ## Long Term Improvements - ~~Properly query surface to find supported formats for surfaces~~ +- Fix all this cleanup vs destructor NONSENSE (inconsistency) - Add pipeline caching - Make more robust solution to window minimization (flushing out Input system should provide candidates) \ No newline at end of file diff --git a/Renderer/CommandBuffer.cpp b/Renderer/CommandBuffer.cpp index 72bf254..bf23414 100644 --- a/Renderer/CommandBuffer.cpp +++ b/Renderer/CommandBuffer.cpp @@ -8,6 +8,7 @@ #include CommandBuffer::CommandBuffer(vk::Device dev, u32 queue_family) { + Log::debug("Command Buffer created\n"); /* (For now) allow command buffers to be individually recycled */ auto pool_info = vk::CommandPoolCreateInfo { .flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer @@ -49,7 +50,7 @@ void CommandBuffer::copy(Buffer& src, Image& dst, vk::ImageLayout layout) { .aspectMask = vk::ImageAspectFlagBits::eColor, .mipLevel = 0, .baseArrayLayer = 0, - .layerCount = 0, + .layerCount = 1, }, .imageOffset = { 0, 0, 0 }, .imageExtent = dst.extent, diff --git a/Renderer/Pipeline.cpp b/Renderer/Pipeline.cpp index b5a83b5..33db072 100644 --- a/Renderer/Pipeline.cpp +++ b/Renderer/Pipeline.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -188,6 +189,22 @@ void GraphicsPipeline::update(uint32_t binding, const UniformBuffer& uni) { }, nullptr); } +void GraphicsPipeline::update(uint32_t binding, const Texture& tex) { + auto tex_info = vk::DescriptorImageInfo { + .sampler = tex.sampler, + .imageView = tex.view, + .imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal, + }; + + dev.updateDescriptorSets(vk::WriteDescriptorSet { + .dstSet = desc_set, + .dstBinding = binding, + .descriptorCount = 1, + .descriptorType = vk::DescriptorType::eCombinedImageSampler, + .pImageInfo = &tex_info, + }, nullptr); +} + GraphicsPipeline::~GraphicsPipeline() { dev.destroyDescriptorSetLayout(desc_layout); dev.destroyPipelineLayout(layout); diff --git a/Renderer/Pipeline.hpp b/Renderer/Pipeline.hpp index fedc1b8..ca5f104 100644 --- a/Renderer/Pipeline.hpp +++ b/Renderer/Pipeline.hpp @@ -7,6 +7,7 @@ struct Shader; struct UniformBuffer; struct VertexBuffer; struct RenderPass; +struct Texture; struct GraphicsPipeline { GraphicsPipeline(vk::Device dev, const std::vector& shaders, @@ -26,6 +27,7 @@ struct GraphicsPipeline { /* create overload for every type of object we need to update */ void update(uint32_t binding, const UniformBuffer& uni); + void update(uint32_t binding, const Texture& tex); ~GraphicsPipeline(); }; diff --git a/Renderer/Renderer.cpp b/Renderer/Renderer.cpp index 53d10ec..c690ad9 100644 --- a/Renderer/Renderer.cpp +++ b/Renderer/Renderer.cpp @@ -1,4 +1,6 @@ #include +#include + #include #include @@ -16,12 +18,12 @@ const static std::vector triangle = { - {{ 1.0, -1.0, 1.0 }, { 1.0, 0.0 }}, - {{ 1.0, 1.0, 1.0 }, { 1.0, 1.0 }}, - {{-1.0, 1.0, 1.0 }, { 0.0, 1.0 }}, - {{-1.0, 1.0, 1.0 }, { 0.0, 1.0 }}, - {{-1.0, -1.0, 1.0 }, { 0.0, 0.0 }}, - {{ 1.0, -1.0, 1.0 }, { 1.0, 0.0 }}, + {{ 1.0, -1.0, -1.0 }, { 1.0, 0.0 }}, + {{ 1.0, 1.0, -1.0 }, { 1.0, 1.0 }}, + {{-1.0, 1.0, -1.0 }, { 0.0, 1.0 }}, + {{-1.0, 1.0, -1.0 }, { 0.0, 1.0 }}, + {{-1.0, -1.0, -1.0 }, { 0.0, 0.0 }}, + {{ 1.0, -1.0, -1.0 }, { 1.0, 0.0 }}, }; using namespace std::string_literals; @@ -101,7 +103,7 @@ Renderer::Renderer(Window& win) : win(win) { if (discrete_idx == -1) discrete_idx = 0; - auto& phys_dev = phys_devs[discrete_idx]; + phys_dev = phys_devs[discrete_idx]; Log::info("Selected device: \"%s\" (#%zu)\n", phys_dev.getProperties().deviceName.data(), discrete_idx); /* find queue family */ @@ -184,23 +186,65 @@ Renderer::Renderer(Window& win) : win(win) { vertex_buffer->upload(triangle); + textures = createTextures({ + "assets/textures/oil.jpg", + }); + std::vector shaders = { { dev, "assets/shaders/basic.vert.spv", vk::ShaderStageFlagBits::eVertex }, - { dev, "assets/shaders/trace.frag.spv", vk::ShaderStageFlagBits::eFragment }, + { dev, "assets/shaders/basic.frag.spv", vk::ShaderStageFlagBits::eFragment }, }; std::vector bindings = { uniform_buffer->binding(0), + textures[0].binding(1), }; pipeline = std::make_unique(dev, shaders, swapchain->extent, *render_pass, bindings, *vertex_buffer); pipeline->update(0, *uniform_buffer); + pipeline->update(1, textures[0]); shaders[0].cleanup(); shaders[1].cleanup(); } +std::vector Renderer::createTextures(const std::vector& names) { + std::vector ret; + + CommandBuffer texture_cmd(dev, queue_family); + + texture_cmd.begin(); + + for (const auto& name : names) { + ret.push_back({phys_dev, dev, texture_cmd, "assets/textures/oil.jpg"}); + } + + texture_cmd.end(); + + auto texture_creation_fence = dev.createFence(vk::FenceCreateInfo {}); + dev.resetFences(texture_creation_fence); + + queue.submit(vk::SubmitInfo { + .commandBufferCount = 1, + .pCommandBuffers = texture_cmd, + }, texture_creation_fence); + + if (dev.waitForFences(texture_creation_fence, vk::True, UINT64_MAX) != vk::Result::eSuccess) { + Log::error("Failed to create textures\n"); + } + + dev.destroyFence(texture_creation_fence); + + for (auto& tex : ret) { + tex.finishCreation(); + } + + texture_cmd.cleanup(dev); + + return ret; +} + void Renderer::draw() { if(dev.waitForFences(render_fence, true, UINT64_MAX) != vk::Result::eSuccess) { @@ -270,7 +314,7 @@ void Renderer::draw() { const auto p = glm::perspective(glm::radians(90.0f), static_cast(sz.width) / static_cast(sz.height), 0.01f, 50.0f); uniform_buffer->upload(UniformData{ - //.mvp = p * glm::rotate(glm::mat4(1.0), glm::radians(static_cast(frame)), glm::vec3(1.0, 1.0, 1.0)), + .mvp = p * glm::rotate(glm::mat4(1.0), glm::radians(static_cast(frame)), glm::vec3(1.0, 1.0, 1.0)), .time = static_cast(frame) * 0.0167f, .aspect_ratio = static_cast(sz.width)/static_cast(sz.height), }); @@ -331,6 +375,10 @@ Renderer::~Renderer() { vertex_buffer.reset(); pipeline.reset(); + for (auto& tex : textures) { + tex.cleanup(); + } + swapchain.reset(); dev.destroySemaphore(image_wait_semaphore); diff --git a/Renderer/Renderer.hpp b/Renderer/Renderer.hpp index 72b09be..638f3e4 100644 --- a/Renderer/Renderer.hpp +++ b/Renderer/Renderer.hpp @@ -12,18 +12,22 @@ struct Window; struct UniformBuffer; struct VertexBuffer; +struct Texture; /* Contains all of the Vulkan objects involved in rendering the scene */ struct Renderer { Renderer(Window& win); ~Renderer(); + std::vector createTextures(const std::vector& names); + void draw(); void present(); Window& win; vk::Instance instance; + vk::PhysicalDevice phys_dev; vk::Device dev; vk::Fence render_fence; @@ -42,6 +46,8 @@ struct Renderer { std::unique_ptr vertex_buffer; std::unique_ptr uniform_buffer; + std::vector textures; + uint32_t current_image_idx; uint64_t frame = 0; }; diff --git a/Resources/Texture.cpp b/Resources/Texture.cpp index f8130b5..53ac4f5 100644 --- a/Resources/Texture.cpp +++ b/Resources/Texture.cpp @@ -5,32 +5,103 @@ #include #include +#include #define STB_IMAGE_IMPLEMENTATION #include +/* externall synchonized, just writes to a command buffer, you still need to pull the trigger (allows bulk texture image preperation) */ +Texture::Texture(vk::PhysicalDevice phys_dev, vk::Device dev, CommandBuffer& command_buffer, const std::string& fname) : dev(dev) { + Log::debug("Starting texture creation for: %s\n", fname.c_str()); -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(&extent.width), reinterpret_cast(&extent.height), &n_channels, STBI_rgb_alpha); extent.depth = 1; - image = std::make_unique(phys_dev, dev, extent, vk::Format::eR8G8B8A8Srgb, - vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eSampled, + image = std::make_unique(phys_dev, dev, extent, vk::Format::eR8G8B8A8Unorm, + vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); vk::DeviceSize sz = static_cast(extent.width * extent.height) * sizeof(uint32_t); /* staging buffer to hold image data from the CPU */ - Buffer staging(phys_dev, dev, sz, vk::BufferUsageFlagBits::eTransferSrc, + staging = std::make_unique(phys_dev, dev, sz, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); - staging.upload(image_data); + staging->upload(image_data); stbi_image_free(image_data); - command_buffer.copy(staging, *image); + /* pipeline memory barrier ensures this doesn't get reordered wrong */ - /* TODO: Finish, also rethink if we want submission to happen internally or externally to the function for creation */ + auto staging_buffer_trans_barrier = vk::ImageMemoryBarrier { + .srcAccessMask = vk::AccessFlagBits(0), + .dstAccessMask = vk::AccessFlagBits::eTransferWrite, + .oldLayout = vk::ImageLayout::eUndefined, + .newLayout = vk::ImageLayout::eTransferDstOptimal, + .image = *image, + .subresourceRange = vk::ImageSubresourceRange { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .levelCount = 1, + .layerCount = 1, + }, + }; + + /* transfer optimal --> shader optimal */ + auto shader_barrier = vk::ImageMemoryBarrier{ + .srcAccessMask = vk::AccessFlagBits::eTransferWrite, + .dstAccessMask = vk::AccessFlagBits::eShaderRead, + .oldLayout = vk::ImageLayout::eTransferDstOptimal, + .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, + .image = *image, + .subresourceRange = vk::ImageSubresourceRange { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .levelCount = 1, + .layerCount = 1, + }, + }; + + command_buffer.command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits(0), nullptr, nullptr, staging_buffer_trans_barrier); + command_buffer.copy(*staging, *image); + command_buffer.command_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, vk::DependencyFlagBits(0), nullptr, nullptr, shader_barrier); +} + + +void Texture::finishCreation() { + view = dev.createImageView(vk::ImageViewCreateInfo { + .image = *image, + .viewType = vk::ImageViewType::e2D, + .format = vk::Format::eR8G8B8A8Unorm, + .subresourceRange = vk::ImageSubresourceRange{ + .aspectMask = vk::ImageAspectFlagBits::eColor, + .levelCount = 1, + .layerCount = 1, + }, + }); + + sampler = dev.createSampler(vk::SamplerCreateInfo { + .magFilter = vk::Filter::eLinear, + .minFilter = vk::Filter::eLinear, + .mipmapMode = vk::SamplerMipmapMode::eLinear, + .addressModeU = vk::SamplerAddressMode::eClampToEdge, + .addressModeV = vk::SamplerAddressMode::eClampToEdge, + .addressModeW = vk::SamplerAddressMode::eClampToEdge, + .mipLodBias = 0.0, + .anisotropyEnable = vk::False, + .maxAnisotropy = 0.0, + .compareEnable = vk::False, + .compareOp = vk::CompareOp::eAlways, + .minLod = 0.0, + .maxLod = 0.0, + .borderColor = vk::BorderColor::eIntOpaqueBlack, + .unnormalizedCoordinates = vk::False, + }); +} + +void Texture::cleanup() { + staging.reset(); + image->cleanup(); + dev.destroyImageView(view); + dev.destroySampler(sampler); } \ No newline at end of file diff --git a/Resources/Texture.hpp b/Resources/Texture.hpp index fad2396..5b10461 100644 --- a/Resources/Texture.hpp +++ b/Resources/Texture.hpp @@ -7,8 +7,31 @@ #include struct CommandBuffer; +struct Buffer; struct Texture { + vk::Device dev; std::unique_ptr image; - Texture(vk::PhysicalDevice phys_dev, vk::Device dev, CommandBuffer command_buffer, const std::string& fname); + vk::ImageView view; + vk::Sampler sampler; + + std::unique_ptr staging; + + Texture(vk::PhysicalDevice phys_dev, vk::Device dev, CommandBuffer& command_buffer, const std::string& fname); + + inline vk::DescriptorSetLayoutBinding binding(uint32_t binding, vk::ShaderStageFlags stages = vk::ShaderStageFlagBits::eAll) { + return vk::DescriptorSetLayoutBinding { + .binding = binding, + .descriptorType = vk::DescriptorType::eCombinedImageSampler, + .descriptorCount = 1, + .stageFlags = vk::ShaderStageFlagBits::eFragment, + .pImmutableSamplers = nullptr, + }; + } + + /* seperates out steps that need to be taken *after* command buffer is submitted */ + void finishCreation(); + + + void cleanup(); }; \ No newline at end of file diff --git a/assets/shaders/basic.frag b/assets/shaders/basic.frag index 347d294..7f65238 100644 --- a/assets/shaders/basic.frag +++ b/assets/shaders/basic.frag @@ -8,6 +8,8 @@ layout (set = 0, binding = 0) uniform Matrices { float time; }; +layout (set = 0, binding = 1) uniform sampler2D tex; + void main() { - FragColor = vec4(1.0, 1.0, 1.0, 1.0); + FragColor = texture(tex, texCoord); } \ No newline at end of file diff --git a/assets/shaders/basic.frag.spv b/assets/shaders/basic.frag.spv index 80131c7..c3781e4 100644 Binary files a/assets/shaders/basic.frag.spv and b/assets/shaders/basic.frag.spv differ diff --git a/assets/shaders/basic.vert b/assets/shaders/basic.vert index 378c838..3ed02c6 100644 --- a/assets/shaders/basic.vert +++ b/assets/shaders/basic.vert @@ -10,6 +10,6 @@ layout (set = 0, binding = 0) uniform Matrices { }; void main() { - gl_Position = vec4(aPos, 1.0); + gl_Position = mpv*vec4(aPos, 1.0); texCoord = aTexCoord; } \ No newline at end of file diff --git a/assets/shaders/basic.vert.spv b/assets/shaders/basic.vert.spv index 1c39b82..8b0dbc5 100644 Binary files a/assets/shaders/basic.vert.spv and b/assets/shaders/basic.vert.spv differ diff --git a/assets/shaders/trace.frag.spv b/assets/shaders/trace.frag.spv index b16437f..2574cde 100644 Binary files a/assets/shaders/trace.frag.spv and b/assets/shaders/trace.frag.spv differ diff --git a/assets/textures/oil.jpg b/assets/textures/oil.jpg new file mode 100644 index 0000000..cc60587 Binary files /dev/null and b/assets/textures/oil.jpg differ diff --git a/pléascach.cpp b/pléascach.cpp index d165c17..2c35f42 100644 --- a/pléascach.cpp +++ b/pléascach.cpp @@ -42,7 +42,7 @@ int main(int argc, char* argv[]) { ren.draw(); ren.present(); - Log::debug("Frame: %.2lf milliseconds (60fps ~ 16.67)\n", frame_timer.stop()); + Log::debug("Frame: %.2lf milliseconds (60fps ~ 16.67)\r", frame_timer.stop()); } } catch (const std::string& e) { diff --git a/util/log.hpp b/util/log.hpp index 146cc0b..c4b3f59 100644 --- a/util/log.hpp +++ b/util/log.hpp @@ -13,7 +13,7 @@ namespace Log { return static_cast(static_cast(a) | static_cast(b)); } - static const MessageLevelBit log_mask = ERROR | INFO; + static const MessageLevelBit log_mask = ERROR | INFO | DEBUG; template static void print(MessageLevelBit level, const std::string& fmt, Args... args) {