to test on windows

This commit is contained in:
vfs committed 2026-02-20 14:35:31 +01:00
1 parent b83207e652
commit a015aa00ef
10 files changed
+102 -81

No files matched your search

+73 -68
View File
@@ -102,39 +102,33 @@ void Renderer::submit_sprite(glm::vec2 pos, const sprite_t &sprite) {
}
void Renderer::create_pipeline_layout() {
VkDescriptorSetLayoutBinding bindings[2];
bindings[0] = VkDescriptorSetLayoutBinding{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
std::array<VkDescriptorSetLayoutBinding, 1> bindings = {
{
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = nextTextureSlot,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
}
}
};
bindings[1] = {
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT
};
VkDescriptorBindingFlags flags[2] = {
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT,
0 // Standard behavior for the buffer
VkDescriptorBindingFlags flags[1] = {
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT
};
VkDescriptorSetLayoutBindingFlagsCreateInfo layoutFlags{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
.bindingCount = 2,
.bindingCount = 1,
.pBindingFlags = flags
};
VkDescriptorSetLayoutCreateInfo dslci{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pNext = &layoutFlags,
.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT,
.bindingCount = 2,
.pBindings = bindings
// .flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT,
.bindingCount = bindings.size(),
.pBindings = bindings.data()
};
vkCreateDescriptorSetLayout(device, &dslci, nullptr, &descriptor_set_layout);
@@ -316,15 +310,14 @@ VkPipeline Renderer::get_pipeline(PipelineType type) const {
void Renderer::create_descriptor_pool() {
VkDescriptorPoolSize pool_sizes[] = {
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 10 },
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1 },
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nextTextureSlot },
};
VkDescriptorPoolCreateInfo pool_info{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT,
.maxSets = 1,
.poolSizeCount = 2,
.poolSizeCount = 1,
.pPoolSizes = pool_sizes
};
@@ -340,7 +333,7 @@ void Renderer::create_descriptor_pool() {
vkAllocateDescriptorSets(device, &alloc_info, &set);
}
void Renderer::update_bindless_slot(uint32_t slot, VkImageView view, VkSampler sampler) {
void Renderer::update_bindless_slot(uint32_t slot, VkImageView view, VkSampler sampler) const {
VkDescriptorImageInfo image_info{
.sampler = sampler,
.imageView = view,
@@ -350,7 +343,7 @@ void Renderer::update_bindless_slot(uint32_t slot, VkImageView view, VkSampler s
VkWriteDescriptorSet write{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = set,
.dstArrayElement = slot, // Index in the 1000-size array
.dstArrayElement = slot,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &image_info
@@ -359,9 +352,16 @@ void Renderer::update_bindless_slot(uint32_t slot, VkImageView view, VkSampler s
vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
}
Texture Renderer::upload_texture(int w, int h, void* pixels) {
void Renderer::upload_texture(
const int w,
const int h,
const void* pixels,
VkImage *image,
VmaAllocation *allocation,
VkImageView *view,
uint32_t *descriptor_index)
{
VkDeviceSize imageSize = w * h * 4;
Texture res{};
// --- 1. Create Staging Buffer (CPU Visible) ---
VkBuffer stagingBuffer;
@@ -371,9 +371,10 @@ Texture Renderer::upload_texture(int w, int h, void* pixels) {
stagingBufferInfo.size = imageSize;
stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo stagingAllocCreateInfo = {};
stagingAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
stagingAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT;
VmaAllocationCreateInfo stagingAllocCreateInfo = {
.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT,
.usage = VMA_MEMORY_USAGE_AUTO,
};
VmaAllocationInfo stagingResultInfo;
vmaCreateBuffer(allocator, &stagingBufferInfo, &stagingAllocCreateInfo, &stagingBuffer, &stagingAlloc, &stagingResultInfo);
@@ -384,26 +385,30 @@ Texture Renderer::upload_texture(int w, int h, void* pixels) {
// --- 2. Create GPU Image (Device Local / Tiled) ---
VkExtent3D imageExtent = { (uint32_t) w, (uint32_t) h, 1 };
VkImageCreateInfo imageInfo = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
imageInfo.extent = imageExtent;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
VkImageCreateInfo imageInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.format = VK_FORMAT_R8G8B8A8_UNORM,
.extent = imageExtent,
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED
};
VmaAllocationCreateInfo imageAllocCreateInfo = {};
imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
imageAllocCreateInfo.priority = 1.0f; // High priority for textures
VmaAllocationCreateInfo imageAllocCreateInfo = {
.usage = VMA_MEMORY_USAGE_AUTO,
.priority = 1.0f,
};
vmaCreateImage(allocator, &imageInfo, &imageAllocCreateInfo, &res.image, &res.allocation, nullptr);
vmaCreateImage(allocator, &imageInfo, &imageAllocCreateInfo, image, allocation, nullptr);
// --- 3. The Transfer ---
immediate_submit([&](VkCommandBuffer cmd) {
// Transition image from UNDEFINED to TRANSFER_DST
transition_image_layout(cmd, res.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
transition_image_layout(cmd, *image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkBufferImageCopy copyRegion = {};
copyRegion.bufferOffset = 0;
@@ -415,23 +420,21 @@ Texture Renderer::upload_texture(int w, int h, void* pixels) {
copyRegion.imageSubresource.layerCount = 1;
copyRegion.imageExtent = imageExtent;
vkCmdCopyBufferToImage(cmd, stagingBuffer, res.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion);
vkCmdCopyBufferToImage(cmd, stagingBuffer, *image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion);
// Transition image from TRANSFER_DST to SHADER_READ_ONLY
transition_image_layout(cmd, res.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
transition_image_layout(cmd, *image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
});
// Clean up temporary staging resources
vmaDestroyBuffer(allocator, stagingBuffer, stagingAlloc);
// --- 4. Finalize Handles ---
res.view = create_image_view(res.image, imageInfo.format);
*view = create_image_view(*image, imageInfo.format);
// Register in your Bindless Array (Set 0, Binding 0, Index N)
res.descriptor_index = nextTextureSlot++;
update_bindless_slot(res.descriptor_index, res.view, defaultSampler);
return res;
*descriptor_index = nextTextureSlot++;
update_bindless_slot(*descriptor_index, *view, defaultSampler);
}
void Renderer::immediate_submit(std::function<void(VkCommandBuffer)>&& func) const {
@@ -513,25 +516,27 @@ VkImageView Renderer::create_image_view(VkImage image, VkFormat format) const {
}
void Renderer::create_default_sampler() {
VkSamplerCreateInfo samplerInfo{ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
VkSamplerCreateInfo samplerInfo{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
// For crisp pixel art, use NEAREST. For smooth textures, use LINEAR.
.magFilter = VK_FILTER_NEAREST,
.minFilter = VK_FILTER_NEAREST,
// For crisp pixel art, use NEAREST. For smooth textures, use LINEAR.
samplerInfo.magFilter = VK_FILTER_NEAREST;
samplerInfo.minFilter = VK_FILTER_NEAREST;
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
// How to handle "out of bounds" UVs
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
// How to handle "out of bounds" UVs
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
// Optimization: turn off things we don't need for simple 2D
samplerInfo.anisotropyEnable = VK_FALSE;
samplerInfo.maxAnisotropy = 1.0f;
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
samplerInfo.unnormalizedCoordinates = VK_FALSE;
samplerInfo.compareEnable = VK_FALSE;
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
// Optimization: turn off things we don't need for simple 2D
.anisotropyEnable = VK_FALSE,
.maxAnisotropy = 1.0f,
.compareEnable = VK_FALSE,
.compareOp = VK_COMPARE_OP_ALWAYS,
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
.unnormalizedCoordinates = VK_FALSE,
};
vkCreateSampler(device, &samplerInfo, nullptr, &defaultSampler);
}
+10 -3
View File
@@ -203,13 +203,20 @@ struct Renderer {
const Frame &frame,
std::span<const vertex_p2_s2_st2_col4_a1_u32> vertices) const;
VkPipeline get_pipeline(PipelineType type) const;
[[nodiscard]] VkPipeline get_pipeline(PipelineType type) const;
// void bind_material(VkCommandBuffer cmd, uint16_t materialID);
void create_descriptor_pool();
void update_bindless_slot(uint32_t slot, VkImageView view, VkSampler sampler);
void update_bindless_slot(uint32_t slot, VkImageView view, VkSampler sampler) const;
// Returns the resource info so the Manager can store it
Texture upload_texture(int w, int h, void* pixels);
void upload_texture(
int w,
int h,
const void* pixels,
VkImage *image,
VmaAllocation *allocation,
VkImageView *view,
uint32_t *descriptor_index);
template <typename T>
VkPipeline create_graphics_pipeline(
+12 -4
View File
@@ -10,7 +10,7 @@ TextureManager::TextureManager() {
}
uint32_t TextureManager::load(const std::string& path, Renderer &renderer) {
Texture TextureManager::load(const std::string& path, Renderer &renderer) {
// Dedup: Don't load the same file twice!
// if (path_to_id.contains(path)) return path_to_id[path];
@@ -18,13 +18,21 @@ uint32_t TextureManager::load(const std::string& path, Renderer &renderer) {
unsigned char* data = stbi_load(path.c_str(), &w, &h, &ch, STBI_rgb_alpha);
// Tell the renderer to make the GPU version
Texture res = renderer.upload_texture(w, h, data);
Texture res;
res.width = w;
res.height = h;
res.channels = STBI_rgb_alpha;
res.srgb = true;
renderer.upload_texture(w, h, data, &res.image, &res.allocation, &res.view, &res.descriptor_index);
stbi_image_free(data);
uint32_t id = static_cast<uint32_t>(textures.size());
res.id = path;
res.path = path;
res.uploaded = true;
textures[path] = res;
// path_to_id[path] = id;
return id; // This is the textureID for your sprites
return res; // This is the textureID for your sprites
}
+1 -2
View File
@@ -17,7 +17,6 @@ typedef std::string texture_id;
struct Texture {
texture_id id;
std::string path;
uint32_t index;
// NOTE: (vfs) stb_image wants s32 values for the width and height.
int32_t width;
@@ -37,7 +36,7 @@ struct TextureManager {
std::unordered_map<texture_id, Texture> textures;
TextureManager();
uint32_t load(const std::string& path, Renderer &renderer);
Texture load(const std::string& path, Renderer &renderer);
};
inline TextureManager texture_manager;
+1 -1
View File
@@ -2,4 +2,4 @@
// Created by Vicente Ferrari Smith on 14.02.26.
//
#include "texture_sheet.h"
#include "texture_sheet.h"