From d34f66b0aeab3f5ef91cdb58769f4b76c008b17e Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Tue, 19 Sep 2017 22:04:24 -0700 Subject: [PATCH] working on implementing device memory --- src/demo/demo.cpp | 20 +-- src/pipeline/pipeline.cpp | 9 +- src/util/memory.h | 4 +- src/vulkan/api_objects.cpp | 12 ++ src/vulkan/api_objects.h | 274 +++++++++++++++++++++++++++------- src/vulkan_icd/vulkan_icd.cpp | 86 +++++++---- src/vulkan_icd/x11_wsi.cpp | 2 +- 7 files changed, 312 insertions(+), 95 deletions(-) diff --git a/src/demo/demo.cpp b/src/demo/demo.cpp index 022bfc8..a257d66 100644 --- a/src/demo/demo.cpp +++ b/src/demo/demo.cpp @@ -892,16 +892,16 @@ int test_main(int argc, char **argv) ::SDL_FreeSurface(v); } }; - std::unique_ptr surface( - SDL_CreateRGBSurfaceFrom(color_attachment->memory.get(), - window_width, - window_height, - bits_per_pixel, - color_attachment->descriptor.get_memory_stride(), - rgba(0xFF, 0, 0, 0), - rgba(0, 0xFF, 0, 0), - rgba(0, 0, 0xFF, 0), - rgba(0, 0, 0, 0xFF))); + std::unique_ptr surface(SDL_CreateRGBSurfaceFrom( + color_attachment->memory.get(), + window_width, + window_height, + bits_per_pixel, + color_attachment->descriptor.get_memory_properties().get_color_component().stride, + rgba(0xFF, 0, 0, 0), + rgba(0, 0xFF, 0, 0), + rgba(0, 0, 0xFF, 0), + rgba(0, 0, 0, 0xFF))); if(!surface) throw std::runtime_error(std::string("SDL_CreateRGBSurfaceFrom failed: ") + SDL_GetError()); diff --git a/src/pipeline/pipeline.cpp b/src/pipeline/pipeline.cpp index dda7491..84c6225 100644 --- a/src/pipeline/pipeline.cpp +++ b/src/pipeline/pipeline.cpp @@ -374,8 +374,13 @@ void Graphics_pipeline::run(std::uint32_t vertex_start_index, { 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(); + auto color_attachment_memory_properties = color_attachment.descriptor.get_memory_properties(); + auto color_attachment_memory_properties_color_component = + color_attachment_memory_properties.get_color_component(); + std::size_t color_attachment_stride = color_attachment_memory_properties_color_component.stride; + std::size_t color_attachment_pixel_size = + color_attachment_memory_properties_color_component.pixel_size; + assert(color_attachment_memory_properties_color_component.offset_from_array_layer_start == 0); 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; diff --git a/src/util/memory.h b/src/util/memory.h index 67479cb..c1bcc16 100644 --- a/src/util/memory.h +++ b/src/util/memory.h @@ -31,8 +31,6 @@ namespace kazan { namespace util { -namespace detail -{ constexpr std::size_t get_max_align_alignment() noexcept { using namespace std; @@ -40,6 +38,8 @@ constexpr std::size_t get_max_align_alignment() noexcept return alignof(max_align_t); } +namespace detail +{ template get_max_align_alignment())> struct Aligned_memory_allocator_base { diff --git a/src/vulkan/api_objects.cpp b/src/vulkan/api_objects.cpp index f0d4369..595f3bc 100644 --- a/src/vulkan/api_objects.cpp +++ b/src/vulkan/api_objects.cpp @@ -521,6 +521,18 @@ std::unique_ptr Vulkan_image::create(Vulkan_device &device, return std::make_unique(Vulkan_image_descriptor(create_info)); } +std::unique_ptr Vulkan_image_view::create( + Vulkan_device &device, const VkImageViewCreateInfo &create_info) +{ + assert(create_info.sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO); + assert(create_info.image); + return std::make_unique(*Vulkan_image::from_handle(create_info.image), + create_info.viewType, + create_info.format, + create_info.components, + create_info.subresourceRange); +} + void Vulkan_command_buffer::Command::on_record_end(Vulkan_command_buffer &command_buffer) { static_cast(command_buffer); diff --git a/src/vulkan/api_objects.h b/src/vulkan/api_objects.h index 0ca1eb3..45bbfd0 100644 --- a/src/vulkan/api_objects.h +++ b/src/vulkan/api_objects.h @@ -33,6 +33,7 @@ #include "util/constexpr_array.h" #include "util/optional.h" #include "util/circular_queue.h" +#include "util/memory.h" #include #include #include @@ -1519,6 +1520,35 @@ typename std:: *>(object)); } +struct Vulkan_device; + +struct Vulkan_device_memory + : public Vulkan_nondispatchable_object +{ + static constexpr std::size_t alignment = 64; + std::shared_ptr memory; + explicit Vulkan_device_memory(std::shared_ptr memory) noexcept : memory(std::move(memory)) + { + } + static std::shared_ptr allocate(VkDeviceSize size) + { + if(static_cast(size) != size) + throw std::bad_alloc(); + typedef util::Aligned_memory_allocator Allocator; + return std::shared_ptr(Allocator::allocate(size), Allocator::Deleter{}); + } + static std::unique_ptr create(Vulkan_device &device, + const VkMemoryAllocateInfo &allocate_info) + { + static_cast(device); + assert(allocate_info.sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO); + constexpr std::uint32_t main_memory_type_index = 0; + assert(allocate_info.memoryTypeIndex == main_memory_type_index); + assert(allocate_info.allocationSize != 0); + return std::make_unique(allocate(allocate_info.allocationSize)); + } +}; + struct Vulkan_instance; struct Vulkan_physical_device @@ -1639,9 +1669,9 @@ struct Vulkan_physical_device }, .viewportSubPixelBits = 16, .minMemoryMapAlignment = 64, - .minTexelBufferOffsetAlignment = alignof(std::max_align_t), - .minUniformBufferOffsetAlignment = alignof(std::max_align_t), - .minStorageBufferOffsetAlignment = alignof(std::max_align_t), + .minTexelBufferOffsetAlignment = util::get_max_align_alignment(), + .minUniformBufferOffsetAlignment = util::get_max_align_alignment(), + .minStorageBufferOffsetAlignment = util::get_max_align_alignment(), .minTexelOffset = std::numeric_limits::min(), .maxTexelOffset = std::numeric_limits::max(), .minTexelGatherOffset = 0, @@ -1850,8 +1880,6 @@ struct Vulkan_instance : public Vulkan_dispatchable_object { void signal() // empty function for if semaphores are needed later @@ -2129,10 +2157,17 @@ struct Vulkan_image_descriptor assert(type == VK_IMAGE_TYPE_2D && "unimplemented image type"); assert(extent.depth == 1); - assert(format == VK_FORMAT_B8G8R8A8_UNORM && "unimplemented image format"); + switch(format) + { + case VK_FORMAT_B8G8R8A8_UNORM: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + case VK_FORMAT_D32_SFLOAT: + break; + default: + assert(!"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"); } @@ -2153,27 +2188,88 @@ struct Vulkan_image_descriptor tiling(tiling) { } - constexpr std::size_t get_memory_size() const noexcept + struct Image_memory_properties { -#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 + std::size_t array_layer_size; + std::size_t size; + std::size_t alignment = util::get_max_align_alignment(); + static constexpr std::size_t max_subimage_count = 2; + std::size_t subimage_count; + struct Subimage + { + enum class Component + { + None, + Color, + Depth, + Stencil, + }; + Component component; + std::size_t size; + std::size_t stride; + std::size_t pixel_size; + std::size_t offset_from_array_layer_start; + constexpr Subimage() noexcept : component(Component::None), + size(0), + stride(0), + pixel_size(0), + offset_from_array_layer_start(0) + { + } + constexpr Subimage(Component component, + std::size_t size, + std::size_t stride, + std::size_t pixel_size, + std::size_t offset_from_array_layer_start) noexcept + : component(component), + size(size), + stride(stride), + pixel_size(pixel_size), + offset_from_array_layer_start(offset_from_array_layer_start) + { + } + }; + Subimage subimages[max_subimage_count]; + constexpr Image_memory_properties(std::uint32_t array_layer_count, + const Subimage &subimage) noexcept + : array_layer_size(subimage.size), + size(array_layer_size *array_layer_count), + subimage_count(1), + subimages{subimage} + { + } + constexpr Image_memory_properties(std::uint32_t array_layer_count, + const Subimage &subimage0, + const Subimage &subimage1) noexcept + : array_layer_size(subimage0.size + subimage1.size), + size(array_layer_size *array_layer_count), + subimage_count(2), + subimages{subimage0, subimage1} + { + assert(subimage0.component != subimage1.component); + } + constexpr Subimage get_component(Subimage::Component component) const noexcept + { + for(std::size_t i = 0; i < subimage_count; i++) + if(subimages[i].component == component) + return subimages[i]; + assert(!"image component not found"); + return {}; + } + constexpr Subimage get_color_component() const noexcept + { + return get_component(Subimage::Component::Color); + } + constexpr Subimage get_depth_component() const noexcept + { + return get_component(Subimage::Component::Depth); + } + constexpr Subimage get_stencil_component() const noexcept + { + return get_component(Subimage::Component::Stencil); + } + }; + constexpr Image_memory_properties get_memory_properties() const noexcept { #warning finish implementing Image assert(samples == VK_SAMPLE_COUNT_1_BIT && "multisample images are unimplemented"); @@ -2184,31 +2280,78 @@ struct Vulkan_image_descriptor 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; + +#warning implement non-linear image tiling + switch(format) + { + case VK_FORMAT_B8G8R8A8_UNORM: + { + std::size_t pixel_size = sizeof(std::uint32_t); + std::size_t stride = pixel_size * extent.width; + std::size_t subimage_size = stride * extent.height; + return Image_memory_properties(array_layers, + Image_memory_properties::Subimage( + Image_memory_properties::Subimage::Component::Color, + subimage_size, + stride, + pixel_size, + 0)); + } + case VK_FORMAT_D32_SFLOAT: + { + std::size_t pixel_size = sizeof(float); + std::size_t stride = pixel_size * extent.width; + std::size_t subimage_size = stride * extent.height; + return Image_memory_properties(array_layers, + Image_memory_properties::Subimage( + Image_memory_properties::Subimage::Component::Depth, + subimage_size, + stride, + pixel_size, + 0)); + } + case VK_FORMAT_D32_SFLOAT_S8_UINT: + { + std::size_t depth_pixel_size = sizeof(float); + std::size_t stencil_pixel_size = sizeof(std::uint8_t); + std::size_t depth_stride = depth_pixel_size * extent.width; + std::size_t stencil_stride = stencil_pixel_size * extent.width; + static_assert(sizeof(float) == 4, ""); + // round stencil_stride up to multiple of sizeof(float) + stencil_stride = (stencil_stride + sizeof(float) - 1) & ~(sizeof(float) - 1); + std::size_t depth_subimage_size = depth_stride * extent.height; + std::size_t stencil_subimage_size = stencil_stride * extent.height; + return Image_memory_properties( + array_layers, + Image_memory_properties::Subimage( + Image_memory_properties::Subimage::Component::Depth, + depth_subimage_size, + depth_stride, + depth_pixel_size, + 0), + Image_memory_properties::Subimage( + Image_memory_properties::Subimage::Component::Stencil, + stencil_subimage_size, + stencil_stride, + stencil_pixel_size, + depth_subimage_size)); + } + default: + assert(!"unimplemented image format"); + return Image_memory_properties(array_layers, {}); + } } - constexpr std::size_t get_memory_pixel_size() const noexcept + constexpr VkMemoryRequirements get_memory_requirements() 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; + constexpr std::size_t main_memory_type_index = 0; + auto memory_properties = get_memory_properties(); + return { + .size = memory_properties.size, + .alignment = memory_properties.alignment, + .memoryTypeBits = 1UL << main_memory_type_index, + }; } }; @@ -2224,11 +2367,12 @@ struct Vulkan_image : public Vulkan_nondispatchable_object create_with_memory( const Vulkan_image_descriptor &descriptor) { - std::shared_ptr memory(new unsigned char[descriptor.get_memory_size()], - [](unsigned char *p) noexcept - { - delete[] p; - }); + std::shared_ptr memory( + new unsigned char[descriptor.get_memory_properties().size], + [](unsigned char *p) noexcept + { + delete[] p; + }); return std::make_unique(descriptor, std::move(memory)); } void clear(VkClearColorValue color) noexcept; @@ -2238,6 +2382,30 @@ struct Vulkan_image : public Vulkan_nondispatchable_object +{ + Vulkan_image &base_image; + VkImageViewType view_type; + VkFormat format; + VkComponentMapping components; + VkImageSubresourceRange subresource_range; + Vulkan_image_view(Vulkan_image &base_image, + VkImageViewType view_type, + VkFormat format, + const VkComponentMapping &components, + const VkImageSubresourceRange &subresource_range) noexcept + : base_image(base_image), + view_type(view_type), + format(format), + components(components), + subresource_range(subresource_range) + { + } +#warning finish implementing Vulkan_image_view + static std::unique_ptr create(Vulkan_device &device, + const VkImageViewCreateInfo &create_info); +}; + struct Vulkan_command_pool; struct Vulkan_command_buffer diff --git a/src/vulkan_icd/vulkan_icd.cpp b/src/vulkan_icd/vulkan_icd.cpp index 1a88b65..430cb52 100644 --- a/src/vulkan_icd/vulkan_icd.cpp +++ b/src/vulkan_icd/vulkan_icd.cpp @@ -348,13 +348,22 @@ extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle(VkDevice device) extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(VkDevice device, - const VkMemoryAllocateInfo *pAllocateInfo, + const VkMemoryAllocateInfo *allocate_info, const VkAllocationCallbacks *allocator, - VkDeviceMemory *pMemory) + VkDeviceMemory *memory) { validate_allocator(allocator); -#warning finish implementing vkAllocateMemory - assert(!"vkAllocateMemory is not implemented"); + assert(device); + assert(allocate_info); + assert(memory); + return vulkan_icd::catch_exceptions_and_return_result( + [&]() + { + auto create_result = vulkan::Vulkan_device_memory::create( + *vulkan::Vulkan_device::from_handle(device), *allocate_info); + *memory = move_to_handle(std::move(create_result)); + return VK_SUCCESS; + }); } extern "C" VKAPI_ATTR void VKAPI_CALL vkFreeMemory(VkDevice device, @@ -362,8 +371,8 @@ extern "C" VKAPI_ATTR void VKAPI_CALL vkFreeMemory(VkDevice device, const VkAllocationCallbacks *allocator) { validate_allocator(allocator); -#warning finish implementing vkFreeMemory - assert(!"vkFreeMemory is not implemented"); + assert(device); + vulkan::Vulkan_device_memory::move_from_handle(memory).reset(); } extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory(VkDevice device, @@ -371,16 +380,19 @@ extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory(VkDevice device, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, - void **ppData) + void **data) { -#warning finish implementing vkMapMemory - assert(!"vkMapMemory is not implemented"); + assert(device); + assert(memory); + assert(data); + *data = static_cast(vulkan::Vulkan_device_memory::from_handle(memory)->memory.get()) + offset; + return VK_SUCCESS; } extern "C" VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(VkDevice device, VkDeviceMemory memory) { -#warning finish implementing vkUnmapMemory - assert(!"vkUnmapMemory is not implemented"); + assert(device); + assert(memory); } extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges( @@ -430,10 +442,12 @@ extern "C" VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements( } extern "C" VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements( - VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) + VkDevice device, VkImage image, VkMemoryRequirements *memory_requirements) { -#warning finish implementing vkGetImageMemoryRequirements - assert(!"vkGetImageMemoryRequirements is not implemented"); + assert(device); + assert(image); + assert(memory_requirements); + *memory_requirements = vulkan::Vulkan_image::from_handle(image)->descriptor.get_memory_requirements(); } extern "C" VKAPI_ATTR void VKAPI_CALL @@ -677,13 +691,22 @@ extern "C" VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView(VkDevice device, } extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(VkDevice device, - const VkImageCreateInfo *pCreateInfo, + const VkImageCreateInfo *create_info, const VkAllocationCallbacks *allocator, - VkImage *pImage) + VkImage *image) { validate_allocator(allocator); -#warning finish implementing vkCreateImage - assert(!"vkCreateImage is not implemented"); + assert(device); + assert(create_info); + assert(image); + return vulkan_icd::catch_exceptions_and_return_result( + [&]() + { + auto create_result = vulkan::Vulkan_image::create( + *vulkan::Vulkan_device::from_handle(device), *create_info); + *image = move_to_handle(std::move(create_result)); + return VK_SUCCESS; + }); } extern "C" VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, @@ -691,8 +714,8 @@ extern "C" VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, const VkAllocationCallbacks *allocator) { validate_allocator(allocator); -#warning finish implementing vkDestroyImage - assert(!"vkDestroyImage is not implemented"); + assert(device); + vulkan::Vulkan_image::move_from_handle(image).reset(); } extern "C" VKAPI_ATTR void VKAPI_CALL @@ -707,22 +730,31 @@ extern "C" VKAPI_ATTR void VKAPI_CALL extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(VkDevice device, - const VkImageViewCreateInfo *pCreateInfo, + const VkImageViewCreateInfo *create_info, const VkAllocationCallbacks *allocator, - VkImageView *pView) + VkImageView *view) { validate_allocator(allocator); -#warning finish implementing vkCreateImageView - assert(!"vkCreateImageView is not implemented"); + assert(device); + assert(create_info); + assert(view); + return vulkan_icd::catch_exceptions_and_return_result( + [&]() + { + auto create_result = vulkan::Vulkan_image_view::create( + *vulkan::Vulkan_device::from_handle(device), *create_info); + *view = move_to_handle(std::move(create_result)); + return VK_SUCCESS; + }); } extern "C" VKAPI_ATTR void VKAPI_CALL vkDestroyImageView(VkDevice device, - VkImageView imageView, + VkImageView image_view, const VkAllocationCallbacks *allocator) { validate_allocator(allocator); -#warning finish implementing vkDestroyImageView - assert(!"vkDestroyImageView is not implemented"); + assert(device); + vulkan::Vulkan_image_view::move_from_handle(image_view).reset(); } extern "C" VKAPI_ATTR VkResult VKAPI_CALL diff --git a/src/vulkan_icd/x11_wsi.cpp b/src/vulkan_icd/x11_wsi.cpp index 9b2b76e..bda25f7 100644 --- a/src/vulkan_icd/x11_wsi.cpp +++ b/src/vulkan_icd/x11_wsi.cpp @@ -780,7 +780,7 @@ struct Xcb_wsi::Implementation } else { - std::size_t image_size = image.descriptor.get_memory_size(); + std::size_t image_size = image.descriptor.get_memory_properties().size; assert(static_cast(image_size) == image_size); xcb_put_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, -- 2.30.2