working on getting SDL2's testvulkan to run
authorJacob Lifshay <programmerjake@gmail.com>
Tue, 19 Sep 2017 01:52:33 +0000 (18:52 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Tue, 19 Sep 2017 01:52:33 +0000 (18:52 -0700)
15 files changed:
src/CMakeLists.txt
src/demo/demo.cpp
src/image/CMakeLists.txt [deleted file]
src/image/image.cpp [deleted file]
src/image/image.h [deleted file]
src/pipeline/CMakeLists.txt
src/pipeline/pipeline.cpp
src/pipeline/pipeline.h
src/util/circular_queue.h [new file with mode: 0644]
src/vulkan/api_objects.cpp
src/vulkan/api_objects.h
src/vulkan_icd/CMakeLists.txt
src/vulkan_icd/vulkan_icd.cpp
src/vulkan_icd/wsi.h
src/vulkan_icd/x11_wsi.cpp

index 20d202e0ffc70002fb052534ffc172bf17e8582d..324b6470ab1fcead677e2f948dce7faea16154e7 100644 (file)
@@ -22,7 +22,6 @@ cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 add_subdirectory(demo)
 add_subdirectory(generate_spirv_parser)
-add_subdirectory(image)
 add_subdirectory(json)
 add_subdirectory(llvm_wrapper)
 add_subdirectory(pipeline)
index f304c977bf149422e22a0bd25055f41670e20c10..022bfc87ba1d415158f25182631525bed5610983 100644 (file)
@@ -211,7 +211,7 @@ void dump_words(const std::vector<spirv::Word> &words)
     dump_words(words.data(), words.size());
 }
 
-pipeline::Shader_module_handle load_shader(const char *filename)
+std::unique_ptr<pipeline::Shader_module> load_shader(const char *filename)
 {
     std::cerr << "loading " << filename << std::endl;
     auto file = load_file(filename);
@@ -226,10 +226,10 @@ pipeline::Shader_module_handle load_shader(const char *filename)
         .codeSize = file->size() * sizeof(spirv::Word),
         .pCode = file->data(),
     };
-    return pipeline::Shader_module_handle::make(shader_module_create_info);
+    return pipeline::Shader_module::make(shader_module_create_info);
 }
 
-pipeline::Pipeline_layout_handle make_pipeline_layout()
+std::unique_ptr<pipeline::Pipeline_layout> make_pipeline_layout()
 {
     VkPipelineLayoutCreateInfo pipeline_layout_create_info = {
         .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
@@ -240,7 +240,7 @@ pipeline::Pipeline_layout_handle make_pipeline_layout()
         .pushConstantRangeCount = 0,
         .pPushConstantRanges = nullptr,
     };
-    return pipeline::Pipeline_layout_handle::make(pipeline_layout_create_info);
+    return pipeline::Pipeline_layout::make(pipeline_layout_create_info);
 }
 
 template <typename Integer_type>
@@ -653,7 +653,7 @@ int test_main(int argc, char **argv)
             .dependencyCount = 0,
             .pDependencies = nullptr,
         };
-        auto render_pass = pipeline::Render_pass_handle::make(render_pass_create_info);
+        auto render_pass = pipeline::Render_pass::make(render_pass_create_info);
         constexpr std::size_t stage_index_vertex = 0;
         constexpr std::size_t stage_index_fragment = stage_index_vertex + 1;
         constexpr std::size_t stage_count = stage_index_fragment + 1;
@@ -663,7 +663,7 @@ int test_main(int argc, char **argv)
             .pNext = nullptr,
             .flags = 0,
             .stage = VK_SHADER_STAGE_VERTEX_BIT,
-            .module = pipeline::to_handle(vertex_shader.get()),
+            .module = to_handle(vertex_shader.get()),
             .pName = "main",
             .pSpecializationInfo = nullptr,
         };
@@ -672,7 +672,7 @@ int test_main(int argc, char **argv)
             .pNext = nullptr,
             .flags = 0,
             .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
-            .module = pipeline::to_handle(fragment_shader.get()),
+            .module = to_handle(fragment_shader.get()),
             .pName = "main",
             .pSpecializationInfo = nullptr,
         };
@@ -817,8 +817,8 @@ int test_main(int argc, char **argv)
             .pDepthStencilState = nullptr,
             .pColorBlendState = &pipeline_color_blend_state_create_info,
             .pDynamicState = nullptr,
-            .layout = pipeline::to_handle(pipeline_layout.get()),
-            .renderPass = pipeline::to_handle(render_pass.get()),
+            .layout = to_handle(pipeline_layout.get()),
+            .renderPass = to_handle(render_pass.get()),
             .subpass = 0,
             .basePipelineHandle = VK_NULL_HANDLE,
             .basePipelineIndex = -1,
@@ -845,15 +845,15 @@ int test_main(int argc, char **argv)
             .pQueueFamilyIndices = nullptr,
             .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
         };
-        image::Image color_attachment(image::Image_descriptor(image_create_info),
-                                      image::allocate_memory_tag);
+        auto color_attachment = vulkan::Vulkan_image::create_with_memory(
+            vulkan::Vulkan_image_descriptor(image_create_info));
         VkClearColorValue clear_color;
         // set clear_color to opaque gray
         clear_color.float32[0] = 0.25;
         clear_color.float32[1] = 0.25;
         clear_color.float32[2] = 0.25;
         clear_color.float32[3] = 1;
-        color_attachment.clear(clear_color);
+        color_attachment->clear(clear_color);
         constexpr std::uint32_t vertex_start_index = 0;
         std::uint32_t vertex_end_index = vertexes.size();
         constexpr std::uint32_t instance_id = 0;
@@ -861,7 +861,7 @@ int test_main(int argc, char **argv)
             vertexes.data(),
         };
         graphics_pipeline->run(
-            vertex_start_index, vertex_end_index, instance_id, color_attachment, bindings);
+            vertex_start_index, vertex_end_index, instance_id, *color_attachment, bindings);
         typedef std::uint32_t Pixel_type;
         // check Pixel_type
         static_assert(std::is_void<util::void_t<decltype(graphics_pipeline->run_fragment_shader(
@@ -893,11 +893,11 @@ int test_main(int argc, char **argv)
             }
         };
         std::unique_ptr<SDL_Surface, Surface_deleter> surface(
-            SDL_CreateRGBSurfaceFrom(color_attachment.memory.get(),
+            SDL_CreateRGBSurfaceFrom(color_attachment->memory.get(),
                                      window_width,
                                      window_height,
                                      bits_per_pixel,
-                                     color_attachment.descriptor.get_memory_stride(),
+                                     color_attachment->descriptor.get_memory_stride(),
                                      rgba(0xFF, 0, 0, 0),
                                      rgba(0, 0xFF, 0, 0),
                                      rgba(0, 0, 0xFF, 0),
diff --git a/src/image/CMakeLists.txt b/src/image/CMakeLists.txt
deleted file mode 100644 (file)
index d8c7931..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2017 Jacob Lifshay
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
-set(sources image.cpp) 
-add_library(kazan_image STATIC ${sources})
-target_link_libraries(kazan_image kazan_util kazan_llvm_wrapper kazan_vulkan)
diff --git a/src/image/image.cpp b/src/image/image.cpp
deleted file mode 100644 (file)
index 7f59214..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2017 Jacob Lifshay
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#include "image.h"
diff --git a/src/image/image.h b/src/image/image.h
deleted file mode 100644 (file)
index 60657b9..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2017 Jacob Lifshay
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#ifndef IMAGE_IMAGE_H_
-#define IMAGE_IMAGE_H_
-
-#include "vulkan/vulkan.h"
-#include "vulkan/remove_xlib_macros.h"
-#include <memory>
-#include <cassert>
-#include <cstdint>
-#include "util/enum.h"
-
-namespace kazan
-{
-namespace image
-{
-struct Image_descriptor
-{
-    static constexpr VkImageCreateFlags supported_flags =
-        VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
-    VkImageCreateFlags flags;
-    VkImageType type;
-    VkFormat format;
-    VkExtent3D extent;
-    std::uint32_t mip_levels;
-    std::uint32_t array_layers;
-    static constexpr VkSampleCountFlags supported_samples = VK_SAMPLE_COUNT_1_BIT;
-    VkSampleCountFlagBits samples;
-    VkImageTiling tiling;
-    constexpr explicit Image_descriptor(const VkImageCreateInfo &image_create_info) noexcept
-        : flags(image_create_info.flags),
-          type(image_create_info.imageType),
-          format(image_create_info.format),
-          extent(image_create_info.extent),
-          mip_levels(image_create_info.mipLevels),
-          array_layers(image_create_info.arrayLayers),
-          samples(image_create_info.samples),
-          tiling(image_create_info.tiling)
-    {
-        assert(image_create_info.sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
-        assert((flags & ~supported_flags) == 0);
-        assert((samples & ~supported_samples) == 0);
-        assert(extent.width > 0);
-        assert(extent.height > 0);
-        assert(extent.depth > 0);
-
-#warning finish implementing Image
-        assert(type == VK_IMAGE_TYPE_2D && "unimplemented image type");
-        assert(extent.depth == 1);
-
-        assert(format == VK_FORMAT_B8G8R8A8_UNORM && "unimplemented image format");
-        assert(mip_levels == 1 && "mipmapping is unimplemented");
-        assert(array_layers == 1 && "array images are unimplemented");
-        assert(tiling == VK_IMAGE_TILING_LINEAR && "non-linear image tiling is unimplemented");
-        assert(image_create_info.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED
-               && "preinitialized images are unimplemented");
-    }
-    constexpr Image_descriptor(VkImageCreateFlags flags,
-                               VkImageType type,
-                               VkFormat format,
-                               VkExtent3D extent,
-                               std::uint32_t mip_levels,
-                               std::uint32_t array_layers,
-                               VkSampleCountFlagBits samples,
-                               VkImageTiling tiling) noexcept : flags(flags),
-                                                                type(type),
-                                                                format(format),
-                                                                extent(extent),
-                                                                mip_levels(mip_levels),
-                                                                array_layers(array_layers),
-                                                                samples(samples),
-                                                                tiling(tiling)
-    {
-    }
-    constexpr std::size_t get_memory_size() const noexcept
-    {
-#warning finish implementing Image
-        assert(samples == VK_SAMPLE_COUNT_1_BIT && "multisample images are unimplemented");
-        assert(extent.width > 0);
-        assert(extent.height > 0);
-        assert(extent.depth > 0);
-
-        assert(type == VK_IMAGE_TYPE_2D && "unimplemented image type");
-        assert(extent.depth == 1);
-
-        assert(format == VK_FORMAT_B8G8R8A8_UNORM && "unimplemented image format");
-        assert(mip_levels == 1 && "mipmapping is unimplemented");
-        assert(array_layers == 1 && "array images are unimplemented");
-        assert(tiling == VK_IMAGE_TILING_LINEAR && "non-linear image tiling is unimplemented");
-        std::size_t retval = sizeof(std::uint32_t);
-        retval *= extent.width;
-        retval *= extent.height;
-        return retval;
-    }
-    constexpr std::size_t get_memory_stride() const noexcept
-    {
-#warning finish implementing Image
-        assert(samples == VK_SAMPLE_COUNT_1_BIT && "multisample images are unimplemented");
-        assert(extent.width > 0);
-        assert(extent.height > 0);
-        assert(extent.depth > 0);
-
-        assert(type == VK_IMAGE_TYPE_2D && "unimplemented image type");
-        assert(extent.depth == 1);
-
-        assert(format == VK_FORMAT_B8G8R8A8_UNORM && "unimplemented image format");
-        assert(mip_levels == 1 && "mipmapping is unimplemented");
-        assert(array_layers == 1 && "array images are unimplemented");
-        assert(tiling == VK_IMAGE_TILING_LINEAR && "non-linear image tiling is unimplemented");
-        std::size_t retval = sizeof(std::uint32_t);
-        retval *= extent.width;
-        return retval;
-    }
-    constexpr std::size_t get_memory_pixel_size() const noexcept
-    {
-#warning finish implementing Image
-        assert(samples == VK_SAMPLE_COUNT_1_BIT && "multisample images are unimplemented");
-        assert(extent.width > 0);
-        assert(extent.height > 0);
-        assert(extent.depth > 0);
-
-        assert(type == VK_IMAGE_TYPE_2D && "unimplemented image type");
-        assert(extent.depth == 1);
-
-        assert(format == VK_FORMAT_B8G8R8A8_UNORM && "unimplemented image format");
-        assert(mip_levels == 1 && "mipmapping is unimplemented");
-        assert(array_layers == 1 && "array images are unimplemented");
-        assert(tiling == VK_IMAGE_TILING_LINEAR && "non-linear image tiling is unimplemented");
-        std::size_t retval = sizeof(std::uint32_t);
-        return retval;
-    }
-};
-
-struct Allocate_memory_tag
-{
-    explicit constexpr Allocate_memory_tag(int) noexcept
-    {
-    }
-};
-
-constexpr Allocate_memory_tag allocate_memory_tag{0};
-
-struct Image
-{
-    const Image_descriptor descriptor;
-    std::unique_ptr<unsigned char[]> memory;
-    Image(const Image_descriptor &descriptor,
-          std::unique_ptr<unsigned char[]> memory = nullptr) noexcept : descriptor(descriptor),
-                                                                        memory(std::move(memory))
-    {
-    }
-    Image(const Image_descriptor &descriptor, Allocate_memory_tag)
-        : descriptor(descriptor), memory(new unsigned char[descriptor.get_memory_size()])
-    {
-    }
-    void clear(VkClearColorValue color) noexcept
-    {
-        assert(memory);
-        assert(descriptor.samples == VK_SAMPLE_COUNT_1_BIT
-               && "multisample images are unimplemented");
-        assert(descriptor.extent.width > 0);
-        assert(descriptor.extent.height > 0);
-        assert(descriptor.extent.depth > 0);
-
-        assert(descriptor.type == VK_IMAGE_TYPE_2D && "unimplemented image type");
-        assert(descriptor.extent.depth == 1);
-
-        assert(descriptor.format == VK_FORMAT_B8G8R8A8_UNORM && "unimplemented image format");
-        assert(descriptor.mip_levels == 1 && "mipmapping is unimplemented");
-        assert(descriptor.array_layers == 1 && "array images are unimplemented");
-        assert(descriptor.tiling == VK_IMAGE_TILING_LINEAR
-               && "non-linear image tiling is unimplemented");
-        union
-        {
-            std::uint8_t bytes[4];
-            std::uint32_t u32;
-        } clear_color;
-        float r_float = color.float32[0];
-        float g_float = color.float32[1];
-        float b_float = color.float32[2];
-        float a_float = color.float32[3];
-        auto float_to_byte = [](float v) noexcept->std::uint8_t
-        {
-            if(!(v >= 0))
-                v = 0;
-            else if(v > 1)
-                v = 1;
-            union
-            {
-                std::uint32_t i;
-                float f;
-            } u;
-            static_assert(sizeof(std::uint32_t) == sizeof(float), "");
-            u.f = 0x100;
-            u.i--; // u.f = nextafter(u.f, -1)
-            v *= u.f;
-            return (int)v;
-        };
-        clear_color.bytes[0] = float_to_byte(b_float);
-        clear_color.bytes[1] = float_to_byte(g_float);
-        clear_color.bytes[2] = float_to_byte(r_float);
-        clear_color.bytes[3] = float_to_byte(a_float);
-        std::size_t pixel_count =
-            static_cast<std::size_t>(descriptor.extent.width) * descriptor.extent.height;
-        std::uint32_t *pixels = reinterpret_cast<std::uint32_t *>(memory.get());
-        for(std::size_t i = 0; i < pixel_count; i++)
-        {
-            pixels[i] = clear_color.u32;
-        }
-    }
-#warning finish implementing Image
-};
-}
-}
-
-#endif // IMAGE_IMAGE_H_
index 149f665659c4de06e0d65284d2a6aa76a35b1753..a394223362bd57b033c3186ce1a78dbaa8b2c6b6 100644 (file)
@@ -27,5 +27,4 @@ target_link_libraries(kazan_pipeline kazan_spirv_to_llvm
                                      kazan_util
                                      kazan_spirv
                                      kazan_llvm_wrapper
-                                     kazan_vulkan
-                                     kazan_image)
+                                     kazan_vulkan)
index a0b97718fc374b55404eeb2665e7c1a6a4588871..dda74915e37a16e24c4fda8672cbc3a133d41c30 100644 (file)
@@ -36,49 +36,6 @@ namespace kazan
 {
 namespace pipeline
 {
-class Pipeline_cache
-{
-};
-
-void Api_object_deleter<Pipeline_cache>::operator()(Pipeline_cache *pipeline_cache) const noexcept
-{
-    delete pipeline_cache;
-}
-
-class Render_pass
-{
-};
-
-void Api_object_deleter<Render_pass>::operator()(Render_pass *render_pass) const noexcept
-{
-    delete render_pass;
-}
-
-template <>
-Render_pass_handle Render_pass_handle::make(const VkRenderPassCreateInfo &render_pass_create_info)
-{
-#warning finish implementing Render_pass_handle::make
-    return Render_pass_handle(new Render_pass());
-}
-
-class Pipeline_layout
-{
-};
-
-void Api_object_deleter<Pipeline_layout>::operator()(Pipeline_layout *pipeline_layout) const
-    noexcept
-{
-    delete pipeline_layout;
-}
-
-template <>
-Pipeline_layout_handle Pipeline_layout_handle::make(
-    const VkPipelineLayoutCreateInfo &pipeline_layout_create_info)
-{
-#warning finish implementing Pipeline_layout_handle::make
-    return Pipeline_layout_handle(new Pipeline_layout());
-}
-
 llvm_wrapper::Module Pipeline::optimize_module(llvm_wrapper::Module module,
                                                ::LLVMTargetMachineRef target_machine)
 {
@@ -412,14 +369,14 @@ void Graphics_pipeline::dump_vertex_shader_output_struct(const void *output_stru
 void Graphics_pipeline::run(std::uint32_t vertex_start_index,
                             std::uint32_t vertex_end_index,
                             std::uint32_t instance_id,
-                            const image::Image &color_attachment,
+                            const vulkan::Vulkan_image &color_attachment,
                             void *const *bindings)
 {
     typedef std::uint32_t Pixel_type;
     assert(color_attachment.descriptor.tiling == VK_IMAGE_TILING_LINEAR);
     std::size_t color_attachment_stride = color_attachment.descriptor.get_memory_stride();
     std::size_t color_attachment_pixel_size = color_attachment.descriptor.get_memory_pixel_size();
-    unsigned char *color_attachment_memory = color_attachment.memory.get();
+    void *color_attachment_memory = color_attachment.memory.get();
     float viewport_x_scale, viewport_x_offset, viewport_y_scale, viewport_y_offset,
         viewport_z_scale, viewport_z_offset;
     {
@@ -866,7 +823,7 @@ void Graphics_pipeline::run(std::uint32_t vertex_start_index,
                     if(inside)
                     {
                         auto *pixel = reinterpret_cast<Pixel_type *>(
-                            color_attachment_memory
+                            static_cast<unsigned char *>(color_attachment_memory)
                             + (static_cast<std::size_t>(x) * color_attachment_pixel_size
                                + static_cast<std::size_t>(y) * color_attachment_stride));
                         fs(pixel);
@@ -881,9 +838,9 @@ std::unique_ptr<Graphics_pipeline> Graphics_pipeline::make(
     Pipeline_cache *pipeline_cache, const VkGraphicsPipelineCreateInfo &create_info)
 {
     assert(create_info.sType == VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO);
-    auto *render_pass = Render_pass_handle::from_handle(create_info.renderPass);
+    auto *render_pass = Render_pass::from_handle(create_info.renderPass);
     assert(render_pass);
-    auto *pipeline_layout = Pipeline_layout_handle::from_handle(create_info.layout);
+    auto *pipeline_layout = Pipeline_layout::from_handle(create_info.layout);
     assert(pipeline_layout);
     if(create_info.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT)
     {
@@ -909,7 +866,7 @@ std::unique_ptr<Graphics_pipeline> Graphics_pipeline::make(
             std::get<1>(found_shader_stages.insert(execution_model));
         if(!added_to_found_shader_stages)
             throw std::runtime_error("duplicate shader stage");
-        auto *shader_module = Shader_module_handle::from_handle(stage_info.module);
+        auto *shader_module = Shader_module::from_handle(stage_info.module);
         assert(shader_module);
         {
             spirv::Dump_callbacks dump_callbacks;
index b3554569d5b7672c35de921db9d5ba8fda671cba..fc47b7af688556f85707b4667463f8c82bdfa7cb 100644 (file)
 #include "vulkan/vulkan.h"
 #include "vulkan/remove_xlib_macros.h"
 #include "spirv/spirv.h"
-#include "image/image.h"
+#include "vulkan/api_objects.h"
 
 namespace kazan
 {
 namespace pipeline
 {
-template <typename T>
-struct Api_object_deleter
+class Pipeline_cache : public vulkan::Vulkan_nondispatchable_object<Pipeline_cache, VkPipelineCache>
 {
-    void operator()(T *) const noexcept = delete;
-    typedef void Vulkan_handle;
-    typedef void Create_info;
-};
-
-template <typename Object_>
-struct Api_object_handle : public std::unique_ptr<Object_, Api_object_deleter<Object_>>
-{
-    typedef typename Api_object_deleter<Object_>::Vulkan_handle Vulkan_handle;
-    typedef typename Api_object_deleter<Object_>::Create_info Create_info;
-    typedef Object_ Object;
-    using std::unique_ptr<Object_, Api_object_deleter<Object_>>::unique_ptr;
-    static Object *from_handle(Vulkan_handle vulkan_handle) noexcept
-    {
-        return reinterpret_cast<Object *>(vulkan_handle);
-    }
-    static Api_object_handle move_from_handle(Vulkan_handle vulkan_handle) noexcept
+#warning finish implementing Pipeline_cache
+public:
+    static std::unique_ptr<Pipeline_cache> make(
+        const VkPipelineCacheCreateInfo &pipeline_cache_create_info)
     {
-        return Api_object_handle(from_handle(vulkan_handle));
+#warning finish implementing Pipeline_cache::make
+        return std::make_unique<Pipeline_cache>();
     }
-    static Api_object_handle make(const Create_info &create_info);
 };
 
-template <typename Object>
-inline typename Api_object_deleter<Object>::Vulkan_handle to_handle(Object *object) noexcept
-{
-    static_assert(!std::is_void<typename Api_object_deleter<Object>::Vulkan_handle>::value, "");
-    return reinterpret_cast<typename Api_object_deleter<Object>::Vulkan_handle>(object);
-}
-
-template <typename Object>
-inline typename Api_object_deleter<Object>::Vulkan_handle move_to_handle(
-    Api_object_handle<Object> object) noexcept
-{
-    return to_handle(object.release());
-}
-
-class Pipeline_cache;
-
-template <>
-struct Api_object_deleter<Pipeline_cache>
+class Render_pass : public vulkan::Vulkan_nondispatchable_object<Render_pass, VkRenderPass>
 {
-    void operator()(Pipeline_cache *pipeline_cache) const noexcept;
-    typedef VkPipelineCache Vulkan_handle;
-    typedef VkPipelineCacheCreateInfo Create_info;
-};
-
-typedef Api_object_handle<Pipeline_cache> Pipeline_cache_handle;
-
-class Render_pass;
-
-template <>
-struct Api_object_deleter<Render_pass>
-{
-    void operator()(Render_pass *render_pass) const noexcept;
-    typedef VkRenderPass Vulkan_handle;
-    typedef VkRenderPassCreateInfo Create_info;
+#warning finish implementing Render_pass
+public:
+    static std::unique_ptr<Render_pass> make(const VkRenderPassCreateInfo &render_pass_create_info)
+    {
+#warning finish implementing Render_pass::make
+        return std::make_unique<Render_pass>();
+    }
 };
 
-typedef Api_object_handle<Render_pass> Render_pass_handle;
-
-class Pipeline_layout;
-
-template <>
-struct Api_object_deleter<Pipeline_layout>
+class Pipeline_layout
+    : public vulkan::Vulkan_nondispatchable_object<Pipeline_layout, VkPipelineLayout>
 {
-    void operator()(Pipeline_layout *pipeline_layout) const noexcept;
-    typedef VkPipelineLayout Vulkan_handle;
-    typedef VkPipelineLayoutCreateInfo Create_info;
+#warning finish implementing Pipeline_layout
+public:
+    static std::unique_ptr<Pipeline_layout> make(
+        const VkPipelineLayoutCreateInfo &pipeline_layout_create_info)
+    {
+#warning finish implementing Pipeline_layout::make
+        return std::make_unique<Pipeline_layout>();
+    }
 };
 
-typedef Api_object_handle<Pipeline_layout> Pipeline_layout_handle;
-
-struct Shader_module
+struct Shader_module : public vulkan::Vulkan_nondispatchable_object<Shader_module, VkShaderModule>
 {
     std::shared_ptr<unsigned char> bytes;
     std::size_t byte_count;
@@ -132,38 +92,23 @@ struct Shader_module
         assert(byte_count % sizeof(spirv::Word) == 0);
         return byte_count / sizeof(spirv::Word);
     }
-};
-
-template <>
-struct Api_object_deleter<Shader_module>
-{
-    void operator()(Shader_module *shader_module) const noexcept
+    static std::unique_ptr<Shader_module> make(const VkShaderModuleCreateInfo &create_info)
     {
-        delete shader_module;
+        struct Code_deleter
+        {
+            void operator()(unsigned char *bytes) const noexcept
+            {
+                delete[] bytes;
+            }
+        };
+        auto bytes =
+            std::shared_ptr<unsigned char>(new unsigned char[create_info.codeSize], Code_deleter{});
+        std::memcpy(bytes.get(), create_info.pCode, create_info.codeSize);
+        return std::make_unique<Shader_module>(std::move(bytes), create_info.codeSize);
     }
-    typedef VkShaderModule Vulkan_handle;
-    typedef VkShaderModuleCreateInfo Create_info;
 };
 
-typedef Api_object_handle<Shader_module> Shader_module_handle;
-
-template <>
-inline Shader_module_handle Shader_module_handle::make(const VkShaderModuleCreateInfo &create_info)
-{
-    struct Code_deleter
-    {
-        void operator()(unsigned char *bytes) const noexcept
-        {
-            delete[] bytes;
-        }
-    };
-    auto bytes =
-        std::shared_ptr<unsigned char>(new unsigned char[create_info.codeSize], Code_deleter{});
-    std::memcpy(bytes.get(), create_info.pCode, create_info.codeSize);
-    return Shader_module_handle(new Shader_module(std::move(bytes), create_info.codeSize));
-}
-
-class Pipeline
+class Pipeline : public vulkan::Vulkan_nondispatchable_object<Pipeline, VkPipeline>
 {
     Pipeline(const Pipeline &) = delete;
     Pipeline &operator=(const Pipeline &) = delete;
@@ -187,16 +132,6 @@ protected:
                                                 ::LLVMTargetMachineRef target_machine);
 };
 
-inline VkPipeline to_handle(Pipeline *pipeline) noexcept
-{
-    return reinterpret_cast<VkPipeline>(pipeline);
-}
-
-inline VkPipeline move_to_handle(std::unique_ptr<Pipeline> pipeline) noexcept
-{
-    return to_handle(pipeline.release());
-}
-
 class Graphics_pipeline final : public Pipeline
 {
 private:
@@ -233,7 +168,7 @@ public:
     void run(std::uint32_t vertex_start_index,
              std::uint32_t vertex_end_index,
              std::uint32_t instance_id,
-             const image::Image &color_attachment,
+             const vulkan::Vulkan_image &color_attachment,
              void *const *bindings);
     static std::unique_ptr<Graphics_pipeline> make(Pipeline_cache *pipeline_cache,
                                                    const VkGraphicsPipelineCreateInfo &create_info);
@@ -275,16 +210,6 @@ private:
     VkViewport viewport;
     VkRect2D scissor_rect;
 };
-
-inline VkPipeline to_handle(Graphics_pipeline *pipeline) noexcept
-{
-    return to_handle(static_cast<Pipeline *>(pipeline));
-}
-
-inline VkPipeline move_to_handle(std::unique_ptr<Graphics_pipeline> pipeline) noexcept
-{
-    return to_handle(pipeline.release());
-}
 }
 }
 
diff --git a/src/util/circular_queue.h b/src/util/circular_queue.h
new file mode 100644 (file)
index 0000000..d3b8119
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#ifndef UTIL_CIRCULAR_QUEUE_H_
+#define UTIL_CIRCULAR_QUEUE_H_
+
+#include <new>
+#include <utility>
+#include <type_traits>
+#include <cassert>
+
+namespace kazan
+{
+namespace util
+{
+template <typename T, std::size_t Capacity>
+class Static_circular_deque
+{
+    static_assert(Capacity != 0, "");
+    static_assert(std::is_nothrow_destructible<T>::value, "");
+
+private:
+    union
+    {
+        T objects[Capacity];
+        alignas(T) char bytes[sizeof(T) * Capacity];
+    };
+    std::size_t front_index = 0;
+    std::size_t back_index = Capacity - 1;
+    std::size_t enqueued_count = 0;
+    static constexpr std::size_t prev_index(std::size_t index) noexcept
+    {
+        return index == 0 ? Capacity - 1 : index - 1;
+    }
+    static constexpr std::size_t next_index(std::size_t index) noexcept
+    {
+        return index == Capacity - 1 ? 0 : index + 1;
+    }
+
+public:
+    constexpr Static_circular_deque() noexcept : bytes{}
+    {
+    }
+    ~Static_circular_deque()
+    {
+        while(!empty())
+            pop_back();
+    }
+    Static_circular_deque(Static_circular_deque &&rt) noexcept(
+        std::is_nothrow_move_constructible<T>::value)
+        : Static_circular_deque()
+    {
+        try
+        {
+            while(!rt.empty())
+            {
+                push_back(std::move(rt.front()));
+                rt.pop_front();
+            }
+        }
+        catch(...)
+        {
+            while(!empty())
+                pop_back();
+            throw;
+        }
+    }
+    Static_circular_deque &operator=(Static_circular_deque &&rt) noexcept(
+        std::is_nothrow_move_constructible<T>::value)
+    {
+        if(this == &rt)
+            return *this;
+        while(!empty())
+            pop_back();
+        while(!rt.empty())
+        {
+            push_back(std::move(rt.front()));
+            rt.pop_front();
+        }
+        return *this;
+    }
+    std::size_t size() const noexcept
+    {
+        return enqueued_count;
+    }
+    std::size_t capacity() const noexcept
+    {
+        return Capacity;
+    }
+    bool empty() const noexcept
+    {
+        return enqueued_count == 0;
+    }
+    bool full() const noexcept
+    {
+        return enqueued_count == Capacity;
+    }
+    T &front() noexcept
+    {
+        assert(!empty());
+        return objects[front_index];
+    }
+    T &back() noexcept
+    {
+        assert(!empty());
+        return objects[back_index];
+    }
+    void pop_back() noexcept
+    {
+        assert(!empty());
+        std::size_t new_index = prev_index(back_index);
+        objects[back_index].~T();
+        enqueued_count--;
+        back_index = new_index;
+    }
+    void pop_front() noexcept
+    {
+        assert(!empty());
+        std::size_t new_index = next_index(front_index);
+        objects[front_index].~T();
+        enqueued_count--;
+        front_index = new_index;
+    }
+    template <typename... Args>
+    void emplace_back(Args &&... args) noexcept(std::is_nothrow_constructible<T, Args &&...>::value)
+    {
+        assert(!full());
+        std::size_t new_index = next_index(back_index);
+        ::new(std::addressof(objects[new_index])) T(std::forward<Args>(args)...);
+        enqueued_count++;
+        back_index = new_index;
+    }
+    template <typename... Args>
+    void emplace_front(Args &&... args) noexcept(std::is_nothrow_constructible<T, Args &&...>::value)
+    {
+        assert(!full());
+        std::size_t new_index = prev_index(front_index);
+        ::new(std::addressof(objects[new_index])) T(std::forward<Args>(args)...);
+        enqueued_count++;
+        front_index = new_index;
+    }
+    void push_back(const T &new_value) noexcept(std::is_nothrow_copy_constructible<T>::value)
+    {
+        emplace_back(new_value);
+    }
+    void push_back(T &&new_value) noexcept(std::is_nothrow_move_constructible<T>::value)
+    {
+        emplace_back(std::move(new_value));
+    }
+    void push_front(const T &new_value) noexcept(std::is_nothrow_copy_constructible<T>::value)
+    {
+        emplace_front(new_value);
+    }
+    void push_front(T &&new_value) noexcept(std::is_nothrow_move_constructible<T>::value)
+    {
+        emplace_front(std::move(new_value));
+    }
+};
+}
+}
+
+#endif
+
index 6591b3dd22df9ae85c3968ea7a6872e4c6910581..95497959fd4efc879847f568ce492f36ee1721e9 100644 (file)
@@ -459,25 +459,125 @@ std::unique_ptr<Vulkan_fence> Vulkan_fence::create(Vulkan_device &device,
     return std::make_unique<Vulkan_fence>(create_info.flags);
 }
 
+void Vulkan_image::clear(VkClearColorValue color) noexcept
+{
+    assert(memory);
+    assert(descriptor.samples == VK_SAMPLE_COUNT_1_BIT && "multisample images are unimplemented");
+    assert(descriptor.extent.width > 0);
+    assert(descriptor.extent.height > 0);
+    assert(descriptor.extent.depth > 0);
+
+    assert(descriptor.type == VK_IMAGE_TYPE_2D && "unimplemented image type");
+    assert(descriptor.extent.depth == 1);
+
+    assert(descriptor.format == VK_FORMAT_B8G8R8A8_UNORM && "unimplemented image format");
+    assert(descriptor.mip_levels == 1 && "mipmapping is unimplemented");
+    assert(descriptor.array_layers == 1 && "array images are unimplemented");
+    assert(descriptor.tiling == VK_IMAGE_TILING_LINEAR
+           && "non-linear image tiling is unimplemented");
+    union
+    {
+        std::uint8_t bytes[4];
+        std::uint32_t u32;
+    } clear_color;
+    float r_float = color.float32[0];
+    float g_float = color.float32[1];
+    float b_float = color.float32[2];
+    float a_float = color.float32[3];
+    auto float_to_byte = [](float v) noexcept->std::uint8_t
+    {
+        if(!(v >= 0))
+            v = 0;
+        else if(v > 1)
+            v = 1;
+        union
+        {
+            std::uint32_t i;
+            float f;
+        } u;
+        static_assert(sizeof(std::uint32_t) == sizeof(float), "");
+        u.f = 0x100;
+        u.i--; // u.f = nextafter(u.f, -1)
+        v *= u.f;
+        return (int)v;
+    };
+    clear_color.bytes[0] = float_to_byte(b_float);
+    clear_color.bytes[1] = float_to_byte(g_float);
+    clear_color.bytes[2] = float_to_byte(r_float);
+    clear_color.bytes[3] = float_to_byte(a_float);
+    std::size_t pixel_count =
+        static_cast<std::size_t>(descriptor.extent.width) * descriptor.extent.height;
+    std::uint32_t *pixels = static_cast<std::uint32_t *>(memory.get());
+    for(std::size_t i = 0; i < pixel_count; i++)
+    {
+        pixels[i] = clear_color.u32;
+    }
+}
+
 std::unique_ptr<Vulkan_image> Vulkan_image::create(Vulkan_device &device,
                                                    const VkImageCreateInfo &create_info)
 {
 #warning finish implementing Vulkan_image::create
-    return std::make_unique<Vulkan_image>();
+    return std::make_unique<Vulkan_image>(Vulkan_image_descriptor(create_info));
 }
 
+void Vulkan_command_buffer::Command::on_record_end(Vulkan_command_buffer &command_buffer)
+{
+    static_cast<void>(command_buffer);
+}
+
+
 Vulkan_command_buffer::Vulkan_command_buffer(
     std::list<std::unique_ptr<Vulkan_command_buffer>>::iterator iter,
     Vulkan_command_pool &command_pool,
     Vulkan_device &device) noexcept : iter(iter),
                                       command_pool(command_pool),
-                                      device(device)
+                                      device(device),
+                                      commands(),
+                                      state(Command_buffer_state::Initial)
+{
+}
+
+void Vulkan_command_buffer::reset(VkCommandBufferResetFlags flags)
+{
+    commands.clear();
+    state = Command_buffer_state::Initial;
+}
+
+void Vulkan_command_buffer::begin(const VkCommandBufferBeginInfo &begin_info)
+{
+    commands.clear();
+    state = Command_buffer_state::Recording;
+}
+
+VkResult Vulkan_command_buffer::end() noexcept
 {
+    if(state == Command_buffer_state::Out_of_memory)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    assert(state == Command_buffer_state::Recording);
+    try
+    {
+        for(auto &command : commands)
+        {
+            assert(command);
+            command->on_record_end(*this);
+        }
+    }
+    catch(std::bad_alloc &)
+    {
+        state = Command_buffer_state::Out_of_memory;
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+    state = Command_buffer_state::Executable;
+    return VK_SUCCESS;
 }
 
-void Vulkan_command_buffer::reset(VkCommandPoolResetFlags flags)
+void Vulkan_command_buffer::run() const noexcept
 {
-#warning finish implementing Vulkan_command_buffer::reset
+    assert(state == Command_buffer_state::Executable);
+    Running_state running_state(*this);
+    for(auto &command : commands)
+        command->run(running_state);
 }
 
 void Vulkan_command_pool::allocate_multiple(Vulkan_device &device,
index c35ed35c838bb1b2bd064a53512704ada87fe344..68b949fdc005a93c867d82b6e31a366b1320f823 100644 (file)
@@ -1570,6 +1570,9 @@ struct Vulkan_device : public Vulkan_dispatchable_object<Vulkan_device, VkDevice
 
 struct Vulkan_semaphore : public Vulkan_nondispatchable_object<Vulkan_semaphore, VkSemaphore>
 {
+    void signal() // empty function for if semaphores are needed later
+    {
+    }
     static std::unique_ptr<Vulkan_semaphore> create(Vulkan_device &device,
                                                     const VkSemaphoreCreateInfo &create_info);
 };
@@ -1655,8 +1658,153 @@ public:
                                                 const VkFenceCreateInfo &create_info);
 };
 
+struct Vulkan_image_descriptor
+{
+    static constexpr VkImageCreateFlags supported_flags =
+        VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
+    VkImageCreateFlags flags;
+    VkImageType type;
+    VkFormat format;
+    VkExtent3D extent;
+    std::uint32_t mip_levels;
+    std::uint32_t array_layers;
+    static constexpr VkSampleCountFlags supported_samples = VK_SAMPLE_COUNT_1_BIT;
+    VkSampleCountFlagBits samples;
+    VkImageTiling tiling;
+    constexpr Vulkan_image_descriptor() noexcept : flags(),
+                                                   type(),
+                                                   format(),
+                                                   extent(),
+                                                   mip_levels(),
+                                                   array_layers(),
+                                                   samples(),
+                                                   tiling()
+    {
+    }
+    constexpr explicit Vulkan_image_descriptor(const VkImageCreateInfo &image_create_info) noexcept
+        : flags(image_create_info.flags),
+          type(image_create_info.imageType),
+          format(image_create_info.format),
+          extent(image_create_info.extent),
+          mip_levels(image_create_info.mipLevels),
+          array_layers(image_create_info.arrayLayers),
+          samples(image_create_info.samples),
+          tiling(image_create_info.tiling)
+    {
+        assert(image_create_info.sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
+        assert((flags & ~supported_flags) == 0);
+        assert((samples & ~supported_samples) == 0);
+        assert(extent.width > 0);
+        assert(extent.height > 0);
+        assert(extent.depth > 0);
+
+#warning finish implementing Image
+        assert(type == VK_IMAGE_TYPE_2D && "unimplemented image type");
+        assert(extent.depth == 1);
+
+        assert(format == VK_FORMAT_B8G8R8A8_UNORM && "unimplemented image format");
+        assert(mip_levels == 1 && "mipmapping is unimplemented");
+        assert(array_layers == 1 && "array images are unimplemented");
+        assert(tiling == VK_IMAGE_TILING_LINEAR && "non-linear image tiling is unimplemented");
+        assert(image_create_info.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED
+               && "preinitialized images are unimplemented");
+    }
+    constexpr Vulkan_image_descriptor(VkImageCreateFlags flags,
+                                      VkImageType type,
+                                      VkFormat format,
+                                      VkExtent3D extent,
+                                      std::uint32_t mip_levels,
+                                      std::uint32_t array_layers,
+                                      VkSampleCountFlagBits samples,
+                                      VkImageTiling tiling) noexcept : flags(flags),
+                                                                       type(type),
+                                                                       format(format),
+                                                                       extent(extent),
+                                                                       mip_levels(mip_levels),
+                                                                       array_layers(array_layers),
+                                                                       samples(samples),
+                                                                       tiling(tiling)
+    {
+    }
+    constexpr std::size_t get_memory_size() const noexcept
+    {
+#warning finish implementing Image
+        assert(samples == VK_SAMPLE_COUNT_1_BIT && "multisample images are unimplemented");
+        assert(extent.width > 0);
+        assert(extent.height > 0);
+        assert(extent.depth > 0);
+
+        assert(type == VK_IMAGE_TYPE_2D && "unimplemented image type");
+        assert(extent.depth == 1);
+
+        assert(format == VK_FORMAT_B8G8R8A8_UNORM && "unimplemented image format");
+        assert(mip_levels == 1 && "mipmapping is unimplemented");
+        assert(array_layers == 1 && "array images are unimplemented");
+        assert(tiling == VK_IMAGE_TILING_LINEAR && "non-linear image tiling is unimplemented");
+        std::size_t retval = sizeof(std::uint32_t);
+        retval *= extent.width;
+        retval *= extent.height;
+        return retval;
+    }
+    constexpr std::size_t get_memory_stride() const noexcept
+    {
+#warning finish implementing Image
+        assert(samples == VK_SAMPLE_COUNT_1_BIT && "multisample images are unimplemented");
+        assert(extent.width > 0);
+        assert(extent.height > 0);
+        assert(extent.depth > 0);
+
+        assert(type == VK_IMAGE_TYPE_2D && "unimplemented image type");
+        assert(extent.depth == 1);
+
+        assert(format == VK_FORMAT_B8G8R8A8_UNORM && "unimplemented image format");
+        assert(mip_levels == 1 && "mipmapping is unimplemented");
+        assert(array_layers == 1 && "array images are unimplemented");
+        assert(tiling == VK_IMAGE_TILING_LINEAR && "non-linear image tiling is unimplemented");
+        std::size_t retval = sizeof(std::uint32_t);
+        retval *= extent.width;
+        return retval;
+    }
+    constexpr std::size_t get_memory_pixel_size() const noexcept
+    {
+#warning finish implementing Image
+        assert(samples == VK_SAMPLE_COUNT_1_BIT && "multisample images are unimplemented");
+        assert(extent.width > 0);
+        assert(extent.height > 0);
+        assert(extent.depth > 0);
+
+        assert(type == VK_IMAGE_TYPE_2D && "unimplemented image type");
+        assert(extent.depth == 1);
+
+        assert(format == VK_FORMAT_B8G8R8A8_UNORM && "unimplemented image format");
+        assert(mip_levels == 1 && "mipmapping is unimplemented");
+        assert(array_layers == 1 && "array images are unimplemented");
+        assert(tiling == VK_IMAGE_TILING_LINEAR && "non-linear image tiling is unimplemented");
+        std::size_t retval = sizeof(std::uint32_t);
+        return retval;
+    }
+};
+
 struct Vulkan_image : public Vulkan_nondispatchable_object<Vulkan_image, VkImage>
 {
+    const Vulkan_image_descriptor descriptor;
+    std::shared_ptr<void> memory;
+    Vulkan_image(const Vulkan_image_descriptor &descriptor,
+                 std::shared_ptr<void> memory = nullptr) noexcept : descriptor(descriptor),
+                                                                    memory(std::move(memory))
+    {
+    }
+    static std::unique_ptr<Vulkan_image> create_with_memory(
+        const Vulkan_image_descriptor &descriptor)
+    {
+        std::shared_ptr<unsigned char> memory(new unsigned char[descriptor.get_memory_size()],
+                                              [](unsigned char *p) noexcept
+                                              {
+                                                  delete[] p;
+                                              });
+        return std::make_unique<Vulkan_image>(descriptor, std::move(memory));
+    }
+    void clear(VkClearColorValue color) noexcept;
     virtual ~Vulkan_image() = default;
 #warning finish implementing Vulkan_image
     static std::unique_ptr<Vulkan_image> create(Vulkan_device &device,
@@ -1668,14 +1816,58 @@ struct Vulkan_command_pool;
 struct Vulkan_command_buffer
     : public Vulkan_dispatchable_object<Vulkan_command_buffer, VkCommandBuffer>
 {
+    struct Running_state
+    {
+        const Vulkan_command_buffer &command_buffer;
+        Vulkan_device &device;
+        explicit Running_state(const Vulkan_command_buffer &command_buffer) noexcept
+            : command_buffer(command_buffer),
+              device(command_buffer.device)
+        {
+        }
+#warning finish implementing Vulkan_command_buffer
+    };
+    class Command
+    {
+    public:
+        virtual ~Command() = default;
+        virtual void run(Running_state &state) noexcept = 0;
+        virtual void on_record_end(Vulkan_command_buffer &command_buffer);
+    };
+    enum class Command_buffer_state
+    {
+        Initial,
+        Recording,
+        Executable,
+        Out_of_memory,
+    };
     std::list<std::unique_ptr<Vulkan_command_buffer>>::iterator iter;
     Vulkan_command_pool &command_pool;
     Vulkan_device &device;
+    std::vector<std::unique_ptr<Command>> commands;
+    Command_buffer_state state;
     Vulkan_command_buffer(std::list<std::unique_ptr<Vulkan_command_buffer>>::iterator iter,
                           Vulkan_command_pool &command_pool,
                           Vulkan_device &device) noexcept;
-    void reset(VkCommandPoolResetFlags flags);
-#warning finish implementing Vulkan_command_buffer
+    void reset(VkCommandBufferResetFlags flags);
+    void begin(const VkCommandBufferBeginInfo &begin_info);
+    template <typename Fn>
+    void record_command_and_keep_errors(Fn fn) noexcept
+    {
+        if(state == Command_buffer_state::Out_of_memory)
+            return;
+        assert(state == Command_buffer_state::Recording);
+        try
+        {
+            fn();
+        }
+        catch(std::bad_alloc &)
+        {
+            state = Command_buffer_state::Out_of_memory;
+        }
+    }
+    VkResult end() noexcept;
+    void run() const noexcept;
 };
 
 struct Vulkan_command_pool
@@ -1684,8 +1876,12 @@ struct Vulkan_command_pool
     std::list<std::unique_ptr<Vulkan_command_buffer>> command_buffers;
     void reset(VkCommandPoolResetFlags flags)
     {
+        VkCommandBufferResetFlags buffer_flags = 0;
+        assert((flags & ~(VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT)) == 0);
+        if(flags & VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT)
+            buffer_flags |= VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT;
         for(auto &command_buffer : command_buffers)
-            command_buffer->reset(flags);
+            command_buffer->reset(buffer_flags);
     }
     void allocate_multiple(Vulkan_device &device,
                            const VkCommandBufferAllocateInfo &allocate_info,
index 8b7dd20e3b7e3c41c60d4f4a5aff526503155be9..1f3008177c5cbcca8ea8f3f2efc5201138103a2a 100644 (file)
@@ -24,6 +24,7 @@ set(sources vulkan_icd.cpp
             x11_wsi.cpp)
 add_library(kazan_vulkan_icd MODULE ${sources})
 target_link_libraries(kazan_vulkan_icd
+                      kazan_pipeline
                       kazan_vulkan
                       kazan_util)
 file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/kazan_vulkan_icd.json INPUT ${CMAKE_CURRENT_SOURCE_DIR}/kazan_vulkan_icd.json.in)
index aa6363b0b18e88f70a588743f03ffb76962948af..df682ce69c4ce8eaf4cc3651a940b6d6aa6f1b29 100644 (file)
@@ -24,7 +24,9 @@
 #include "util/string_view.h"
 #include <initializer_list>
 #include <iostream>
+#include <atomic>
 #include "wsi.h"
+#include "pipeline/pipeline.h"
 
 using namespace kazan;
 
@@ -983,23 +985,35 @@ extern "C" VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers(VkDevice device,
 }
 
 extern "C" VKAPI_ATTR VkResult VKAPI_CALL
-    vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo)
+    vkBeginCommandBuffer(VkCommandBuffer command_buffer, const VkCommandBufferBeginInfo *begin_info)
 {
-#warning finish implementing vkBeginCommandBuffer
-    assert(!"vkBeginCommandBuffer is not implemented");
+    assert(command_buffer);
+    assert(begin_info);
+    assert(begin_info->sType == VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO);
+    return vulkan_icd::catch_exceptions_and_return_result(
+        [&]()
+        {
+            vulkan::Vulkan_command_buffer::from_handle(command_buffer)->begin(*begin_info);
+            return VK_SUCCESS;
+        });
 }
 
-extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(VkCommandBuffer commandBuffer)
+extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(VkCommandBuffer command_buffer)
 {
-#warning finish implementing vkEndCommandBuffer
-    assert(!"vkEndCommandBuffer is not implemented");
+    assert(command_buffer);
+    return vulkan::Vulkan_command_buffer::from_handle(command_buffer)->end();
 }
 
-extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer(VkCommandBuffer commandBuffer,
+extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandBuffer(VkCommandBuffer command_buffer,
                                                                VkCommandBufferResetFlags flags)
 {
-#warning finish implementing vkResetCommandBuffer
-    assert(!"vkResetCommandBuffer is not implemented");
+    assert(command_buffer);
+    return vulkan_icd::catch_exceptions_and_return_result(
+        [&]()
+        {
+            vulkan::Vulkan_command_buffer::from_handle(command_buffer)->reset(flags);
+            return VK_SUCCESS;
+        });
 }
 
 extern "C" VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline(VkCommandBuffer commandBuffer,
@@ -1251,15 +1265,61 @@ extern "C" VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer(VkCommandBuffer commandBuf
     assert(!"vkCmdFillBuffer is not implemented");
 }
 
-extern "C" VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(VkCommandBuffer commandBuffer,
+extern "C" VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(VkCommandBuffer command_buffer,
                                                            VkImage image,
-                                                           VkImageLayout imageLayout,
-                                                           const VkClearColorValue *pColor,
-                                                           uint32_t rangeCount,
-                                                           const VkImageSubresourceRange *pRanges)
-{
-#warning finish implementing vkCmdClearColorImage
-    assert(!"vkCmdClearColorImage is not implemented");
+                                                           VkImageLayout image_layout,
+                                                           const VkClearColorValue *color,
+                                                           uint32_t range_count,
+                                                           const VkImageSubresourceRange *ranges)
+{
+    assert(command_buffer);
+    assert(image);
+    assert(image_layout == VK_IMAGE_LAYOUT_GENERAL
+           || image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+    assert(color);
+    assert(range_count > 0);
+    assert(ranges);
+    auto command_buffer_pointer = vulkan::Vulkan_command_buffer::from_handle(command_buffer);
+    command_buffer_pointer->record_command_and_keep_errors(
+        [&]()
+        {
+            auto image_pointer = vulkan::Vulkan_image::from_handle(image);
+            assert(range_count == 1
+                   && "vkCmdClearColorImage with multiple subresource ranges is not implemented");
+            for(std::uint32_t i = 0; i < range_count; i++)
+            {
+                auto &range = ranges[i];
+                assert(range.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
+                assert(range.baseMipLevel == 0
+                       && (range.levelCount == image_pointer->descriptor.mip_levels
+                           || range.levelCount == VK_REMAINING_MIP_LEVELS)
+                       && "vkCmdClearColorImage with clearing only some of the mipmap levels is not implemented");
+                assert(range.baseArrayLayer == 0
+                       && (range.layerCount == image_pointer->descriptor.array_layers
+                           || range.layerCount == VK_REMAINING_ARRAY_LAYERS)
+                       && "vkCmdClearColorImage with clearing only some of the array layers is not implemented");
+                static_cast<void>(range);
+            }
+#warning finish implementing non-linear image layouts
+            struct Clear_command final : public vulkan::Vulkan_command_buffer::Command
+            {
+                VkClearColorValue clear_color;
+                vulkan::Vulkan_image *image;
+                Clear_command(const VkClearColorValue &clear_color,
+                              vulkan::Vulkan_image *image) noexcept : clear_color(clear_color),
+                                                                      image(image)
+                {
+                }
+                virtual void run(
+                    vulkan::Vulkan_command_buffer::Running_state &state) noexcept override
+                {
+                    static_cast<void>(state);
+                    image->clear(clear_color);
+                }
+            };
+            command_buffer_pointer->commands.push_back(
+                std::make_unique<Clear_command>(*color, image_pointer));
+        });
 }
 
 extern "C" VKAPI_ATTR void VKAPI_CALL
@@ -1330,19 +1390,68 @@ extern "C" VKAPI_ATTR void VKAPI_CALL
 }
 
 extern "C" VKAPI_ATTR void VKAPI_CALL
-    vkCmdPipelineBarrier(VkCommandBuffer commandBuffer,
-                         VkPipelineStageFlags srcStageMask,
-                         VkPipelineStageFlags dstStageMask,
-                         VkDependencyFlags dependencyFlags,
-                         uint32_t memoryBarrierCount,
-                         const VkMemoryBarrier *pMemoryBarriers,
-                         uint32_t bufferMemoryBarrierCount,
-                         const VkBufferMemoryBarrier *pBufferMemoryBarriers,
-                         uint32_t imageMemoryBarrierCount,
-                         const VkImageMemoryBarrier *pImageMemoryBarriers)
-{
-#warning finish implementing vkCmdPipelineBarrier
-    assert(!"vkCmdPipelineBarrier is not implemented");
+    vkCmdPipelineBarrier(VkCommandBuffer command_buffer,
+                         VkPipelineStageFlags src_stage_mask,
+                         VkPipelineStageFlags dst_stage_mask,
+                         VkDependencyFlags dependency_flags,
+                         uint32_t memory_barrier_count,
+                         const VkMemoryBarrier *memory_barriers,
+                         uint32_t buffer_memory_barrier_count,
+                         const VkBufferMemoryBarrier *buffer_memory_barriers,
+                         uint32_t image_memory_barrier_count,
+                         const VkImageMemoryBarrier *image_memory_barriers)
+{
+    assert(command_buffer);
+    assert(src_stage_mask != 0);
+    assert(dst_stage_mask != 0);
+    assert((dependency_flags & ~VK_DEPENDENCY_BY_REGION_BIT) == 0);
+    assert(memory_barrier_count == 0 || memory_barriers);
+    assert(buffer_memory_barrier_count == 0 || buffer_memory_barriers);
+    assert(image_memory_barrier_count == 0 || image_memory_barriers);
+    auto command_buffer_pointer = vulkan::Vulkan_command_buffer::from_handle(command_buffer);
+    command_buffer_pointer->record_command_and_keep_errors(
+        [&]()
+        {
+            bool any_memory_barriers = false;
+            for(std::uint32_t i = 0; i < memory_barrier_count; i++)
+            {
+                auto &memory_barrier = memory_barriers[i];
+                assert(memory_barrier.sType == VK_STRUCTURE_TYPE_MEMORY_BARRIER);
+#warning finish implementing vkCmdPipelineBarrier for VkMemoryBarrier
+                assert(!"vkCmdPipelineBarrier for VkMemoryBarrier is not implemented");
+                any_memory_barriers = true;
+            }
+            for(std::uint32_t i = 0; i < buffer_memory_barrier_count; i++)
+            {
+                auto &buffer_memory_barrier = buffer_memory_barriers[i];
+                assert(buffer_memory_barrier.sType == VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER);
+#warning finish implementing vkCmdPipelineBarrier for VkBufferMemoryBarrier
+                assert(!"vkCmdPipelineBarrier for VkBufferMemoryBarrier is not implemented");
+                any_memory_barriers = true;
+            }
+            for(std::uint32_t i = 0; i < image_memory_barrier_count; i++)
+            {
+                auto &image_memory_barrier = image_memory_barriers[i];
+                assert(image_memory_barrier.sType == VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER);
+#warning finish implementing non-linear image layouts
+                any_memory_barriers = true;
+            }
+            if(any_memory_barriers)
+            {
+                struct Generic_memory_barrier_command final
+                    : public vulkan::Vulkan_command_buffer::Command
+                {
+                    void run(kazan::vulkan::Vulkan_command_buffer::Running_state
+                                 &state) noexcept override
+                    {
+                        static_cast<void>(state);
+                        std::atomic_thread_fence(std::memory_order_acq_rel);
+                    }
+                };
+                command_buffer_pointer->commands.push_back(
+                    std::make_unique<Generic_memory_barrier_command>());
+            }
+        });
 }
 
 extern "C" VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery(VkCommandBuffer commandBuffer,
@@ -1643,10 +1752,21 @@ extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR(VkDevice device,
                                                                 uint64_t timeout,
                                                                 VkSemaphore semaphore,
                                                                 VkFence fence,
-                                                                uint32_t *pImageIndex)
+                                                                uint32_t *image_index)
 {
-#warning finish implementing vkAcquireNextImageKHR
-    assert(!"vkAcquireNextImageKHR is not implemented");
+    assert(device);
+    assert(swapchain);
+    assert(image_index);
+    return vulkan_icd::catch_exceptions_and_return_result(
+        [&]()
+        {
+            auto *swapchain_pointer = vulkan_icd::Vulkan_swapchain::from_handle(swapchain);
+            return swapchain_pointer->acquire_next_image(
+                timeout,
+                vulkan::Vulkan_semaphore::from_handle(semaphore),
+                vulkan::Vulkan_fence::from_handle(fence),
+                *image_index);
+        });
 }
 
 extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue,
index 75645a207e71b2a1753f74c95003811da57da966..ad69747fde1b65bde6b217368361ec1e932ed4e9 100644 (file)
@@ -50,6 +50,10 @@ public:
     {
     }
     virtual ~Vulkan_swapchain() = default;
+    virtual VkResult acquire_next_image(std::uint64_t timeout,
+                                        vulkan::Vulkan_semaphore *semaphore,
+                                        vulkan::Vulkan_fence *fence,
+                                        std::uint32_t &returned_image_index) = 0;
 };
 
 struct Wsi
index c31f19a31ccf27adfe2a604c17ee82787410776f..9656ca4d39bdfd83c7cf5c41bdeb9cb5ece03d0a 100644 (file)
@@ -37,7 +37,9 @@
 #include <list>
 #include <utility>
 #include <algorithm>
+#include <cstdlib>
 #include "util/optional.h"
+#include "util/circular_queue.h"
 
 namespace kazan
 {
@@ -45,6 +47,7 @@ namespace vulkan_icd
 {
 struct Xcb_wsi::Implementation
 {
+    static constexpr std::size_t max_swapchain_image_count = 16;
     static std::uint32_t u32_from_bytes(std::uint8_t b0,
                                         std::uint8_t b1,
                                         std::uint8_t b2,
@@ -222,6 +225,7 @@ struct Xcb_wsi::Implementation
         std::size_t image_pixel_size;
         std::size_t scanline_alignment;
         xcb_shm_query_version_cookie_t shm_query_version_cookie;
+        vulkan::Vulkan_image_descriptor image_descriptor;
         Start_setup_results(Gc gc,
                             bool shm_is_supported,
                             unsigned window_depth,
@@ -232,7 +236,8 @@ struct Xcb_wsi::Implementation
                             const VkSurfaceCapabilitiesKHR &capabilities,
                             std::size_t image_pixel_size,
                             std::size_t scanline_alignment,
-                            xcb_shm_query_version_cookie_t shm_query_version_cookie) noexcept
+                            xcb_shm_query_version_cookie_t shm_query_version_cookie,
+                            const vulkan::Vulkan_image_descriptor &image_descriptor) noexcept
             : status(Status::Success),
               gc(std::move(gc)),
               shm_is_supported(shm_is_supported),
@@ -244,7 +249,8 @@ struct Xcb_wsi::Implementation
               capabilities(capabilities),
               image_pixel_size(image_pixel_size),
               scanline_alignment(scanline_alignment),
-              shm_query_version_cookie(shm_query_version_cookie)
+              shm_query_version_cookie(shm_query_version_cookie),
+              image_descriptor(image_descriptor)
         {
         }
         constexpr Start_setup_results(Status status) noexcept : status(status),
@@ -258,7 +264,8 @@ struct Xcb_wsi::Implementation
                                                                 capabilities{},
                                                                 image_pixel_size(),
                                                                 scanline_alignment(),
-                                                                shm_query_version_cookie()
+                                                                shm_query_version_cookie(),
+                                                                image_descriptor()
         {
             assert(status != Status::Success);
         }
@@ -399,7 +406,7 @@ struct Xcb_wsi::Implementation
         };
         VkSurfaceCapabilitiesKHR capabilities = {
             .minImageCount = 2,
-            .maxImageCount = 0,
+            .maxImageCount = max_swapchain_image_count,
             .currentExtent =
                 {
                     .width = image_width, .height = image_height,
@@ -433,46 +440,67 @@ struct Xcb_wsi::Implementation
                                    capabilities,
                                    image_pixel_size,
                                    scanline_alignment,
-                                   shm_query_version_cookie);
+                                   shm_query_version_cookie,
+                                   vulkan::Vulkan_image_descriptor(
+                                       0,
+                                       VK_IMAGE_TYPE_2D,
+                                       VK_FORMAT_UNDEFINED,
+                                       VkExtent3D{
+                                           .width = image_width, .height = image_height, .depth = 1,
+                                       },
+                                       1,
+                                       1,
+                                       VK_SAMPLE_COUNT_1_BIT,
+                                       VK_IMAGE_TILING_OPTIMAL));
     }
     struct Swapchain final : public Vulkan_swapchain
     {
+        enum class Image_owner
+        {
+            Swapchain,
+            Application,
+            Presentation_engine,
+        };
+        enum class Status
+        {
+            Setup_failed,
+            No_surface,
+            Out_of_date,
+            Good,
+        };
         struct Swapchain_image final : public vulkan::Vulkan_image
         {
-            std::shared_ptr<void> pixels;
-            std::size_t row_pitch;
-            std::uint32_t width;
-            std::uint32_t height;
-            std::size_t pixel_size;
             Shared_memory_segment shared_memory_segment;
             Server_shm_seg server_shm_seg;
             Pixmap pixmap;
-            std::list<Swapchain_image *>::iterator iter;
-            Swapchain_image(std::shared_ptr<void> pixels,
-                            std::size_t row_pitch,
-                            std::uint32_t width,
-                            std::uint32_t height,
-                            std::size_t pixel_size,
+            Image_owner owner;
+            xcb_get_geometry_cookie_t get_geometry_cookie{};
+            Swapchain_image(const vulkan::Vulkan_image_descriptor &descriptor,
+                            std::shared_ptr<void> pixels,
                             Shared_memory_segment shared_memory_segment,
                             Server_shm_seg server_shm_seg,
-                            Pixmap pixmap,
-                            std::list<Swapchain_image *>::iterator iter) noexcept
-                : pixels(std::move(pixels)),
-                  row_pitch(row_pitch),
-                  width(width),
-                  height(height),
-                  pixel_size(pixel_size),
+                            Pixmap pixmap) noexcept
+                : Vulkan_image(descriptor, std::move(pixels)),
                   shared_memory_segment(std::move(shared_memory_segment)),
                   server_shm_seg(std::move(server_shm_seg)),
                   pixmap(std::move(pixmap)),
-                  iter(iter)
+                  owner(Image_owner::Swapchain)
             {
             }
         };
+        Swapchain_image &get_image(std::size_t index) noexcept
+        {
+            assert(index < images.size());
+            assert(dynamic_cast<Swapchain_image *>(images[index].get()));
+            return *static_cast<Swapchain_image *>(images[index].get());
+        }
         xcb_connection_t *connection;
         xcb_window_t window;
         bool shm_is_supported;
-        std::list<Swapchain_image *> free_list;
+        Status status;
+        util::Static_circular_deque<std::size_t, max_swapchain_image_count> presenting_image_queue;
+        std::uint32_t swapchain_width;
+        std::uint32_t swapchain_height;
         explicit Swapchain(Start_setup_results start_setup_results,
                            xcb_connection_t *connection,
                            xcb_window_t window,
@@ -480,7 +508,9 @@ struct Xcb_wsi::Implementation
             : Vulkan_swapchain({}),
               connection(connection),
               window(window),
-              shm_is_supported(start_setup_results.shm_is_supported)
+              shm_is_supported(start_setup_results.shm_is_supported),
+              status(Status::Good),
+              presenting_image_queue()
         {
             assert(create_info.sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
 #warning formats other than VK_FORMAT_B8G8R8A8_UNORM are unimplemented
@@ -497,6 +527,18 @@ struct Xcb_wsi::Implementation
             assert((create_info.compositeAlpha
                     & ~start_setup_results.capabilities.supportedCompositeAlpha)
                    == 0);
+            switch(start_setup_results.status)
+            {
+            case Start_setup_results::Status::Bad_surface:
+            case Start_setup_results::Status::No_support:
+                status = Status::Setup_failed;
+                return;
+            case Start_setup_results::Status::Success:
+                break;
+            }
+            start_setup_results.image_descriptor.format = create_info.imageFormat;
+            swapchain_width = start_setup_results.image_width;
+            swapchain_height = start_setup_results.image_height;
             const char *warning_message_present_mode_name = nullptr;
             switch(create_info.presentMode)
             {
@@ -593,32 +635,93 @@ struct Xcb_wsi::Implementation
                                                                     delete[] p;
                                                                 });
                     }
-                    auto image_iter = free_list.insert(free_list.end(), nullptr);
-                    auto image =
-                        std::make_unique<Swapchain_image>(std::move(pixels),
-                                                          padded_scanline_size,
-                                                          start_setup_results.image_width,
-                                                          start_setup_results.image_height,
-                                                          start_setup_results.image_pixel_size,
+                    images.push_back(
+                        std::make_unique<Swapchain_image>(start_setup_results.image_descriptor,
+                                                          std::move(pixels),
                                                           std::move(shared_memory_segment),
                                                           std::move(server_shm_seg),
-                                                          std::move(pixmap),
-                                                          image_iter);
-                    *image_iter = image.get();
-                    images.push_back(std::move(image));
+                                                          std::move(pixmap)));
                 }
                 if(shm_failed)
                 {
                     std::cerr << "using shared memory failed, falling back to using core X protocol"
                               << std::endl;
                     shm_is_supported = false;
-                    free_list.clear();
                     images.clear();
                     continue;
                 }
                 break;
             }
         }
+        virtual VkResult acquire_next_image(std::uint64_t timeout,
+                                            vulkan::Vulkan_semaphore *semaphore,
+                                            vulkan::Vulkan_fence *fence,
+                                            std::uint32_t &returned_image_index) override
+        {
+#warning figure out how to use timeouts with xcb blocking for X server responses
+            switch(status)
+            {
+            case Status::No_surface:
+            case Status::Setup_failed:
+                return VK_ERROR_SURFACE_LOST_KHR;
+            case Status::Out_of_date:
+                return VK_ERROR_OUT_OF_DATE_KHR;
+            case Status::Good:
+                break;
+            }
+            while(true)
+            {
+                for(std::size_t i = 0; i < images.size(); i++)
+                {
+                    auto &image = get_image(i);
+                    if(image.owner == Image_owner::Swapchain)
+                    {
+                        image.owner = Image_owner::Application;
+                        returned_image_index = i;
+                        if(semaphore)
+                            semaphore->signal();
+                        if(fence)
+                            fence->signal();
+                        return VK_SUCCESS;
+                    }
+                }
+                if(presenting_image_queue.empty())
+                {
+                    std::cerr << "vkAcquireNextImageKHR called when application has already "
+                                 "acquired all swapchain images; aborting"
+                              << std::endl;
+                    std::abort();
+                }
+                assert(shm_is_supported);
+                std::size_t image_index = presenting_image_queue.front();
+                presenting_image_queue.pop_front();
+                auto &image = get_image(image_index);
+                // wait for the presentation request to finish
+                // we use a xcb_get_geometry command after the xcb_copy_area command, so we can wait
+                // on the xcb_get_geometry command since the X server processes commands in order
+                auto get_geometry_reply = Get_geometry_reply(
+                    xcb_get_geometry_reply(connection, image.get_geometry_cookie, nullptr));
+                image.owner = Image_owner::Swapchain;
+                if(!get_geometry_reply)
+                {
+                    status = Status::No_surface;
+                    return VK_ERROR_SURFACE_LOST_KHR;
+                }
+                if(get_geometry_reply->width != swapchain_width
+                   || get_geometry_reply->height != swapchain_height)
+                {
+                    status = Status::Out_of_date;
+                    return VK_ERROR_OUT_OF_DATE_KHR;
+                }
+                image.owner = Image_owner::Application;
+                returned_image_index = image_index;
+                if(semaphore)
+                    semaphore->signal();
+                if(fence)
+                    fence->signal();
+                return VK_SUCCESS;
+            }
+        }
     };
 };
 
@@ -741,13 +844,23 @@ VkResult Xcb_wsi::get_surface_capabilities(VkIcdSurfaceBase *surface_,
 util::variant<VkResult, std::unique_ptr<Vulkan_swapchain>> Xcb_wsi::create_swapchain(
     vulkan::Vulkan_device &device, const VkSwapchainCreateInfoKHR &create_info) const
 {
-#warning finish implementing Xcb_wsi::create_swapchain
     auto &surface = *reinterpret_cast<Surface_type *>(create_info.surface);
-    return std::make_unique<Implementation::Swapchain>(
+    auto swapchain = std::make_unique<Implementation::Swapchain>(
         Implementation::start_setup(surface.connection, surface.window, true),
         surface.connection,
         surface.window,
         create_info);
+    switch(swapchain->status)
+    {
+    case Implementation::Swapchain::Status::Setup_failed:
+    case Implementation::Swapchain::Status::Out_of_date:
+    case Implementation::Swapchain::Status::No_surface:
+        return VK_ERROR_SURFACE_LOST_KHR;
+    case Implementation::Swapchain::Status::Good:
+        return swapchain;
+    }
+    assert(!"unreachable");
+    return {};
 }
 
 const Xcb_wsi &Xcb_wsi::get() noexcept