images (kinda) working again

the image example shows :3 but it errors a lot and shit
This commit is contained in:
jacekpoz 2024-10-06 13:29:47 +02:00
parent 1dbb93543e
commit 114c8a0c5d
Signed by: poz
SSH key fingerprint: SHA256:JyLeVWE4bF3tDnFeUpUaJsPsNlJyBldDGV/dIKSLyN8
21 changed files with 694 additions and 105 deletions

View file

@ -4,8 +4,8 @@ CC = clang
CFLAGS = -std=c23 -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 })
/*)*/);
}

View file

@ -25,6 +25,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);
@ -66,6 +67,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);
@ -73,6 +80,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,7 @@
#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(location = 0) in vec3 fragColor;
layout(location = 1) flat in int shapeType;
@ -10,11 +11,17 @@ layout(location = 2) in vec2 uv;
layout(location = 0) out vec4 outColor;
layout(binding = 1) uniform sampler2D textureSampler;
void main() {
if (shapeType == PTK_COMPONENT_TYPE_ELLIPSE) {
if (length(uv - vec2(0.5)) > 0.5) {
discard;
}
}
outColor = vec4(fragColor, 1.0);
} else if (shapeType == PTK_COMPONENT_TYPE_IMAGE) {
outColor = texture(textureSampler, uv);
} else {
outColor = vec4(fragColor, 1.0);
}
}

View file

@ -118,6 +118,7 @@ const char *ptk_component_type_to_str(PtkComponentType type) {
case PTK_COMPONENT_TYPE_RECT: res = "rect"; break;
case PTK_COMPONENT_TYPE_ELLIPSE: res = "ellipse"; break;
case PTK_COMPONENT_TYPE_CLICKABLE: res = "clickable"; break;
case PTK_COMPONENT_TYPE_IMAGE: res = "image"; break;
default: res = "unknown"; break;
}
return res;
@ -159,6 +160,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

@ -8,6 +8,7 @@
#include "ptk_vk/components.h"
#include "ptk_vk/descriptors.h"
#include "ptk_vk/device.h"
#include "ptk_vk/image.h"
#include "ptk_vk/init.h"
#include "ptk_vk/instance.h"
#include "ptk_vk/physical_device.h"
@ -174,6 +175,21 @@ bool vk_init(GLFWwindow *window, const size_t width, const size_t height, const
return false;
}
if (!vk_create_texture_image("examples/:3.png")) {
PTK_ERR("failed creating texture image");
return false;
}
if (!vk_create_texture_image_view()) {
PTK_ERR("failed creating texture image view");
return false;
}
if (!vk_create_texture_sampler()) {
PTK_ERR("failed creating texture sampler");
return false;
}
const VkDeviceSize buffer_size = 65536;
PTK_OPTION(BufferStuff) vertex_buffer_stuff_opt = vk_create_buffer(

View file

@ -3,15 +3,14 @@
#include "ptk_vk/buffer.h"
#include "ptk_vk/command_pool.h"
#include "ptk_vk/device.h"
#include "ptk_vk/physical_device.h"
#include "ptk_vk/utils.h"
#include <string.h>
PTK_OPTION(uint32_t) find_memory_type(VkPhysicalDevice physical_dev, 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(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) {
@ -46,7 +45,7 @@ PTK_OPTION(BufferStuff) vk_create_buffer(const VkDeviceSize size, const VkBuffer
VkMemoryRequirements mem_reqs;
vkGetBufferMemoryRequirements(g_dev, ret.buffer, &mem_reqs);
const PTK_OPTION(uint32_t) memory_type = find_memory_type(g_physical_dev, 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");
@ -73,30 +72,14 @@ PTK_OPTION(BufferStuff) vk_create_buffer(const VkDeviceSize size, const VkBuffer
}
bool copy_buffer(const VkBuffer src, const VkBuffer dst, const VkDeviceSize size) {
VkCommandBuffer command_buffer;
PTK_OPTION(VkCommandBuffer) command_buffer_opt = vk_begin_single_time_commands();
VK_TRY(false,
vkAllocateCommandBuffers(
g_dev,
&(VkCommandBufferAllocateInfo){
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.pNext = NULL,
.commandPool = g_command_pool,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1,
},
&command_buffer
)
);
if (!command_buffer_opt.exists) {
PTK_ERR("failed to create command buffer");
return false;
}
VK_TRY(false,
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,
})
);
VkCommandBuffer command_buffer = command_buffer_opt.value;
vkCmdCopyBuffer(command_buffer, src, dst, 1, &(VkBufferCopy){
.srcOffset = 0,
@ -104,30 +87,10 @@ bool copy_buffer(const VkBuffer src, const VkBuffer dst, const VkDeviceSize size
.size = size,
});
VK_TRY(false,
vkEndCommandBuffer(command_buffer)
);
vkQueueSubmit(
g_graphics_queue,
1,
&(VkSubmitInfo){
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = NULL,
.waitSemaphoreCount = 0,
.pWaitSemaphores = NULL,
.pWaitDstStageMask = NULL,
.commandBufferCount = 1,
.pCommandBuffers = &command_buffer,
.signalSemaphoreCount = 0,
.pSignalSemaphores = NULL,
},
VK_NULL_HANDLE
);
vkQueueWaitIdle(g_graphics_queue);
vkFreeCommandBuffers(g_dev, g_command_pool, 1, &command_buffer);
if (!vk_end_single_time_commands(command_buffer)) {
PTK_ERR("failed to end command buffer");
return false;
}
return true;
}

View file

@ -3,10 +3,14 @@
#ifndef PTK_PTK_VK_BUFFER_H_
#define PTK_PTK_VK_BUFFER_H_
#include "ptk_vk/device.h"
#include "ptk_option.h"
#include <vulkan/vulkan_core.h>
PTK_OPTION(uint32_t) vk_find_memory_type(const uint32_t type_filter, const VkMemoryPropertyFlags props);
typedef struct {
VkBuffer buffer;
VkDeviceMemory buffer_memory;

View file

@ -5,6 +5,67 @@
#include "ptk_vk/device.h"
#include "ptk_vk/utils.h"
PTK_OPTION(VkCommandBuffer) vk_begin_single_time_commands(void) {
VkCommandBuffer command_buffer;
VK_TRY(PTK_OPTION_NONE(VkCommandBuffer),
vkAllocateCommandBuffers(
g_dev,
&(VkCommandBufferAllocateInfo){
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.pNext = NULL,
.commandPool = g_command_pool,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1,
},
&command_buffer
)
);
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,
}
)
);
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,
vkQueueSubmit(
g_graphics_queue,
1,
&(VkSubmitInfo){
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = NULL,
.waitSemaphoreCount = 0,
.pWaitSemaphores = NULL,
.pWaitDstStageMask = NULL,
.commandBufferCount = 1,
.pCommandBuffers = &command_buffer,
.signalSemaphoreCount = 0,
.pSignalSemaphores = NULL,
},
VK_NULL_HANDLE
);
);
VK_TRY(false, vkQueueWaitIdle(g_graphics_queue));
vkFreeCommandBuffers(g_dev, g_command_pool, 1, &command_buffer);
return true;
}
VkCommandPool g_command_pool;
bool vk_create_command_pool(void) {

View file

@ -3,8 +3,16 @@
#ifndef PTK_PTK_VK_COMMAND_POOL_H_
#define PTK_PTK_VK_COMMAND_POOL_H_
#include "ptk_option.h"
#include <vulkan/vulkan_core.h>
PTK_OPTION_DEFINE(VkCommandBuffer);
PTK_OPTION(VkCommandBuffer) vk_begin_single_time_commands(void);
bool vk_end_single_time_commands(VkCommandBuffer command_buffer);
extern VkCommandPool g_command_pool;
bool vk_create_command_pool(void);

View file

@ -1,6 +1,7 @@
// Copyright (jacekpoz 2024). Licensed under the EUPL-1.2 or later.
#include "ptk_vk/components.h"
#include "ptk_vk/image.h"
#include "ptk_vk/init.h"
#include "ptk.h"
@ -113,6 +114,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));
@ -224,7 +238,20 @@ void ellipse(const PtkEllipse *ellipse) {
rect(r);
}
void image(const PtkImage *image) {
vk_create_texture_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 component(PtkHandle c) {
if (c == PTK_NULL_HANDLE) {
return;
}
if (!m_update.data[c->id]) {
Vertices vcache = m_vertices_cache.data[c->id];
Indices icache = m_indices_cache.data[c->id];
@ -245,6 +272,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;
}
}
@ -255,6 +285,10 @@ void component(PtkHandle c) {
}
void init_component(PtkHandle c) {
if (c == PTK_NULL_HANDLE) {
return;
}
PTK_LIST_SET(bool, m_update, c->id, true);
PTK_LIST_FOR_EACH(PtkHandle, c->children, child, {
init_component(child);
@ -323,6 +357,8 @@ bool intersects(const PtkHandle component, const PtkPos point) {
return ellipse_intersects(*(PtkEllipse *)component, point);
case PTK_COMPONENT_TYPE_CLICKABLE:
return intersects(component->children.data[0], point);
case PTK_COMPONENT_TYPE_IMAGE:
return rect_intersects(*(PtkRect *)rect_component(component->id, ((PtkImage *)component)->top_left, ((PtkImage *)component)->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);

View file

@ -3,15 +3,37 @@
#include "ptk_vk/descriptors.h"
#include "ptk_vk/device.h"
#include "ptk_vk/image.h"
#include "ptk_vk/sync_objects.h"
#include "ptk_vk/uniform_buffers.h"
#include "ptk_vk/utils.h"
#include "ptk_array.h"
VkDescriptorSetLayout g_descriptor_set_layout;
VkDescriptorPool g_descriptor_pool;
PTK_LIST(VkDescriptorSet) g_descriptor_sets;
PTK_ARRAY_DEFINE(VkDescriptorSetLayoutBinding);
bool vk_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,
@ -19,14 +41,8 @@ bool vk_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,
&g_descriptor_set_layout
@ -36,7 +52,20 @@ bool vk_create_descriptor_set_layout(void) {
return true;
}
PTK_ARRAY_DEFINE(VkDescriptorPoolSize);
bool vk_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,
@ -45,11 +74,8 @@ bool vk_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,
&g_descriptor_pool
@ -60,6 +86,7 @@ bool vk_create_descriptor_pool(void) {
}
PTK_LIST_DEFINE(VkDescriptorSetLayout);
PTK_ARRAY_DEFINE(VkWriteDescriptorSet);
bool vk_create_descriptor_sets(void) {
PTK_LIST(VkDescriptorSetLayout) layouts = PTK_LIST_NEW(VkDescriptorSetLayout, g_max_frames_in_flight);
@ -84,10 +111,8 @@ bool vk_create_descriptor_sets(void) {
);
for (size_t i = 0; i < g_max_frames_in_flight; ++i) {
vkUpdateDescriptorSets(
g_dev,
1,
&(VkWriteDescriptorSet){
PTK_ARRAY(VkWriteDescriptorSet) descriptor_writes = PTK_ARRAY_NEW(VkWriteDescriptorSet, {
(VkWriteDescriptorSet){
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = NULL,
.dstSet = g_descriptor_sets.data[i],
@ -103,6 +128,28 @@ bool vk_create_descriptor_sets(void) {
},
.pTexelBufferView = NULL,
},
(VkWriteDescriptorSet){
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = NULL,
.dstSet = g_descriptor_sets.data[i],
.dstBinding = 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &(VkDescriptorImageInfo){
.sampler = g_texture_sampler,
.imageView = g_texture_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
);

View file

@ -88,7 +88,10 @@ static bool is_device_suitable(const VkPhysicalDevice physical_dev, const VkSurf
PTK_LIST_FREE(queue_families);
return indices_found && extensions_supported && swapchain_adequate;
VkPhysicalDeviceFeatures supported_features;
vkGetPhysicalDeviceFeatures(physical_dev, &supported_features);
return indices_found && extensions_supported && swapchain_adequate && supported_features.samplerAnisotropy;
}
bool vk_create_logical_dev(void) {

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

@ -0,0 +1,385 @@
#include "ptk_vk/image.h"
#include "ptk_vk/buffer.h"
#include "ptk_vk/command_pool.h"
#include "ptk_vk/device.h"
#include "ptk_vk/physical_device.h"
#include "ptk_vk/utils.h"
#include "ptk_log.h"
#include "ptk_option.h"
#include "vulkan/vulkan_core.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
VkImage g_texture_image;
VkDeviceMemory g_texture_image_memory;
VkImageView g_texture_image_view;
VkSampler g_texture_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_opt = vk_begin_single_time_commands();
if (!command_buffer_opt.exists) {
PTK_ERR("failed to create command buffer");
return false;
}
VkCommandBuffer command_buffer = command_buffer_opt.value;
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,
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)) {
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_opt = vk_begin_single_time_commands();
if (!command_buffer_opt.exists) {
PTK_ERR("failed to create command buffer");
return false;
}
VkCommandBuffer command_buffer = command_buffer_opt.value;
vkCmdCopyBufferToImage(
command_buffer,
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)) {
PTK_ERR("failed to end command buffer");
return false;
}
return true;
}
bool vk_create_texture_image(const char *path) {
int texture_width;
int 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 at %s", path);
return false;
}
PTK_OPTION(BufferStuff) staging_buffer_stuff_opt = vk_create_buffer(
image_size,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
);
if (!staging_buffer_stuff_opt.exists) {
PTK_ERR("failed creating staging image buffer");
return false;
}
VkBuffer staging_buffer = staging_buffer_stuff_opt.value.buffer;
VkDeviceMemory staging_buffer_memory = staging_buffer_stuff_opt.value.buffer_memory;
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);
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,
&g_texture_image,
&g_texture_image_memory
)
) {
PTK_ERR("failed creating image");
return false;
}
if (
!transition_image_layout(
g_texture_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, g_texture_image, texture_width, texture_height)) {
PTK_ERR("failed copying buffer to image");
return false;
}
if (
!transition_image_layout(
g_texture_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);
if (!vk_create_texture_image_view()) {
PTK_ERR("failed creating texture image view");
return false;
}
return true;
}
PTK_OPTION(VkImageView) vk_create_image_view(VkImage image, VkFormat format) {
VkImageView ret;
VK_TRY(PTK_OPTION_NONE(VkImageView),
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 = format,
.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,
&ret
)
);
return PTK_OPTION_SOME(VkImageView, ret);
}
bool vk_create_texture_image_view(void) {
PTK_OPTION(VkImageView) image_view_opt = vk_create_image_view(g_texture_image, VK_FORMAT_R8G8B8A8_SRGB);
if (!image_view_opt.exists) {
PTK_ERR("failed to create texture image view");
return false;
}
g_texture_image_view = image_view_opt.value;
return true;
}
bool vk_create_texture_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_FALSE,
.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_texture_sampler
)
);
return true;
}

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

@ -0,0 +1,25 @@
#ifndef PTK_PTK_VK_IMAGE_H_
#define PTK_PTK_VK_IMAGE_H_
#include "ptk_option.h"
#include "vulkan/vulkan_core.h"
extern VkImage g_texture_image;
extern VkDeviceMemory g_texture_image_memory;
extern VkImageView g_texture_image_view;
extern VkSampler g_texture_sampler;
bool vk_create_texture_image(const char *path);
PTK_OPTION_DEFINE(VkImageView);
PTK_OPTION(VkImageView) vk_create_image_view(VkImage image, VkFormat format);
bool vk_create_texture_image_view(void);
bool vk_create_texture_sampler(void);
#endif // PTK_PTK_VK_IMAGE_H_

View file

@ -8,6 +8,7 @@
#include "ptk_vk/components.h"
#include "ptk_vk/descriptors.h"
#include "ptk_vk/device.h"
#include "ptk_vk/image.h"
#include "ptk_vk/instance.h"
#include "ptk_vk/pipeline.h"
#include "ptk_vk/render_pass.h"
@ -55,6 +56,12 @@ bool vk_transfer_vertex_data(void) {
void vk_cleanup(void) {
vk_cleanup_swapchain();
vkDestroySampler(g_dev, g_texture_sampler, NULL);
vkDestroyImageView(g_dev, g_texture_image_view, NULL);
vkDestroyImage(g_dev, g_texture_image, NULL);
vkFreeMemory(g_dev, g_texture_image_memory, NULL);
vkDestroyPipeline(g_dev, g_pipeline, NULL);
vkDestroyPipelineLayout(g_dev, g_pipeline_layout, NULL);

View file

@ -115,6 +115,8 @@ PTK_OPTION(VkShaderModule) create_shader_module(VkDevice dev, const PTK_STRING c
return PTK_OPTION_SOME(VkShaderModule, shader_module);
}
PTK_ARRAY_DEFINE(VkSpecializationMapEntry);
bool vk_create_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");
@ -133,15 +135,27 @@ bool vk_create_pipeline(void) {
return false;
}
const VkSpecializationInfo spec_info = {
.mapEntryCount = 1,
.pMapEntries = &(VkSpecializationMapEntry){
PTK_ARRAY(VkSpecializationMapEntry) 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),
},
});
const VkSpecializationInfo spec_info = {
.mapEntryCount = map_entries.size,
.pMapEntries = map_entries.data,
.dataSize = sizeof(int) * map_entries.size,
.pData = (int []){
PTK_COMPONENT_TYPE_ELLIPSE,
PTK_COMPONENT_TYPE_IMAGE,
},
};
const VkPipelineShaderStageCreateInfo shader_stages[] = {

View file

@ -4,6 +4,7 @@
#include "ptk_vk/backend.h"
#include "ptk_vk/device.h"
#include "ptk_vk/image.h"
#include "ptk_vk/physical_device.h"
#include "ptk_vk/render_pass.h"
#include "ptk_vk/utils.h"
@ -183,35 +184,16 @@ bool vk_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, {
VK_TRY(false,
vkCreateImageView(
g_dev,
&(VkImageViewCreateInfo){
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = NULL,
.flags = 0,
.image = swapchain_image,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = g_swapchain_image_format,
.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,
&m_swapchain_image_views.data[i]
)
);
m_swapchain_image_views.size += 1;
PTK_OPTION(VkImageView) image_view_opt = vk_create_image_view(swapchain_image, g_swapchain_image_format);
if (!image_view_opt.exists) {
PTK_ERR("failed to create swapchain image view #%d", i);
return false;
}
VkImageView image_view = image_view_opt.value;
PTK_LIST_ADD(VkImageView, m_swapchain_image_views, image_view);
})
return true;