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)
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);
.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,
.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>
.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;
.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,
};
.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,
};
.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,
.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;
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(
}
};
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),
+++ /dev/null
-# 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)
+++ /dev/null
-/*
- * 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"
+++ /dev/null
-/*
- * 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_
kazan_util
kazan_spirv
kazan_llvm_wrapper
- kazan_vulkan
- kazan_image)
+ kazan_vulkan)
{
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)
{
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;
{
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);
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)
{
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;
#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;
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;
::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:
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);
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());
-}
}
}
--- /dev/null
+/*
+ * 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
+
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,
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);
};
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,
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
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,
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)
#include "util/string_view.h"
#include <initializer_list>
#include <iostream>
+#include <atomic>
#include "wsi.h"
+#include "pipeline/pipeline.h"
using namespace kazan;
}
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,
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
}
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,
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,
{
}
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
#include <list>
#include <utility>
#include <algorithm>
+#include <cstdlib>
#include "util/optional.h"
+#include "util/circular_queue.h"
namespace kazan
{
{
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,
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,
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),
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),
capabilities{},
image_pixel_size(),
scanline_alignment(),
- shm_query_version_cookie()
+ shm_query_version_cookie(),
+ image_descriptor()
{
assert(status != Status::Success);
}
};
VkSurfaceCapabilitiesKHR capabilities = {
.minImageCount = 2,
- .maxImageCount = 0,
+ .maxImageCount = max_swapchain_image_count,
.currentExtent =
{
.width = image_width, .height = image_height,
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,
: 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
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)
{
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;
+ }
+ }
};
};
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