kiba-engine
texture.c
1 #include <kiba/renderer/vulkan/texture.h>
2 
3 #define STB_IMAGE_IMPLEMENTATION
4 #pragma GCC diagnostic push
5 #pragma GCC diagnostic ignored "-Wsign-conversion"
6 #pragma GCC diagnostic ignored "-Wconversion"
7 #include <stb_image.h>
8 #pragma GCC diagnostic pop
9 #undef STB_IMAGE_IMPLEMENTATION
10 
11 #include <kiba/core/memory.h>
12 #include <kiba/renderer/vulkan/buffer.h>
13 #include <kiba/renderer/vulkan/image.h>
14 
15 static b8 vulkan_texture_sampler_create(vulkan_context *context) {
16  VkPhysicalDeviceProperties properties;
17  vkGetPhysicalDeviceProperties(context->device.physical, &properties);
18  VkSamplerCreateInfo sampler_info = {
19  .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
20  .magFilter = VK_FILTER_LINEAR,
21  .minFilter = VK_FILTER_LINEAR,
22  .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
23  .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
24  .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
25  .anisotropyEnable = VK_TRUE, // could optionally disable if feature not available
26  .maxAnisotropy = properties.limits.maxSamplerAnisotropy, // go hard or go home
27  .borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
28  .unnormalizedCoordinates = VK_FALSE,
29  .compareEnable = VK_FALSE,
30  .compareOp = VK_COMPARE_OP_ALWAYS,
31  .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
32  .mipLodBias = 0.0f,
33  .minLod = 0.0f,
34  .maxLod = 0.0f,
35  };
36  VK_CALL_B8(vkCreateSampler(context->device.logical,
37  &sampler_info,
38  &context->alloc.vulkan_callbacks,
39  &context->texture.sampler));
40  return true;
41 }
42 
43 static void vulkan_texture_sampler_destroy(vulkan_context *context) {
44  vkDestroySampler(context->device.logical, context->texture.sampler, &context->alloc.vulkan_callbacks);
45 }
46 
47 b8 vulkan_texture_create(vulkan_context *context) {
48  const int image_mode = STBI_rgb_alpha;
49  const VkDeviceSize pixel_size = 4; // 4 bytes because we enforce alpha above
50 
51  int width, height, channels;
52  // stbi_uc *pixels = stbi_load("assets/textures/dude.jpg", &width, &height, &channels, image_mode);
53  stbi_uc *pixels = stbi_load("assets/textures/viking_room.png", &width, &height, &channels, image_mode);
54  // stbi_uc *pixels = stbi_load("assets/textures/sphere.png", &width, &height, &channels, image_mode);
55  if (!pixels) {
56  KB_ERROR("failed to load texture data");
57  return false;
58  }
59 
60  VkDeviceSize image_size = (u64) (width * height) * pixel_size;
61  vulkan_buffer staging_buffer;
62  if (!vulkan_buffer_create(context,
63  image_size,
64  VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
65  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
66  &staging_buffer)) {
67  KB_ERROR("could not create staging buffer for texture");
68  return false;
69  }
70 
71  VK_CALL_B8(vkMapMemory(context->device.logical, staging_buffer.memory, 0, image_size, 0, &staging_buffer.mapped));
72  memory_copy(staging_buffer.mapped, pixels, (usize) image_size);
73 
74  vkUnmapMemory(context->device.logical, staging_buffer.memory);
75  stbi_image_free(pixels);
76 
77  if (!vulkan_image_create(
78  context,
79  (u32) width,
80  (u32) height,
81  VK_FORMAT_R8G8B8A8_SRGB,
82  VK_IMAGE_TILING_OPTIMAL, // cannot be changed, to directly access texels in memory use _LINEAR
83  VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
84  VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
85  &context->texture.image)) {
86  KB_ERROR("failed to create vulkan_image");
87  return false;
88  }
89  if (!vulkan_image_transition_layout(context,
90  &context->texture.image,
91  VK_FORMAT_R8G8B8A8_SRGB,
92  VK_IMAGE_LAYOUT_UNDEFINED,
93  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)) {
94  KB_ERROR("failed to transition vulkan_image layout for copying");
95  return false;
96  }
97  if (!vulkan_image_copy_from_buffer(context, &staging_buffer, &context->texture.image, (u32) width, (u32) height)) {
98  KB_ERROR("failed to copy image data from buffer to vulkan_image");
99  return false;
100  }
101  if (!vulkan_image_transition_layout(context,
102  &context->texture.image,
103  VK_FORMAT_R8G8B8A8_SRGB,
104  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
105  VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)) {
106  KB_ERROR("failed to transition vulkan_image layout for rendering");
107  return false;
108  }
109  vulkan_buffer_destroy(context, &staging_buffer);
110 
111  if (!vulkan_image_view_create(context,
112  context->texture.image.image,
113  VK_FORMAT_R8G8B8A8_SRGB,
114  VK_IMAGE_ASPECT_COLOR_BIT,
115  &context->texture.view)) {
116  KB_ERROR("failed to create image view for texture");
117  return false;
118  }
119 
120  return vulkan_texture_sampler_create(context);
121 }
122 
123 void vulkan_texture_destroy(vulkan_context *context) {
124  vulkan_texture_sampler_destroy(context);
125  vulkan_image_view_destroy(context, &context->texture.view);
126  vulkan_image_destroy(context, &context->texture.image);
127 }
void * memory_copy(void *dst, const void *src, usize size)
Copy memory.
Definition: memory.c:83
Lightweight layer between platform and other engine components to enable tracing/monitoring.
#define KB_ERROR(...)
Log entry with error log level.
Definition: log.h:142