Compare commits

...

4 commits
main ... image

Author SHA1 Message Date
94aed050bd
wha t ! 2024-09-12 00:13:48 +02:00
9d043c3594
closer 2024-09-11 19:55:26 +02:00
9fba9e626e
holy fuck this is such a stupid issue 2024-09-11 19:41:35 +02:00
97ca8319c3
first working version
uses stb to load the image, currently all images have their texture
replaced with the texture of the first image

gonna try to fix that soon
2024-09-11 18:20:45 +02:00
14 changed files with 712 additions and 107 deletions

View file

@ -4,8 +4,8 @@ CC = clang
CFLAGS = -std=c11 -Wall -Wextra -Wpedantic
CFLAGS += -Werror -Wfloat-equal -Wshadow
CFLAGS += -fPIC -fstrict-aliasing
CFLAGS += $(shell pkg-config --cflags glfw3 vulkan)
LDFLAGS = $(shell pkg-config --libs glfw3 vulkan)
CFLAGS += $(shell pkg-config --cflags glfw3 stb vulkan)
LDFLAGS = $(shell pkg-config --libs glfw3 stb vulkan)
ifdef DEBUG
CFLAGS += -DDEBUG -g

View file

@ -6,6 +6,7 @@
gnumake,
pkg-config,
shaderc,
stb,
vulkan-headers,
vulkan-loader,
vulkan-validation-layers,
@ -20,6 +21,7 @@ in stdenv.mkDerivation {
buildInputs = [
glfw
stb
vulkan-headers
vulkan-loader
vulkan-validation-layers

BIN
examples/:3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

15
examples/image.c Normal file
View file

@ -0,0 +1,15 @@
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
#include <stdlib.h>
#include <ptk.h>
int main(void) {
if (!ptk_init(800, 600, "image", (PtkVersion){ .major = 0, .minor = 1, .patch = 0 })) {
return EXIT_FAILURE;
}
return ptk_run(PTK_BOX(
ptk_image("examples/papiezWasap.png", (PtkPos){ .x = 200.0f, .y = 200.0f }, (PtkSize){ .w = 128.0f, .h = 128.0f }),
ptk_image("examples/:3.png", (PtkPos){ .x = 200.0f, .y = 400.0f }, (PtkSize){ .w = 128.0f, .h = 128.0f })
));
}

BIN
examples/papiezWasap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -26,6 +26,7 @@ typedef enum {
PTK_COMPONENT_TYPE_RECT = 2,
PTK_COMPONENT_TYPE_ELLIPSE = 3,
PTK_COMPONENT_TYPE_CLICKABLE = 4,
PTK_COMPONENT_TYPE_IMAGE = 5,
} PtkComponentType;
const char *ptk_component_type_to_str(PtkComponentType type);
@ -67,6 +68,12 @@ PTK_COMPONENT_DEFINE(PtkClickable,
MouseButtonCallback on_press;
);
PTK_COMPONENT_DEFINE(PtkImage,
const char *path;
PtkPos top_left;
PtkSize size;
);
PtkHandle ptk_box(const size_t child_count, PtkHandle *children);
PtkHandle ptk_triangle(const PtkPos vertices[3], const PtkRGB color);
PtkHandle ptk_rect(const PtkPos top_left, const PtkSize size, const PtkRGB color);
@ -74,6 +81,7 @@ PtkHandle ptk_square(const PtkPos top_left, const float size, const PtkRGB color
PtkHandle ptk_ellipse(const PtkPos center, const PtkSize radii, const PtkRGB color);
PtkHandle ptk_circle(const PtkPos center, const float radius, const PtkRGB color);
PtkHandle ptk_clickable(PtkHandle hitbox, const MouseButtonCallback on_press);
PtkHandle ptk_image(const char *path, const PtkPos top_left, const PtkSize size);
#define PTK_BOX(...) ptk_box(sizeof((PtkHandle []){ __VA_ARGS__ }) / sizeof(PtkHandle), (PtkHandle []) { __VA_ARGS__ })

View file

@ -3,6 +3,9 @@
#version 450
layout(constant_id = 0) const int PTK_COMPONENT_TYPE_ELLIPSE = 0;
layout(constant_id = 1) const int PTK_COMPONENT_TYPE_IMAGE = 0;
layout(constant_id = 2) const int g_max_images = 1;
layout(location = 0) in vec3 fragColor;
layout(location = 1) flat in int shapeType;
@ -10,11 +13,17 @@ layout(location = 2) in vec2 uv;
layout(location = 0) out vec4 outColor;
layout(binding = 1) uniform sampler2D samp;
void main() {
if (shapeType == PTK_COMPONENT_TYPE_ELLIPSE) {
if (length(uv - vec2(0.5)) > 0.5) {
discard;
}
}
if (shapeType == PTK_COMPONENT_TYPE_IMAGE) {
outColor = texture(samp, uv);
} else {
outColor = vec4(fragColor, 1.0);
}
}

View file

@ -191,6 +191,10 @@ PtkHandle ptk_clickable(PtkHandle hitbox, const MouseButtonCallback on_press) {
return clickable_component(get_component_id(), hitbox, on_press);
}
PtkHandle ptk_image(const char *path, const PtkPos top_left, const PtkSize size) {
return image_component(get_component_id(), path, top_left, size);
}
int ptk_run(PtkHandle root) {
vk_init_components(root);

View file

@ -4,6 +4,7 @@
#include <ptk_log.h>
#include <ptk_vk/components.h>
#include <ptk_vk/init.h>
#include <ptk_vk/image.h>
#include <GLFW/glfw3.h>
#include <string.h>
@ -119,6 +120,19 @@ PtkHandle clickable_component(const uint64_t id, PtkHandle hitbox, const MouseBu
return (PtkHandle)ret;
}
PtkHandle image_component(const uint64_t id, const char *path, const PtkPos top_left, const PtkSize size) {
PtkImage *ret = malloc(sizeof(PtkImage));
*ret = (PtkImage){
.id = id,
.type = PTK_COMPONENT_TYPE_IMAGE,
.path = path,
.top_left = top_left,
.size = size,
};
return (PtkHandle)ret;
}
void triangle(const PtkTriangle *triangle) {
PTK_LIST_SET(Vertices, m_vertices_cache, triangle->id, PTK_LIST_NEW(Vertex, 3));
PTK_LIST_SET(Indices, m_indices_cache, triangle->id, PTK_LIST_NEW(uint32_t, 3));
@ -213,6 +227,15 @@ void rect(const PtkRect *rect) {
PTK_LIST_ADD(uint32_t, m_indices_cache.data[rect->id], bottom_right_index);
}
void image(const PtkImage *image) {
vk_create_image(image->path);
PtkRect *r = (PtkRect *)rect_component(image->id, image->top_left, image->size, (PtkRGB){ .r = 0.0f, .g = 0.0f, .b = 0.0f });
r->type = image->type;
rect(r);
}
void ellipse(const PtkEllipse *ellipse) {
const PtkPos top_left = {
.x = ellipse->center.x - ellipse->radii.w,
@ -251,6 +274,9 @@ void component(PtkHandle c) {
case PTK_COMPONENT_TYPE_ELLIPSE: {
ellipse((PtkEllipse *)c);
} break;
case PTK_COMPONENT_TYPE_IMAGE: {
image((PtkImage *)c);
} break;
default: break;
}
}
@ -310,10 +336,10 @@ inline bool ellipse_intersects(const PtkEllipse e, const PtkPos p) {
return ((x * x) / (rx * rx)) + ((y * y) / (ry * ry)) <= 1.0f;
}
bool intersects(const PtkHandle component, const PtkPos point) {
switch (component->type) {
bool intersects(const PtkHandle c, const PtkPos point) {
switch (c->type) {
case PTK_COMPONENT_TYPE_BOX: {
PTK_LIST_FOR_EACH(const PtkHandle, component->children, child, {
PTK_LIST_FOR_EACH(const PtkHandle, c->children, child, {
if (intersects(child, point)) {
return true;
}
@ -322,13 +348,15 @@ bool intersects(const PtkHandle component, const PtkPos point) {
return false;
}
case PTK_COMPONENT_TYPE_TRIANGLE:
return triangle_intersects(*(PtkTriangle *)component, point);
return triangle_intersects(*(PtkTriangle *)c, point);
case PTK_COMPONENT_TYPE_RECT:
return rect_intersects(*(PtkRect *)component, point);
return rect_intersects(*(PtkRect *)c, point);
case PTK_COMPONENT_TYPE_ELLIPSE:
return ellipse_intersects(*(PtkEllipse *)component, point);
return ellipse_intersects(*(PtkEllipse *)c, point);
case PTK_COMPONENT_TYPE_CLICKABLE:
return intersects(component->children.data[0], point);
return intersects(c->children.data[0], point);
case PTK_COMPONENT_TYPE_IMAGE:
return rect_intersects(*(PtkRect *)rect_component(c->id, ((PtkImage *)c)->top_left, ((PtkImage *)c)->size, (PtkRGB){ .r = 0.0f, .g = 0.0f, .b = 0.0f }), point);
}
}

View file

@ -28,6 +28,7 @@ PtkHandle square_component(const uint64_t id, const PtkPos top_left, const float
PtkHandle ellipse_component(const uint64_t id, const PtkPos center, const PtkSize radii, const PtkRGB color);
PtkHandle circle_component(const uint64_t id, const PtkPos center, const float radius, const PtkRGB color);
PtkHandle clickable_component(const uint64_t id, PtkHandle hitbox, const MouseButtonCallback on_press);
PtkHandle image_component(const uint64_t id, const char *path, const PtkPos top_left, const PtkSize size);
void vk_init_components(PtkHandle root);

392
src/ptk_vk/image.c Normal file
View file

@ -0,0 +1,392 @@
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
#include <ptk_vk/image.h>
#include <ptk_vk/init.h>
#include <ptk_vk/utils.h>
#include <ptk_log.h>
#include <ptk_option.h>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
PTK_LIST_DEFINE(VkImage);
PTK_LIST_DEFINE(VkDeviceMemory);
const size_t g_max_images = 64;
size_t g_image_count = 0;
static PTK_LIST(VkImage) m_images;
static PTK_LIST(VkDeviceMemory) m_image_memories;
VkImageView g_image_view;
VkSampler g_sampler;
bool create_image(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags props, VkImage *image, VkDeviceMemory *image_memory) {
VK_TRY(false,
vkCreateImage(
g_dev,
&(VkImageCreateInfo){
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = NULL,
.flags = 0,
.imageType = VK_IMAGE_TYPE_2D,
.format = format,
.extent = (VkExtent3D){
.width = width,
.height = height,
.depth = 1,
},
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = tiling,
.usage = usage,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = NULL,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
},
NULL,
image
)
);
VkMemoryRequirements mem_reqs;
vkGetImageMemoryRequirements(g_dev, *image, &mem_reqs);
PTK_OPTION(uint32_t) mem_type = vk_find_memory_type(mem_reqs.memoryTypeBits, props);
if (!mem_type.exists) {
PTK_ERR("failed to find suitable memory type");
return false;
}
VK_TRY(false,
vkAllocateMemory(
g_dev,
&(VkMemoryAllocateInfo){
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = NULL,
.allocationSize = mem_reqs.size,
.memoryTypeIndex = mem_type.value,
},
NULL,
image_memory
)
);
VK_TRY(false,
vkBindImageMemory(
g_dev,
*image,
*image_memory,
0
)
);
return true;
}
bool transition_image_layout(VkImage image, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) {
(void)format;
PTK_OPTION(VkCommandBuffer) command_buffer = vk_begin_single_time_commands();
if (!command_buffer.exists) {
PTK_ERR("failed to create command buffer");
return false;
}
VkAccessFlags source_access_mask;
VkAccessFlags destination_access_mask;
VkPipelineStageFlags source_stage;
VkPipelineStageFlags destination_stage;
if (
old_layout == VK_IMAGE_LAYOUT_UNDEFINED
&& new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
) {
source_access_mask = 0;
destination_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT;
source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
destination_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
} else if (
old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
&& new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
) {
source_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT;
destination_access_mask = VK_ACCESS_SHADER_READ_BIT;
source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
destination_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} else {
PTK_ERR("unsupported layer transition");
return false;
}
vkCmdPipelineBarrier(
command_buffer.value,
source_stage,
destination_stage,
0,
0,
NULL,
0,
NULL,
1,
&(VkImageMemoryBarrier){
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = NULL,
.srcAccessMask = source_access_mask,
.dstAccessMask = destination_access_mask,
.oldLayout = old_layout,
.newLayout = new_layout,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange = (VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
}
);
if (!vk_end_single_time_commands(command_buffer.value)) {
PTK_ERR("failed to end command buffer");
return false;
}
return true;
}
bool copy_buffer_to_image(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) {
PTK_OPTION(VkCommandBuffer) command_buffer = vk_begin_single_time_commands();
if (!command_buffer.exists) {
PTK_ERR("failed to create command buffer");
return false;
}
vkCmdCopyBufferToImage(
command_buffer.value,
buffer,
image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&(VkBufferImageCopy){
.bufferOffset = 0,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource = (VkImageSubresourceLayers){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.imageOffset = (VkOffset3D){
.x = 0,
.y = 0,
.z = 0,
},
.imageExtent = (VkExtent3D){
.width = width,
.height = height,
.depth = 1,
},
}
);
if (!vk_end_single_time_commands(command_buffer.value)) {
PTK_ERR("failed to end command buffer");
return false;
}
return true;
}
bool create_image_view(VkImage image) {
VK_TRY(false,
vkCreateImageView(
g_dev,
&(VkImageViewCreateInfo){
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = NULL,
.flags = 0,
.image = image,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = VK_FORMAT_R8G8B8A8_SRGB,
.components = (VkComponentMapping){
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
},
.subresourceRange = (VkImageSubresourceRange){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
},
NULL,
&g_image_view
)
);
return true;
}
bool vk_create_sampler(void) {
VkPhysicalDeviceProperties props;
vkGetPhysicalDeviceProperties(g_physical_dev, &props);
VK_TRY(false,
vkCreateSampler(
g_dev,
&(VkSamplerCreateInfo){
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.pNext = NULL,
.flags = 0,
.magFilter = VK_FILTER_LINEAR,
.minFilter = VK_FILTER_LINEAR,
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
.mipLodBias = 0.0f,
.anisotropyEnable = VK_TRUE,
.maxAnisotropy = props.limits.maxSamplerAnisotropy,
.compareEnable = VK_FALSE,
.compareOp = VK_COMPARE_OP_ALWAYS,
.minLod = 0.0f,
.maxLod = 0.0f,
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
.unnormalizedCoordinates = VK_FALSE,
},
NULL,
&g_sampler
)
);
return true;
}
bool vk_create_image(const char *path) {
int texture_width, texture_height;
int texture_channels;
stbi_uc *pixels = stbi_load(path, &texture_width, &texture_height, &texture_channels, STBI_rgb_alpha);
VkDeviceSize image_size = texture_width * texture_height * 4;
if (pixels == NULL) {
PTK_ERR("failed to load image %s", path);
return false;
}
VkBuffer staging_buffer;
VkDeviceMemory staging_buffer_memory;
if (
!vk_create_buffer(
image_size,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&staging_buffer,
&staging_buffer_memory
)
) {
PTK_ERR("failed creating staging image buffer");
return false;
}
void *data;
vkMapMemory(g_dev, staging_buffer_memory, 0, image_size, 0, &data);
memcpy(data, pixels, image_size);
vkUnmapMemory(g_dev, staging_buffer_memory);
stbi_image_free(pixels);
VkImage image;
VkDeviceMemory image_memory;
if (
!create_image(
texture_width,
texture_height,
VK_FORMAT_R8G8B8A8_SRGB,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
&image,
&image_memory
)
) {
PTK_ERR("failed creating image");
return false;
}
if (
!transition_image_layout(
image,
VK_FORMAT_R8G8B8A8_SRGB,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
)
) {
PTK_ERR("failed transitioning image layout to optimal");
return false;
}
if (!copy_buffer_to_image(staging_buffer, image, texture_width, texture_height)) {
PTK_ERR("failed copying buffer to image");
return false;
}
if (
!transition_image_layout(
image,
VK_FORMAT_R8G8B8A8_SRGB,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
)
) {
PTK_ERR("failed transitioning image layout to shader optimal");
return false;
}
vkDestroyBuffer(g_dev, staging_buffer, NULL);
vkFreeMemory(g_dev, staging_buffer_memory, NULL);
PTK_LIST_ADD(VkImage, m_images, image);
PTK_LIST_ADD(VkDeviceMemory, m_image_memories, image_memory);
create_image_view(image);
g_image_count += 1;
vk_update_descriptor_sets();
return true;
}
void vk_image_cleanup(void) {
vkDestroySampler(g_dev, g_sampler, NULL);
vkDestroyImageView(g_dev, g_image_view, NULL);
PTK_LIST_FOR_EACH(VkImage, m_images, i, {
vkDestroyImage(g_dev, i, NULL);
})
PTK_LIST_FREE(m_images);
PTK_LIST_FOR_EACH(VkDeviceMemory, m_image_memories, m, {
vkFreeMemory(g_dev, m, NULL);
})
PTK_LIST_FREE(m_image_memories);
}

26
src/ptk_vk/image.h Normal file
View file

@ -0,0 +1,26 @@
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
#ifndef PTK_PTK_VK_IMAGE_H_
#define PTK_PTK_VK_IMAGE_H_
#include <stdbool.h>
#include <stddef.h>
#include <ptk_list.h>
#ifndef GLFW_INCLUDE_VULKAN
#define GLFW_INCLUDE_VULKAN
#endif
#include <GLFW/glfw3.h>
extern const size_t g_max_images;
extern size_t g_image_count;
extern VkImageView g_image_view;
extern VkSampler g_sampler;
bool vk_create_image(const char *path);
bool vk_create_sampler(void);
void vk_image_cleanup(void);
#endif // PTK_PTK_VK_IMAGE_H_

View file

@ -4,6 +4,7 @@
#include <ptk_vk/components.h>
#include <ptk_vk/draw.h>
#include <ptk_vk/image.h>
#include <ptk_vk/utils.h>
#include <ptk_log.h>
@ -16,8 +17,6 @@
#include <errno.h>
PTK_LIST_DEFINE(VkImage);
PTK_LIST_DEFINE(VkImageView);
PTK_OPTION_DEFINE(uint32_t);
PTK_LIST_DEFINE(VkSurfaceFormatKHR);
PTK_LIST_DEFINE(VkPresentModeKHR);
PTK_LIST_DEFINE(VkFramebuffer);
@ -33,6 +32,7 @@ PTK_LIST_DEFINE(VkDescriptorSet);
typedef const char *constcharptr;
PTK_ARRAY_DEFINE(constcharptr);
PTK_LIST_DEFINE(constcharptr);
PTK_LIST_DEFINE(VkImageView);
#ifdef DEBUG
PTK_LIST_DEFINE(VkLayerProperties);
@ -47,7 +47,7 @@ typedef struct {
static GLFWwindow *m_window = NULL;
static VkInstance m_instance = VK_NULL_HANDLE;
static VkPhysicalDevice m_physical_dev = VK_NULL_HANDLE;
VkPhysicalDevice g_physical_dev = VK_NULL_HANDLE;
VkDevice g_dev = VK_NULL_HANDLE;
static VkSurfaceKHR m_surface = VK_NULL_HANDLE;
@ -284,7 +284,7 @@ bool select_physical_dev(void) {
PTK_DEBUG("total memory: %lu", dev_mem_totals[dev_best_index]);
m_physical_dev = devs[dev_best_index];
g_physical_dev = devs[dev_best_index];
return true;
}
@ -432,11 +432,14 @@ bool is_device_suitable(const VkPhysicalDevice dev) {
PTK_LIST_FREE(queue_families);
return indices_found && extensions_supported && swapchain_adequate;
VkPhysicalDeviceFeatures supported_features;
vkGetPhysicalDeviceFeatures(dev, &supported_features);
return indices_found && extensions_supported && swapchain_adequate && supported_features.samplerAnisotropy;
}
bool create_logical_dev(void) {
if (!is_device_suitable(m_physical_dev)) {
if (!is_device_suitable(g_physical_dev)) {
PTK_ERR("physical device isn't suitable");
return false;
}
@ -458,7 +461,7 @@ bool create_logical_dev(void) {
VK_TRY(false,
vkCreateDevice(
m_physical_dev,
g_physical_dev,
&(VkDeviceCreateInfo){
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = NULL,
@ -469,7 +472,9 @@ bool create_logical_dev(void) {
.ppEnabledLayerNames = m_validation_layers.data,
.enabledExtensionCount = m_device_extensions.size,
.ppEnabledExtensionNames = m_device_extensions.data,
.pEnabledFeatures = &(VkPhysicalDeviceFeatures){0},
.pEnabledFeatures = &(VkPhysicalDeviceFeatures){
.samplerAnisotropy = VK_TRUE,
},
},
NULL,
&g_dev
@ -483,7 +488,7 @@ bool create_logical_dev(void) {
}
bool create_swapchain(void) {
const SwapchainSupportInfo swapchain_support = query_swapchain_support(m_physical_dev);
const SwapchainSupportInfo swapchain_support = query_swapchain_support(g_physical_dev);
const VkSurfaceFormatKHR surface_format = select_swap_surface_format(swapchain_support.formats);
const VkPresentModeKHR present_mode = select_swap_present_mode(swapchain_support.present_modes);
@ -554,7 +559,9 @@ bool create_swapchain(void) {
bool create_image_views(void) {
m_swapchain_image_views = PTK_LIST_NEW(VkImageView, m_swapchain_images.size);
PTK_LIST_FOR_EACH_E(VkImage, m_swapchain_images, i, swapchain_image, {
PTK_LIST_FOR_EACH(VkImage, m_swapchain_images, swapchain_image, {
VkImageView image_view;
VK_TRY(false,
vkCreateImageView(
g_dev,
@ -580,10 +587,11 @@ bool create_image_views(void) {
},
},
NULL,
&m_swapchain_image_views.data[i]
&image_view
)
);
m_swapchain_image_views.size += 1;
PTK_LIST_ADD(VkImageView, m_swapchain_image_views, image_view);
})
return true;
@ -703,7 +711,26 @@ bool create_render_pass(void) {
return true;
}
PTK_ARRAY_DEFINE(VkDescriptorSetLayoutBinding);
bool create_descriptor_set_layout(void) {
PTK_ARRAY(VkDescriptorSetLayoutBinding) bindings = PTK_ARRAY_NEW(VkDescriptorSetLayoutBinding, {
(VkDescriptorSetLayoutBinding){
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
.pImmutableSamplers = NULL,
},
(VkDescriptorSetLayoutBinding){
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.pImmutableSamplers = NULL,
},
});
VK_TRY(false,
vkCreateDescriptorSetLayout(
g_dev,
@ -711,14 +738,8 @@ bool create_descriptor_set_layout(void) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pNext = NULL,
.flags = 0,
.bindingCount = 1,
.pBindings = &(VkDescriptorSetLayoutBinding){
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
.pImmutableSamplers = NULL,
},
.bindingCount = bindings.size,
.pBindings = bindings.data,
},
NULL,
&m_descriptor_set_layout
@ -728,6 +749,8 @@ bool create_descriptor_set_layout(void) {
return true;
}
PTK_ARRAY_DEFINE(VkSpecializationMapEntry);
bool create_graphics_pipeline(void) {
const PTK_STRING vert_shader_code = read_spv("target/shaders/shader.vert.spv");
const PTK_STRING frag_shader_code = read_spv("target/shaders/shader.frag.spv");
@ -746,15 +769,33 @@ bool create_graphics_pipeline(void) {
return false;
}
const VkSpecializationInfo spec_info = {
.mapEntryCount = 1,
.pMapEntries = &(VkSpecializationMapEntry){
PTK_ARRAY(VkSpecializationMapEntry) frag_spec_map_entries = PTK_ARRAY_NEW(VkSpecializationMapEntry, {
(VkSpecializationMapEntry){
.constantID = 0,
.offset = 0,
.size = sizeof(int),
},
.dataSize = sizeof(int),
.pData = &(int){PTK_COMPONENT_TYPE_ELLIPSE},
(VkSpecializationMapEntry){
.constantID = 1,
.offset = sizeof(int),
.size = sizeof(int),
},
(VkSpecializationMapEntry){
.constantID = 2,
.offset = sizeof(int) * 2,
.size = sizeof(int),
},
});
const VkSpecializationInfo frag_spec_info = {
.mapEntryCount = frag_spec_map_entries.size,
.pMapEntries = frag_spec_map_entries.data,
.dataSize = sizeof(int) * 3,
.pData = (int []){
PTK_COMPONENT_TYPE_ELLIPSE,
PTK_COMPONENT_TYPE_IMAGE,
g_max_images
},
};
const VkPipelineShaderStageCreateInfo shader_stages[] = {
@ -774,7 +815,7 @@ bool create_graphics_pipeline(void) {
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = frag_shader_module.value,
.pName = "main",
.pSpecializationInfo = &spec_info,
.pSpecializationInfo = &frag_spec_info,
},
};
@ -982,9 +1023,9 @@ bool create_command_pool(void) {
return true;
}
PTK_OPTION(uint32_t) find_memory_type(const uint32_t type_filter, const VkMemoryPropertyFlags props) {
PTK_OPTION(uint32_t) vk_find_memory_type(const uint32_t type_filter, const VkMemoryPropertyFlags props) {
VkPhysicalDeviceMemoryProperties mem_props;
vkGetPhysicalDeviceMemoryProperties(m_physical_dev, &mem_props);
vkGetPhysicalDeviceMemoryProperties(g_physical_dev, &mem_props);
for (uint32_t i = 0; i < mem_props.memoryTypeCount; ++i) {
if (type_filter & (1 << i) && (mem_props.memoryTypes[i].propertyFlags & props) == props) {
@ -995,7 +1036,7 @@ PTK_OPTION(uint32_t) find_memory_type(const uint32_t type_filter, const VkMemory
return PTK_OPTION_NONE(uint32_t);
}
bool create_buffer(const VkDeviceSize size, const VkBufferUsageFlags usage, const VkMemoryPropertyFlags props, VkBuffer *buffer, VkDeviceMemory *buffer_memory) {
bool vk_create_buffer(const VkDeviceSize size, const VkBufferUsageFlags usage, const VkMemoryPropertyFlags props, VkBuffer *buffer, VkDeviceMemory *buffer_memory) {
VK_TRY(false,
vkCreateBuffer(
g_dev,
@ -1017,7 +1058,7 @@ bool create_buffer(const VkDeviceSize size, const VkBufferUsageFlags usage, cons
VkMemoryRequirements mem_reqs;
vkGetBufferMemoryRequirements(g_dev, *buffer, &mem_reqs);
const PTK_OPTION(uint32_t) memory_type = find_memory_type(mem_reqs.memoryTypeBits, props);
const PTK_OPTION(uint32_t) memory_type = vk_find_memory_type(mem_reqs.memoryTypeBits, props);
if (!memory_type.exists) {
PTK_ERR("failed to find suitable memory type");
@ -1043,10 +1084,10 @@ bool create_buffer(const VkDeviceSize size, const VkBufferUsageFlags usage, cons
return true;
}
bool copy_buffer(const VkBuffer src, const VkBuffer dst, const VkDeviceSize size) {
PTK_OPTION(VkCommandBuffer) vk_begin_single_time_commands(void) {
VkCommandBuffer command_buffer;
VK_TRY(false,
VK_TRY(PTK_OPTION_NONE(VkCommandBuffer),
vkAllocateCommandBuffers(
g_dev,
&(VkCommandBufferAllocateInfo){
@ -1060,25 +1101,25 @@ bool copy_buffer(const VkBuffer src, const VkBuffer dst, const VkDeviceSize size
)
);
VK_TRY(false,
vkBeginCommandBuffer(command_buffer, &(VkCommandBufferBeginInfo){
VK_TRY(PTK_OPTION_NONE(VkCommandBuffer),
vkBeginCommandBuffer(
command_buffer,
&(VkCommandBufferBeginInfo){
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.pNext = NULL,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
.pInheritanceInfo = NULL,
})
}
)
);
vkCmdCopyBuffer(command_buffer, src, dst, 1, &(VkBufferCopy){
.srcOffset = 0,
.dstOffset = 0,
.size = size,
});
return PTK_OPTION_SOME(VkCommandBuffer, command_buffer);
}
bool vk_end_single_time_commands(VkCommandBuffer command_buffer) {
VK_TRY(false, vkEndCommandBuffer(command_buffer));
VK_TRY(false,
vkEndCommandBuffer(command_buffer)
);
vkQueueSubmit(
g_graphics_queue,
1,
@ -1095,21 +1136,44 @@ bool copy_buffer(const VkBuffer src, const VkBuffer dst, const VkDeviceSize size
},
VK_NULL_HANDLE
);
);
vkQueueWaitIdle(g_graphics_queue);
VK_TRY(false, vkQueueWaitIdle(g_graphics_queue));
vkFreeCommandBuffers(g_dev, m_command_pool, 1, &command_buffer);
return true;
}
bool copy_buffer(const VkBuffer src, const VkBuffer dst, const VkDeviceSize size) {
PTK_OPTION(VkCommandBuffer) command_buffer = vk_begin_single_time_commands();
if (!command_buffer.exists) {
PTK_ERR("failed to create command buffer");
return false;
}
vkCmdCopyBuffer(command_buffer.value, src, dst, 1, &(VkBufferCopy){
.srcOffset = 0,
.dstOffset = 0,
.size = size,
});
if (!vk_end_single_time_commands(command_buffer.value)) {
PTK_ERR("failed to end command buffer");
return false;
}
return true;
}
bool transfer_to_buffer(void *src, size_t src_size, VkBuffer buffer) {
const VkDeviceSize buffer_size = src_size;
VkBuffer staging_buffer;
VkDeviceMemory staging_buffer_memory;
if (
!create_buffer(
!vk_create_buffer(
buffer_size,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
@ -1171,7 +1235,7 @@ bool create_vertex_buffer(void) {
// const VkDeviceSize buffer_size = sizeof(g_vertices.data[0]) * g_vertices.size;
const VkDeviceSize buffer_size = 65536;
if (
!create_buffer(
!vk_create_buffer(
buffer_size,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
@ -1189,7 +1253,7 @@ bool create_vertex_buffer(void) {
bool create_index_buffer(void) {
const VkDeviceSize buffer_size = 65536;
if (
!create_buffer(
!vk_create_buffer(
buffer_size,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
@ -1213,7 +1277,7 @@ bool create_uniform_buffers(void) {
for (size_t i = 0; i < g_max_frames_in_flight; ++i) {
if (
!create_buffer(
!vk_create_buffer(
buffer_size,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
@ -1231,7 +1295,20 @@ bool create_uniform_buffers(void) {
return true;
}
PTK_ARRAY_DEFINE(VkDescriptorPoolSize);
bool create_descriptor_pool(void) {
PTK_ARRAY(VkDescriptorPoolSize) pool_sizes = PTK_ARRAY_NEW(VkDescriptorPoolSize, {
(VkDescriptorPoolSize){
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = g_max_frames_in_flight,
},
(VkDescriptorPoolSize){
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = g_max_frames_in_flight,
},
});
VK_TRY(false,
vkCreateDescriptorPool(
g_dev,
@ -1240,11 +1317,8 @@ bool create_descriptor_pool(void) {
.pNext = NULL,
.flags = 0,
.maxSets = g_max_frames_in_flight,
.poolSizeCount = 1,
.pPoolSizes = &(VkDescriptorPoolSize){
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = g_max_frames_in_flight,
},
.poolSizeCount = pool_sizes.size,
.pPoolSizes = pool_sizes.data,
},
NULL,
&m_descriptor_pool
@ -1255,6 +1329,54 @@ bool create_descriptor_pool(void) {
}
PTK_LIST_DEFINE(VkDescriptorSetLayout);
PTK_ARRAY_DEFINE(VkWriteDescriptorSet);
void vk_update_descriptor_sets(void) {
for (size_t i = 0; i < g_max_frames_in_flight; ++i) {
PTK_ARRAY(VkWriteDescriptorSet) descriptor_writes = PTK_ARRAY_NEW(VkWriteDescriptorSet, {
(VkWriteDescriptorSet){
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = NULL,
.dstSet = m_descriptor_sets.data[i],
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.pImageInfo = NULL,
.pBufferInfo = &(VkDescriptorBufferInfo){
.buffer = m_uniform_buffers.data[i],
.offset = 0,
.range = sizeof(UniformBufferObject),
},
.pTexelBufferView = NULL,
},
(VkWriteDescriptorSet){
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = NULL,
.dstSet = m_descriptor_sets.data[i],
.dstBinding = 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &(VkDescriptorImageInfo){
.sampler = g_sampler,
.imageView = g_image_view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
},
.pBufferInfo = NULL,
.pTexelBufferView = NULL,
},
});
vkUpdateDescriptorSets(
g_dev,
descriptor_writes.size,
descriptor_writes.data,
0,
NULL
);
}
}
bool create_descriptor_sets(void) {
PTK_LIST(VkDescriptorSetLayout) layouts = PTK_LIST_NEW(VkDescriptorSetLayout, g_max_frames_in_flight);
@ -1278,30 +1400,7 @@ bool create_descriptor_sets(void) {
)
);
for (size_t i = 0; i < g_max_frames_in_flight; ++i) {
vkUpdateDescriptorSets(
g_dev,
1,
&(VkWriteDescriptorSet){
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = NULL,
.dstSet = m_descriptor_sets.data[i],
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.pImageInfo = NULL,
.pBufferInfo = &(VkDescriptorBufferInfo){
.buffer = m_uniform_buffers.data[i],
.offset = 0,
.range = sizeof(UniformBufferObject),
},
.pTexelBufferView = NULL,
},
0,
NULL
);
}
vk_update_descriptor_sets();
return true;
}
@ -1515,6 +1614,11 @@ bool vk_init(GLFWwindow *window, const size_t width, const size_t height, const
return false;
}
if (!vk_create_sampler()) {
PTK_ERR("failed creating sampler");
return false;
}
if (!create_descriptor_set_layout()) {
PTK_ERR("failed creating descriptor set layout");
return false;
@ -1576,6 +1680,8 @@ bool vk_init(GLFWwindow *window, const size_t width, const size_t height, const
void vk_cleanup(void) {
cleanup_swapchain();
vk_image_cleanup();
vkDestroyPipeline(g_dev, m_pipeline, NULL);
vkDestroyPipelineLayout(g_dev, m_pipeline_layout, NULL);

View file

@ -9,12 +9,16 @@
#include <GLFW/glfw3.h>
#include <ptk.h>
#include <ptk_list.h>
#include <ptk_option.h>
PTK_LIST_DEFINE(VkCommandBuffer);
PTK_LIST_DEFINE(VkSemaphore);
PTK_LIST_DEFINE(VkFence);
PTK_OPTION_DEFINE(VkCommandBuffer);
PTK_OPTION_DEFINE(uint32_t);
extern VkDevice g_dev;
extern VkPhysicalDevice g_physical_dev;
extern VkSwapchainKHR g_swapchain;
extern VkQueue g_graphics_queue;
@ -38,6 +42,16 @@ bool vk_recreate_swapchain(void);
bool vk_update_uniform_buffer(const size_t current_frame);
bool vk_create_buffer(const VkDeviceSize size, const VkBufferUsageFlags usage, const VkMemoryPropertyFlags props, VkBuffer *buffer, VkDeviceMemory *buffer_memory);
PTK_OPTION(uint32_t) vk_find_memory_type(const uint32_t type_filter, const VkMemoryPropertyFlags props);
PTK_OPTION(VkCommandBuffer) vk_begin_single_time_commands(void);
bool vk_end_single_time_commands(VkCommandBuffer command_buffer);
void vk_update_descriptor_sets(void);
void vk_cleanup(void);
#endif // PTK_PTK_VK_INIT_H_