to test on windows
This commit is contained in:
parent
b83207e652
commit
a015aa00ef
BIN
assets/boy.jpg
BIN
assets/boy.jpg
Binary file not shown.
|
Before Width: | Height: | Size: 685 KiB |
BIN
assets/boy.png
Normal file
BIN
assets/boy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 MiB |
6
main.cpp
6
main.cpp
@ -51,7 +51,7 @@ int main() {
|
||||
|
||||
Renderer renderer(window);
|
||||
|
||||
texture_manager.load("assets/boy.jpg", renderer);
|
||||
texture_manager.load("assets/boy.png", renderer);
|
||||
|
||||
uint64_t current_time = glfwGetTimerValue();
|
||||
|
||||
@ -72,8 +72,8 @@ int main() {
|
||||
t += dt;
|
||||
updates++;
|
||||
}
|
||||
std::println("Updates: {}", updates);
|
||||
std::println("frame time: {}", ((double) (frame_time) / (double) glfwGetTimerFrequency()));
|
||||
// std::println("Updates: {}", updates);
|
||||
// std::println("frame time: {}", ((double) (frame_time) / (double) glfwGetTimerFrequency()));
|
||||
|
||||
renderer.begin_frame();
|
||||
|
||||
|
||||
@ -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, ©Region);
|
||||
vkCmdCopyBufferToImage(cmd, stagingBuffer, *image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -2,4 +2,4 @@
|
||||
// Created by Vicente Ferrari Smith on 14.02.26.
|
||||
//
|
||||
|
||||
#include "texture_sheet.h"
|
||||
#include "texture_sheet.h"
|
||||
|
||||
@ -17,6 +17,8 @@ struct VSOutput {
|
||||
uint32_t tex_id;
|
||||
};
|
||||
|
||||
Sampler2D textures[];
|
||||
|
||||
static const float2 square[6] = {
|
||||
float2(-0.5, -0.5), // Top-left
|
||||
float2(-0.5, 0.5), // Bottom-left
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user