Bindless textures

main
noah metz 2024-01-13 16:37:29 -07:00
parent a730ab001b
commit 87141577f9
5 changed files with 151 additions and 103 deletions

@ -10,6 +10,8 @@ OBJECTS = $(addsuffix .o, $(basename $(SOURCES)))
VERT_SPV = $(addsuffix .vert.spv, $(basename $(wildcard shader_src/*.vert)))
FRAG_SPV = $(addsuffix .frag.spv, $(basename $(wildcard shader_src/*.frag)))
export MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=1
.PHONY: all
all: spacegame $(VERT_SPV) $(FRAG_SPV)

@ -1,12 +1,9 @@
#version 450
#extension GL_EXT_buffer_reference : require
struct Object {
mat4 model;
};
layout(buffer_reference, buffer_reference_align = 16) buffer ObjectBuffer {
Object objects[];
mat4 model[];
};
layout( push_constant ) uniform constants {
@ -25,6 +22,6 @@ layout(location = 1) in vec3 inColor;
layout(location = 0) out vec3 fragColor;
void main() {
gl_Position = scene.proj * scene.view * scene.objects.objects[0].model * vec4(inPosition, 1.0);
gl_Position = scene.proj * scene.view * scene.objects.model[0] * vec4(inPosition, 1.0);
fragColor = inColor;
}

@ -4,7 +4,8 @@ layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTex;
layout(location = 0) out vec4 outColor;
layout(set = 1, binding = 0) uniform sampler2D texSampler;
void main() {
outColor = vec4(fragTex, 1.0, 1.0);
outColor = texture(texSampler, fragTex);
}

@ -1,9 +1,15 @@
#version 450
#extension GL_EXT_buffer_reference : require
layout(buffer_reference, buffer_reference_align = 16) buffer ObjectBuffer {
mat4 model[];
};
layout( push_constant ) uniform constants {
mat4 view;
mat4 proj;
} scene_pc;
ObjectBuffer objects;
} scene;
layout(set = 0, binding = 0) uniform SceneUniformBuffer {
mat4 test;
@ -17,7 +23,7 @@ layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTex;
void main() {
gl_Position = scene_pc.proj * scene_pc.view * vec4(inPosition, 1.0);
gl_Position = scene.proj * scene.view * scene.objects.model[1] * vec4(inPosition, 1.0);
fragColor = inColor;
fragTex = inTex;
}

@ -109,8 +109,7 @@ typedef struct MeshStruct {
typedef struct GraphicsPipelineInfoStruct {
VkDescriptorSetLayout scene_layout;
VkDescriptorSetLayoutBinding* descriptor_bindings;
uint32_t descriptor_bindings_count;
VkDescriptorSetLayoutCreateInfo descriptor_info;
uint32_t input_bindings_count;
VkVertexInputBindingDescription* input_bindings;
@ -426,6 +425,7 @@ VkResult get_best_physical_device(VkInstance instance, VkPhysicalDevice* device)
VkPhysicalDeviceProperties properties;
vkGetPhysicalDeviceProperties(devices[i], &properties);
fprintf(stderr, "%d\n", properties.limits.maxPerStageResources);
VkPhysicalDeviceFeatures features;
vkGetPhysicalDeviceFeatures(devices[i], &features);
@ -580,7 +580,7 @@ VkResult create_instance(VkInstance* instance) {
VkResult result = vkCreateInstance(&instance_info, 0, instance);
if(result != VK_SUCCESS) {
fprintf(stderr, "vkCreateInstance: 0x%02x\n", result);
fprintf(stderr, "vkCreateInstance: %s\n", string_VkResult(result));
return result;
}
@ -635,6 +635,7 @@ VkResult create_logical_device(VkPhysicalDevice physical_device, QueueIndices qu
.descriptorBindingVariableDescriptorCount = VK_TRUE,
.descriptorBindingUniformBufferUpdateAfterBind = VK_TRUE,
.descriptorBindingStorageBufferUpdateAfterBind = VK_TRUE,
.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE,
};
VkPhysicalDeviceFeatures device_features = {
@ -1586,34 +1587,28 @@ VkResult create_graphics_pipeline(
out->max_frames_in_flight = max_frames_in_flight;
VkDescriptorSetLayoutCreateInfo descriptor_layout_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = pipeline_info.descriptor_bindings_count,
.pBindings = pipeline_info.descriptor_bindings,
};
VkResult result = vkCreateDescriptorSetLayout(device, &descriptor_layout_info, 0, &out->descriptors_layout);
VkResult result = vkCreateDescriptorSetLayout(device, &pipeline_info.descriptor_info, 0, &out->descriptors_layout);
if(result != VK_SUCCESS) {
return result;
}
if(pipeline_info.descriptor_bindings_count > 0) {
VkDescriptorPoolSize* pool_sizes = malloc(sizeof(VkDescriptorPool)*(1 + pipeline_info.descriptor_bindings_count));
if(pipeline_info.descriptor_info.bindingCount > 0) {
VkDescriptorPoolSize* pool_sizes = malloc(sizeof(VkDescriptorPool)*(1 + pipeline_info.descriptor_info.bindingCount));
if(pool_sizes == 0) {
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
for(uint32_t i = 0; i < pipeline_info.descriptor_bindings_count; i++) {
for(uint32_t i = 0; i < pipeline_info.descriptor_info.bindingCount; i++) {
VkDescriptorPoolSize pool_size = {
.type = pipeline_info.descriptor_bindings[i].descriptorType,
.descriptorCount = pipeline_info.descriptor_bindings[i].descriptorCount*max_frames_in_flight,
.type = pipeline_info.descriptor_info.pBindings[i].descriptorType,
.descriptorCount = pipeline_info.descriptor_info.pBindings[i].descriptorCount*max_frames_in_flight,
};
pool_sizes[i] = pool_size;
}
VkDescriptorPoolCreateInfo pool_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.poolSizeCount = pipeline_info.descriptor_bindings_count,
.poolSizeCount = pipeline_info.descriptor_info.bindingCount,
.maxSets = max_frames_in_flight,
.pPoolSizes = pool_sizes,
.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT,
@ -1816,7 +1811,7 @@ VkResult create_graphics_pipeline(
return VK_SUCCESS;
}
VkResult create_simple_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryProperties memories, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_layout, uint32_t max_frames_in_flight, GraphicsPipeline* out) {
VkResult create_simple_mesh_pipeline(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_layout, uint32_t max_frames_in_flight, GraphicsPipeline* out) {
if(out == NULL) {
return VK_ERROR_VALIDATION_FAILED_EXT;
}
@ -1861,7 +1856,7 @@ VkResult create_simple_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryProp
},
};
VkDescriptorSetLayoutBinding descriptor_bindings[] = {
VkDescriptorSetLayoutBinding set_bindings[] = {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
@ -1871,9 +1866,15 @@ VkResult create_simple_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryProp
},
};
VkDescriptorSetLayoutCreateInfo set_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pBindings = set_bindings,
.bindingCount = sizeof(set_bindings)/sizeof(VkDescriptorSetLayoutBinding),
.pNext = NULL,
};
GraphicsPipelineInfo pipeline_info = {
.descriptor_bindings_count = sizeof(descriptor_bindings)/sizeof(VkDescriptorSetLayoutBinding),
.descriptor_bindings = descriptor_bindings,
.descriptor_info = set_info,
.shader_stages_count = sizeof(shader_stages)/sizeof(VkPipelineShaderStageCreateInfo),
.shader_stages = shader_stages,
.scene_layout = scene_layout,
@ -1883,16 +1884,10 @@ VkResult create_simple_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryProp
.input_attributes_count = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription),
};
GPUPage* memory = NULL;
VkResult result = gpu_page_allocate(device, memories, 100000, 0xFFFFFFFF, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 0, &memory);
if(result != VK_SUCCESS) {
return result;
}
return create_graphics_pipeline(device, extent, render_pass, pipeline_info, max_frames_in_flight, out);
}
VkResult create_texture_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryProperties memories, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_layout, uint32_t max_frames_in_flight, GraphicsPipeline* out) {
VkResult create_texture_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryProperties memories, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_layout, uint32_t max_frames_in_flight, VkCommandPool transfer_pool, VkQueue transfer_queue, VkQueue graphics_queue, VkCommandPool graphics_pool, uint32_t transfer_family, uint32_t graphics_family, GraphicsPipeline* out) {
if(out == NULL) {
return VK_ERROR_VALIDATION_FAILED_EXT;
}
@ -1945,18 +1940,36 @@ VkResult create_texture_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryPro
};
// TODO: use bindless descriptors for textures, so each draw command will bind a large buffer that is indexed by object ID to get the address of the texture in GPU memory
VkDescriptorSetLayoutBinding mesh_set_bindings[] = {
VkDescriptorSetLayoutBinding set_bindings[] = {
{
.binding = 0,
.descriptorCount = 1,
.descriptorCount = 1000,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImmutableSamplers = 0,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
},
};
(void)mesh_set_bindings;
VkDescriptorBindingFlags set_binding_flags[] = {
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT,
};
VkDescriptorSetLayoutBindingFlagsCreateInfo set_flags_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
.bindingCount = sizeof(set_bindings)/sizeof(VkDescriptorSetLayoutBinding),
.pBindingFlags = set_binding_flags,
};
VkDescriptorSetLayoutCreateInfo set_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pBindings = set_bindings,
.bindingCount = sizeof(set_bindings)/sizeof(VkDescriptorSetLayoutBinding),
.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT,
.pNext = &set_flags_info,
};
GraphicsPipelineInfo pipeline_info = {
.descriptor_info = set_info,
.shader_stages_count = sizeof(shader_stages)/sizeof(VkPipelineShaderStageCreateInfo),
.shader_stages = shader_stages,
.scene_layout = scene_layout,
@ -1972,7 +1985,92 @@ VkResult create_texture_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryPro
return result;
}
return create_graphics_pipeline(device, extent, render_pass, pipeline_info, max_frames_in_flight, out);
result = create_graphics_pipeline(device, extent, render_pass, pipeline_info, max_frames_in_flight, out);
if(result != VK_SUCCESS) {
return result;
}
GPUPage* tex_memory = NULL;
result = gpu_page_allocate(device, memories, 100000, 0xFFFFFFFF, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 0, &tex_memory);
if(result != VK_SUCCESS) {
return result;
}
VkExtent2D texture_size = {
.width = 10,
.height = 10,
};
(void)texture_size;
struct __attribute__((__packed__)) texel {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
struct texel WHT = {255, 255, 255, 255};
struct texel BLK = {0, 0, 0, 255};
struct texel RED = {255, 0, 0, 255};
struct texel GRN = {0, 255, 0, 255};
struct texel BLU = {0, 0, 255, 255};
struct texel texture_data[100] = {
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, WHT,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, WHT,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, WHT,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, WHT,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
};
(void)texture_data;
GPUPage* texture_memory = NULL;
result = gpu_page_allocate(device, memories, 100000, 0xFFFFFFFF, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, 0, &texture_memory);
if(result != VK_SUCCESS) {
return result;
}
GPUPage* staging_memory = NULL;
result = gpu_page_allocate(device, memories, 100000, 0xFFFFFFFF, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 0, &staging_memory);
if(result != VK_SUCCESS) {
return result;
}
GPUBuffer staging = {0};
result = gpu_buffer_malloc(device, staging_memory, 100000, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, &staging);
if(result != VK_SUCCESS) {
return result;
}
Texture test_texture = load_texture(device, texture_memory, staging, transfer_pool, transfer_queue, graphics_pool, graphics_queue, texture_size, VK_FORMAT_R8G8B8A8_SRGB, texture_data, transfer_family, graphics_family);
for(uint32_t i = 0; i < out->max_frames_in_flight; i++) {
VkDescriptorImageInfo image_info = {
.sampler = test_texture.sampler,
.imageView = test_texture.view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
};
VkWriteDescriptorSet descriptor_write = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = out->descriptors[i],
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.pBufferInfo = 0,
.pImageInfo = &image_info,
.pTexelBufferView = 0,
};
vkUpdateDescriptorSets(device, 1, &descriptor_write, 0, 0);
}
return VK_SUCCESS;
}
VkResult command_copy_to_buffer(VkDevice device, GPUBuffer staging, VkBuffer destination, void* data, VkDeviceSize size, VkDeviceSize offset, VkCommandPool pool, VkQueue queue) {
@ -2809,64 +2907,6 @@ Object create_texture_mesh_object(GraphicsPipeline* texture_mesh_pipeline, VkPhy
return zero;
}
VkExtent2D texture_size = {
.width = 10,
.height = 10,
};
(void)texture_size;
struct __attribute__((__packed__)) texel {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
struct texel WHT = {255, 255, 255, 255};
struct texel BLK = {0, 0, 0, 255};
struct texel RED = {255, 0, 0, 255};
struct texel GRN = {0, 255, 0, 255};
struct texel BLU = {0, 0, 255, 255};
struct texel texture_data[100] = {
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, WHT,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, WHT,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, WHT,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, WHT,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
};
(void)texture_data;
/*
Texture test_texture = load_texture(device, mesh_memory, transfer_buffer, transfer_pool, transfer_queue, graphics_pool, graphics_queue, texture_size, VK_FORMAT_R8G8B8A8_SRGB, texture_data, transfer_family, graphics_family);
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
VkDescriptorImageInfo image_info = {
.sampler = test_texture.sampler,
.imageView = test_texture.view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
};
VkWriteDescriptorSet descriptor_write = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = sets[i],
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.pBufferInfo = 0,
.pImageInfo = &image_info,
.pTexelBufferView = 0,
};
vkUpdateDescriptorSets(device, 1, &descriptor_write, 0, 0);
}*/ // TODO: bindless textures
return object;
}
@ -2878,7 +2918,7 @@ void main_loop(PlyMesh ply_mesh, GLFWwindow* window, VulkanContext* context) {
GraphicsPipeline simple_mesh_pipeline = {0};
GraphicsPipeline texture_mesh_pipeline = {0};
VkResult result = create_simple_mesh_pipeline(context->device, context->memories, context->swapchain_extent, context->render_pass, scene.descriptor_layout, context->max_frames_in_flight, &simple_mesh_pipeline);
VkResult result = create_simple_mesh_pipeline(context->device, context->swapchain_extent, context->render_pass, scene.descriptor_layout, context->max_frames_in_flight, &simple_mesh_pipeline);
if(result != VK_SUCCESS) {
fprintf(stderr, "failed to create simple mesh material: %s\n", string_VkResult(result));
return;
@ -2890,7 +2930,7 @@ void main_loop(PlyMesh ply_mesh, GLFWwindow* window, VulkanContext* context) {
return;
}
result = create_texture_mesh_pipeline(context->device, context->memories, context->swapchain_extent, context->render_pass, scene.descriptor_layout, context->max_frames_in_flight, &texture_mesh_pipeline);
result = create_texture_mesh_pipeline(context->device, context->memories, context->swapchain_extent, context->render_pass, scene.descriptor_layout, context->max_frames_in_flight, context->transfer_command_pool, context->queues.transfer, context->queues.graphics, context->extra_graphics_pool, context->queue_indices.transfer_family, context->queue_indices.graphics_index, &texture_mesh_pipeline);
if(result != VK_SUCCESS) {
fprintf(stderr, "failed to create texture mesh material\n");
return;
@ -2918,10 +2958,12 @@ void main_loop(PlyMesh ply_mesh, GLFWwindow* window, VulkanContext* context) {
return;
}
mat4* tmp = memory->ptr + buffer.memory->offset;
glm_mat4_identity(*tmp);
vec3 scale = {2.0f, 2.0f, 2.0f};
glm_scale(*tmp, scale);
mat4* model_1 = memory->ptr + buffer.memory->offset;
mat4* model_2 = memory->ptr + buffer.memory->offset + sizeof(mat4);
glm_mat4_identity(*model_1);
glm_translate_x(*model_1, 1.0f);
glm_mat4_identity(*model_2);
glm_translate_x(*model_2, -1.0f);
VkBufferDeviceAddressInfo addr_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,