Compare commits
4 commits
Author | SHA1 | Date | |
---|---|---|---|
94aed050bd | |||
9d043c3594 | |||
9fba9e626e | |||
97ca8319c3 |
14 changed files with 712 additions and 107 deletions
4
Makefile
4
Makefile
|
@ -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
|
||||
|
|
|
@ -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
BIN
examples/:3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
15
examples/image.c
Normal file
15
examples/image.c
Normal 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
BIN
examples/papiezWasap.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -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__ })
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
outColor = vec4(fragColor, 1.0);
|
||||
if (shapeType == PTK_COMPONENT_TYPE_IMAGE) {
|
||||
outColor = texture(samp, uv);
|
||||
} else {
|
||||
outColor = vec4(fragColor, 1.0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
392
src/ptk_vk/image.c
Normal 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
26
src/ptk_vk/image.h
Normal 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_
|
|
@ -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,45 +1101,68 @@ bool copy_buffer(const VkBuffer src, const VkBuffer dst, const VkDeviceSize size
|
|||
)
|
||||
);
|
||||
|
||||
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,
|
||||
})
|
||||
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){
|
||||
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, 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,
|
||||
});
|
||||
|
||||
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, m_command_pool, 1, &command_buffer);
|
||||
if (!vk_end_single_time_commands(command_buffer.value)) {
|
||||
PTK_ERR("failed to end command buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1109,7 +1173,7 @@ bool transfer_to_buffer(void *src, size_t src_size, VkBuffer buffer) {
|
|||
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);
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
|
Loading…
Reference in a new issue