From 7213c85fdf0743cbf86eb52aabbf6c6d766e740d Mon Sep 17 00:00:00 2001 From: Draklaw Date: Fri, 11 Mar 2022 23:45:27 +0100 Subject: [PATCH] Depth test. --- CMakeLists.txt | 1 + shaders/shader.geom | 2 +- shaders/shader.vert | 11 +- src/Renderer.cpp | 247 +++++++++++++++++++++++++++++--------------- src/Renderer.h | 4 + src/VkExpe.cpp | 17 ++- src/core/math.cpp | 10 +- src/core/utils.h | 8 +- src/vk/Image.cpp | 124 ++++++++++++++++++++++ src/vk/Image.h | 66 ++++++++++++ 10 files changed, 392 insertions(+), 98 deletions(-) create mode 100644 src/vk/Image.cpp create mode 100644 src/vk/Image.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c29d86..9eee940 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ add_executable(vk_expe src/vk/Pipeline.cpp src/vk/Memory.cpp src/vk/Buffer.cpp + src/vk/Image.cpp src/vk/ImageView.cpp src/vk/DescriptorSetLayout.cpp src/vk/PipelineLayout.cpp diff --git a/shaders/shader.geom b/shaders/shader.geom index f924475..99a3d83 100644 --- a/shaders/shader.geom +++ b/shaders/shader.geom @@ -43,7 +43,7 @@ void main() { vec2 v0 = p0 - p2; vec2 v1 = p1 - p2; - out_edge_dist[i] = determinant(mat2(v0, v1)) / length(v1); + out_edge_dist[i] = abs(determinant(mat2(v0, v1))) / length(v1); EmitVertex(); } diff --git a/shaders/shader.vert b/shaders/shader.vert index aa8206e..6fe926a 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -18,11 +18,12 @@ layout(location = 1) out vec3 out_normal; layout(location = 2) out vec3 out_color; void main() { - float lod = clamp( - 2.0 * dot(transpose(uniforms.scene_from_model)[0].xyz, in_position) + 0.5, - 0.0, 1.0 - ); - vec3 position = mix(in_position2, in_position, lod); + // float lod = clamp( + // 2.0 * dot(transpose(uniforms.scene_from_model)[0].xyz, in_position) + 0.5, + // 0.0, 1.0 + // ); + // vec3 position = mix(in_position2, in_position, lod); + vec3 position = in_position; out_position = uniforms.projection_from_scene * uniforms.scene_from_model * diff --git a/src/Renderer.cpp b/src/Renderer.cpp index 3cc6652..ab61701 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -59,35 +59,31 @@ std::array vertex_attributes_description() std::vector vertices = { - // {{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}}, - // {{0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}}, - // {{-0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}}, - // {{0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}}, - - // {{-0.5f, -0.5f, 0.5f}, {0.0f, 1.0f, 1.0f}}, - // {{0.5f, -0.5f, 0.5f}, {1.0f, 0.0f, 1.0f}}, - // {{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 0.0f}}, - // {{0.5f, 0.5f, 0.5f}, {0.2f, 0.2f, 0.2f}}, + {{-1.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 0.0f, 0.0f}}, + {{ 1.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 0.0f, 0.0f}}, + {{-1.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 0.0f, 0.0f}}, + {{ 1.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 0.0f, 0.0f}}, + + {{0.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 0.0f}}, + {{0.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 0.0f}}, + {{0.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 0.0f}}, + {{0.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 0.0f}}, + + {{-1.0f, 0.0f, -1.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, 1.0f}}, + {{ 1.0f, 0.0f, -1.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, 1.0f}}, + {{-1.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, 1.0f}}, + {{ 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, 1.0f}}, }; std::vector indices = { - // 0, 1, 2, - // 2, 1, 3, + 0, 1, 2, + 2, 1, 3, - // 1, 5, 3, - // 3, 5, 7, + 4, 5, 6, + 6, 5, 7, - // 5, 4, 7, - // 7, 4, 6, - - // 4, 0, 6, - // 6, 0, 2, - - // 0, 4, 1, - // 1, 4, 5, - - // 2, 3, 6, - // 6, 3, 7, + 8, 9, 10, + 10, 9, 11, }; struct Uniforms { @@ -102,43 +98,43 @@ Renderer::Renderer() { m_swapchain.register_creation_callback( std::bind(&Renderer::create_swapchain_objects, this)); - auto const subdiv_count = 4; + // auto const subdiv_count = 4; - vertices.resize(6 * Cell::vertex_count(subdiv_count)); - indices.resize(6 * 3 * Cell::triangle_count(subdiv_count)); + // vertices.resize(6 * Cell::vertex_count(subdiv_count)); + // indices.resize(6 * 3 * Cell::triangle_count(subdiv_count)); - Vector3AV positions( - vertices.size(), vertices.data(), - sizeof(Vertex), offsetof(Vertex, position) - ); + // Vector3AV positions( + // vertices.size(), vertices.data(), + // sizeof(Vertex), offsetof(Vertex, position) + // ); - Vector3AV positions2( - vertices.size(), vertices.data(), - sizeof(Vertex), offsetof(Vertex, position2) - ); + // Vector3AV positions2( + // vertices.size(), vertices.data(), + // sizeof(Vertex), offsetof(Vertex, position2) + // ); - Vector3AV normals( - vertices.size(), vertices.data(), - sizeof(Vertex), offsetof(Vertex, normal) - ); + // Vector3AV normals( + // vertices.size(), vertices.data(), + // sizeof(Vertex), offsetof(Vertex, normal) + // ); - Vector3AV colors( - vertices.size(), vertices.data(), - sizeof(Vertex), offsetof(Vertex, color) - ); + // Vector3AV colors( + // vertices.size(), vertices.data(), + // sizeof(Vertex), offsetof(Vertex, color) + // ); - TriangleAV triangles( - indices.size() / 3, - indices.data() - ); + // TriangleAV triangles( + // indices.size() / 3, + // indices.data() + // ); - Planet planet; - planet.build_mesh(positions, positions2, normals, triangles, subdiv_count); + // Planet planet; + // planet.build_mesh(positions, positions2, normals, triangles, subdiv_count); - for (size_t vertex_index = 0; vertex_index < vertices.size(); vertex_index += 1) { - colors[vertex_index] = - positions[vertex_index] / 2.0f + Vector3::Constant(0.5f); - } + // for (size_t vertex_index = 0; vertex_index < vertices.size(); vertex_index += 1) { + // colors[vertex_index] = + // positions[vertex_index] / 2.0f + Vector3::Constant(0.5f); + // } // for(size_t vi = 0; vi < vertices.size(); vi += 1) // logger.debug() << "v" << vi << ": " @@ -315,41 +311,64 @@ void Renderer::create_pipeline_layout() { } void Renderer::create_render_pass() { - VkAttachmentDescription color_attachment { - .format = m_context.surface_format().format, - .samples = VK_SAMPLE_COUNT_1_BIT, - .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - }; - - VkAttachmentReference color_attachment_ref = { + VkAttachmentDescription attachments[] { + { + .format = m_context.surface_format().format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + }, + { + .format = VK_FORMAT_X8_D24_UNORM_PACK32, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + }, + }; + + VkAttachmentReference color_attachment_ref { .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }; + VkAttachmentReference depth_attachment_ref { + .attachment = 1, + .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + }; VkSubpassDescription subpass { .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, .colorAttachmentCount = 1, .pColorAttachments = &color_attachment_ref, + .pDepthStencilAttachment = &depth_attachment_ref, }; VkSubpassDependency subpass_dep = { .srcSubpass = VK_SUBPASS_EXTERNAL, .dstSubpass = 0, - .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcStageMask = + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstStageMask = + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, .srcAccessMask = 0, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dstAccessMask = + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, }; VkRenderPassCreateInfo render_pass_info { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - .attachmentCount = 1, - .pAttachments = &color_attachment, + .attachmentCount = uint32_t(std::extent_v), + .pAttachments = attachments, .subpassCount = 1, .pSubpasses = &subpass, .dependencyCount = 1, @@ -478,8 +497,8 @@ void Renderer::create_graphic_pipeline() { .depthClampEnable = VK_FALSE, .rasterizerDiscardEnable = VK_FALSE, .polygonMode = VK_POLYGON_MODE_FILL, - // .cullMode = VK_CULL_MODE_NONE, - .cullMode = VK_CULL_MODE_BACK_BIT, + .cullMode = VK_CULL_MODE_NONE, + // .cullMode = VK_CULL_MODE_BACK_BIT, .frontFace = VK_FRONT_FACE_CLOCKWISE, .depthBiasEnable = VK_FALSE, .depthBiasConstantFactor = 0.0f, @@ -498,6 +517,13 @@ void Renderer::create_graphic_pipeline() { .alphaToOneEnable = VK_FALSE, }; + VkPipelineDepthStencilStateCreateInfo depth_stencil_info { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .depthTestEnable = VK_TRUE, + .depthWriteEnable = VK_TRUE, + .depthCompareOp = VK_COMPARE_OP_LESS, + }; + VkPipelineColorBlendAttachmentState color_blend_attachment { .blendEnable = VK_FALSE, .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, @@ -531,7 +557,7 @@ void Renderer::create_graphic_pipeline() { .pViewportState = &viewport_info, .pRasterizationState = &rasterization_info, .pMultisampleState = &multisample_info, - .pDepthStencilState = nullptr, + .pDepthStencilState = &depth_stencil_info, .pColorBlendState = &color_blend_info, .pDynamicState = nullptr, .layout = m_pipeline_layout, @@ -549,6 +575,7 @@ void Renderer::initialize_image_states(size_t image_index) { auto& image_states = m_image_states[image_index]; image_states.m_image_index = image_index; + create_depth_buffer(image_states); create_framebuffer(image_states); create_uniform_buffer(image_states); @@ -562,12 +589,63 @@ void Renderer::initialize_image_states(size_t image_index) { } +void Renderer::create_depth_buffer(ImageStates& image_states) +{ + image_states.m_depth_buffer = vk::Image( + m_context, + VkImageCreateInfo { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .imageType = VK_IMAGE_TYPE_2D, + .format = VK_FORMAT_X8_D24_UNORM_PACK32, + .extent = { + m_swapchain.extent().width, + m_swapchain.extent().height, + 1 + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT + ); + + image_states.m_depth_buffer_view = vk::ImageView( + m_context, + VkImageViewCreateInfo { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = image_states.m_depth_buffer, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = VK_FORMAT_X8_D24_UNORM_PACK32, + .components = { + .r = VK_COMPONENT_SWIZZLE_R, + .g = VK_COMPONENT_SWIZZLE_G, + .b = VK_COMPONENT_SWIZZLE_B, + .a = VK_COMPONENT_SWIZZLE_A, + }, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + } + } + ); +} + void Renderer::create_framebuffer(ImageStates& image_states) { - auto view = m_swapchain.image_view(image_states.m_image_index); + VkImageView views[] { + m_swapchain.image_view(image_states.m_image_index), + image_states.m_depth_buffer_view, + }; image_states.m_framebuffer = vk::Framebuffer( m_context, m_render_pass, - &view, + views, m_swapchain.extent() ); } @@ -661,10 +739,17 @@ void Renderer::create_command_buffer(ImageStates& image_states) { ) != VK_SUCCESS) throw std::runtime_error("failed to begin command buffer"); - VkClearValue clear_color = { - .color = { - .float32 = { 0.0f, 0.0f, 0.0f, 1.0f } - } + VkClearValue clear_values[] = { + { + .color = { + .float32 = { 0.0f, 0.0f, 0.0f, 1.0f } + } + }, + { + .depthStencil = { + .depth = 1.0f, + } + }, }; VkRenderPassBeginInfo pass_info { @@ -675,8 +760,8 @@ void Renderer::create_command_buffer(ImageStates& image_states) { .offset = { 0, 0 }, .extent = m_swapchain.extent(), }, - .clearValueCount = 1, - .pClearValues = &clear_color, + .clearValueCount = uint32_t(std::extent_v), + .pClearValues = clear_values, }; vkCmdBeginRenderPass( diff --git a/src/Renderer.h b/src/Renderer.h index 9cba2f3..d33f8a7 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -81,6 +82,7 @@ private: void initialize_image_states(size_t image_index); + void create_depth_buffer(ImageStates& image_states); void create_framebuffer(ImageStates& image_states); void create_uniform_buffer(ImageStates& image_states); @@ -119,6 +121,8 @@ private: struct ImageStates { size_t m_image_index; + vk::Image m_depth_buffer; + vk::ImageView m_depth_buffer_view; vk::Framebuffer m_framebuffer; vk::Buffer m_uniform_buffer; diff --git a/src/VkExpe.cpp b/src/VkExpe.cpp index d3f364b..c6f6e92 100644 --- a/src/VkExpe.cpp +++ b/src/VkExpe.cpp @@ -70,9 +70,22 @@ void VkExpe::run() { auto last_time = std::chrono::high_resolution_clock::now(); - SDL_Event event; + // SDL_Event event; + std::vector events; + events.reserve(128); while(m_running) { - while(SDL_PollEvent(&event)) { + SDL_PumpEvents(); + + int event_count = SDL_PeepEvents(nullptr, 0, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT); + if(event_count < 0) { + logger.error() << SDL_GetError(); + break; + } + + events.resize(event_count); + SDL_PeepEvents(events.data(), event_count, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT); + + for(const auto& event: events) { switch(event.type) { case SDL_QUIT: m_running = false; diff --git a/src/core/math.cpp b/src/core/math.cpp index ebd395b..f6dc661 100644 --- a/src/core/math.cpp +++ b/src/core/math.cpp @@ -11,13 +11,13 @@ Eigen::Matrix4f projection_matrix(float x_min, float x_max, float y_min, float y auto const dy = y_max - y_min; auto const dz = z_max - z_min; - auto const pz = z_max * z_min; + auto const sz = z_max / dz; return (Eigen::Matrix4f() << - 2.0f * z_min / dx, 0.0f, -cx / dx, 0.0f, - 0.0f, 2.0f * z_min / dy, -cy / dy, 0.0f, - 0.0f, 0.0f, cz / dz, -2.0f * pz / dz, - 0.0f, 0.0f, 1.0f, 0.0f + 2.0f * z_min / dx, 0.0f, -cx / dx, 0.0f, + 0.0f, 2.0f * z_min / dy, -cy / dy, 0.0f, + 0.0f, 0.0f, sz, (1 - sz) * z_max, + 0.0f, 0.0f, 1.0f, 0.0f ).finished(); } diff --git a/src/core/utils.h b/src/core/utils.h index e67a621..2c20f50 100644 --- a/src/core/utils.h +++ b/src/core/utils.h @@ -65,10 +65,10 @@ public: assert((size == 0 && m_data == nullptr) || (size != 0 && m_data != nullptr)); } - Array(T* item) - : m_size(1) - , m_data(item) - {} + // Array(T* item) + // : m_size(1) + // , m_data(item) + // {} template Array(T (&array)[Size]) diff --git a/src/vk/Image.cpp b/src/vk/Image.cpp new file mode 100644 index 0000000..ced6b26 --- /dev/null +++ b/src/vk/Image.cpp @@ -0,0 +1,124 @@ +// Copyright 2022 Simon Boyé + +#include +#include + +#include + + +namespace vk { + + +Image::Image() noexcept { +} + +Image::Image(Context& context, VkImageCreateInfo create_info) + : Wrapper(context) +{ + assert(m_context); + + if(vkCreateImage( + context.device(), + &create_info, + nullptr, + &m_image + ) != VK_SUCCESS) + throw std::runtime_error("failed to create image"); +} + +Image::Image(Context& context, VkImageCreateInfo create_info, VkMemoryPropertyFlags memory_properties) + : Image(context, create_info) +{ + allocate_and_bind_memory(memory_properties); +} + +Image::Image(Image&& other) noexcept +{ + swap(other); +} + +Image::~Image() noexcept { + if(!is_null()) + destroy(); +} + + +Image& Image::operator=(Image&& other) noexcept { + swap(other); + if(other) + other.destroy(); + return *this; +} + + +VkMemoryRequirements Image::memory_requirements() const noexcept { + assert(!is_null()); + assert(*m_context); + + VkMemoryRequirements memory_requirements; + vkGetImageMemoryRequirements( + m_context->device(), + m_image, + &memory_requirements + ); + + return memory_requirements; +} + + +void Image::bind_memory(const MemoryBlock& memory_block, VkDeviceSize offset) { + assert(!is_null()); + assert(*m_context); + assert(memory_block); + + // m_memory = std::move(memory_block); + if(vkBindImageMemory( + m_context->device(), + m_image, + memory_block.device_memory(), + memory_block.offset() + offset + ) != VK_SUCCESS) + throw std::runtime_error("failed to bind image memory"); +} + +void Image::bind_memory(MemoryBlock&& memory_block) { + bind_memory(memory_block); + m_memory = std::move(memory_block); +} + +void Image::allocate_and_bind_memory(VkMemoryPropertyFlags memory_properties) { + assert(!is_null()); + assert(*m_context); + + const auto memory_requirements = this->memory_requirements(); + m_memory = m_context->allocator().allocate( + memory_requirements.size, + memory_requirements.memoryTypeBits, + memory_properties + ); + + bind_memory(m_memory); +} + + +void Image::destroy() noexcept { + assert(!is_null()); + assert(m_context); + + if(m_memory) { + m_memory.free(); + m_memory = MemoryBlock(); + } + + vkDestroyImage( + m_context->device(), + m_image, + nullptr + ); + + m_context = nullptr; + m_image = VK_NULL_HANDLE; +} + + +} diff --git a/src/vk/Image.h b/src/vk/Image.h new file mode 100644 index 0000000..4411747 --- /dev/null +++ b/src/vk/Image.h @@ -0,0 +1,66 @@ +// Copyright 2022 Simon Boyé +#pragma once + +#include +#include +#include + +#include + + +namespace vk { + + +class Image: public Wrapper { +public: + Image() noexcept; + Image(Context& context, VkImageCreateInfo create_info); + Image(Context& context, VkImageCreateInfo create_info, VkMemoryPropertyFlags memory_properties); + Image(const Image&) = default; + Image(Image&& other) noexcept; + ~Image() noexcept; + + Image& operator=(const Image&) = default; + Image& operator=(Image&& other) noexcept; + + explicit inline operator bool() const noexcept { + return !is_null(); + } + + inline bool is_null() const noexcept { + return m_image == VK_NULL_HANDLE; + } + + inline operator VkImage() noexcept { + return m_image; + } + + inline VkImage image() noexcept { + return m_image; + } + + VkMemoryRequirements memory_requirements() const noexcept; + + void bind_memory(const MemoryBlock& memory_block, VkDeviceSize offset=0); + void bind_memory(MemoryBlock&& memory_block); + void allocate_and_bind_memory(VkMemoryPropertyFlags memory_properties); + + inline void swap(Image& other) noexcept { + using std::swap; + Wrapper::swap(other); + swap(m_image, other.m_image); + } + + friend inline void swap(Image& image_0, Image& image_1) noexcept { + image_0.swap(image_1); + } + + void destroy() noexcept; + +private: + VkImage m_image = VK_NULL_HANDLE; + MemoryBlock m_memory; +}; + + +}