Как отлаживать ошибки, на которые не указывает уровень проверки?

Пробую Вулкан впервые. Я никогда не занимался графическим программированием. Я знаю, что мне, вероятно, следует начать с чего-то более простого, например, OpenGL, но Vulkan просто почувствовал, что было бы лучше, если бы я немного изучил Vulkan и просто получил бы простой градиентный треугольник приветствия на экране, но я вроде как потерпел неудачу, и я не Я действительно не знаю, как отлаживать что-либо, на что не указывает уровень проверки, потому что я смог понять только основы.

Я написал довольно дрянной код на C++, но мне удалось получить что-то на экране, синий треугольник, что было довольно неплохо, но дело в том, что он должен был быть градиентным, поэтому я пытался переключать вещи здесь и там, но ничего на самом деле такое случается, поэтому мне просто нужна была помощь профессионалов или просто достаточно профессионалов, чтобы указать на мои ошибки.

Я также хотел бы, чтобы вы рассказали мне о любых инструментах или методах для отладки подобных проблем, на которые не указывает уровень проверки.

вот мой дерьмовый код:

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <bitset>

struct Position {float a, b;};
struct Color {float r, g, b;};

struct Vertex {Position pos; Color col;};

Vertex vertices[] = {
    {{0.0, -0.5},{1.0, 0.0, 0.0}},
    {{0.5, 0.5},{0.0, 1.0, 0.0}},
    {{-0.5, 0.5},{0.0, 0.0, 1.0}}
};

int main(){

    glfwInit();
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    uint32_t count; glfwGetRequiredInstanceExtensions(&count);
    VkInstance instance = 0; {
        const char* layers[] = {
            "VK_LAYER_KHRONOS_validation"
        };
        VkInstanceCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
            .enabledLayerCount = 1,
            .ppEnabledLayerNames = layers,
            .enabledExtensionCount = 2,
            .ppEnabledExtensionNames = glfwGetRequiredInstanceExtensions(&count)
        }; vkCreateInstance(&info, 0, &instance);
    }

    VkDevice device = 0;
    VkPhysicalDevice gpu = 0;  {
        {
            uint32_t count = 1; vkEnumeratePhysicalDevices(instance, &count, &gpu);
        }
        float prior[] = {1.0f};
        VkDeviceQueueCreateInfo queues[] = {
            {
                .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
                .queueFamilyIndex = 0,
                .queueCount = 1,
                .pQueuePriorities = prior
            }
        };
        
        const char* exts[] = {
            VK_KHR_SWAPCHAIN_EXTENSION_NAME
        };
        VkDeviceCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
            .queueCreateInfoCount = 1,
            .pQueueCreateInfos = queues,
            .enabledExtensionCount = 1,
            .ppEnabledExtensionNames = exts
        }; vkCreateDevice(gpu, &info, 0, &device);
    }

    GLFWwindow* window = glfwCreateWindow(1000, 600, "tt", 0, 0);
    VkSurfaceKHR surface = 0; {
        glfwCreateWindowSurface(instance, window, 0, &surface);
    }

    VkSwapchainKHR swapchain = 0; {
        VkSurfaceCapabilitiesKHR  capa;
        vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, surface, &capa);
        VkSwapchainCreateInfoKHR info = {
            .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
            .surface = surface,
            .minImageCount = 2,
            .imageFormat = VK_FORMAT_R8G8B8A8_UNORM,
            .imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR,
            .imageExtent = capa.currentExtent,
            .imageArrayLayers = 1,
            .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
            .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
            .preTransform = capa.currentTransform,
            .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
            .presentMode = VK_PRESENT_MODE_FIFO_KHR,
            .clipped = VK_TRUE,
        }; vkCreateSwapchainKHR(device, &info, 0, &swapchain);
    }
    std::vector<VkImageView> swapchain_views;{
        uint32_t count = 0;
        vkGetSwapchainImagesKHR(device, swapchain, &count, 0);
        std::vector<VkImage> swapchain_images(count); swapchain_views.resize(count);
        vkGetSwapchainImagesKHR(device, swapchain, &count, swapchain_images.data());
        VkImageViewCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
            .viewType = VK_IMAGE_VIEW_TYPE_2D,
            .format = VK_FORMAT_R8G8B8A8_UNORM,
            .components = {
                VK_COMPONENT_SWIZZLE_IDENTITY, 
                VK_COMPONENT_SWIZZLE_IDENTITY, 
                VK_COMPONENT_SWIZZLE_IDENTITY, 
                VK_COMPONENT_SWIZZLE_IDENTITY
            },
            .subresourceRange = {
                .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
                .baseMipLevel = 0,
                .levelCount = 1,
                .baseArrayLayer = 0,
                .layerCount = 1
            }
        };
        
        count = 0; for(auto&image:swapchain_images){
            info.image = image;
            vkCreateImageView(device, &info, 0, &swapchain_views[count]);
            count+=1;
        }
    }
    VkRenderPass renderpass = 0; {
        VkAttachmentDescription attachments[] = {
            {
                .format = VK_FORMAT_R8G8B8A8_UNORM,
                .samples = VK_SAMPLE_COUNT_1_BIT,
                .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
                .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
                .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
                .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
                .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
                .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
            }
        };
        VkAttachmentReference ref[] = {
            {
                .attachment = 0,
                .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
            }
        };
        VkSubpassDescription subpasses[] = {
            {
                .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
                .colorAttachmentCount = 1,
                .pColorAttachments = ref,
            }
        };
        VkSubpassDependency dependencies[] = {
            {
                .srcSubpass = VK_SUBPASS_EXTERNAL,
                .dstSubpass = 0,
                .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
                .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
                .srcAccessMask = 0,
                .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
                .dependencyFlags = 0
            }
        };
        VkRenderPassCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
            .attachmentCount = 1,
            .pAttachments = attachments,
            .subpassCount = 1,
            .pSubpasses = subpasses,
            .dependencyCount = 1,
            .pDependencies = dependencies
        }; vkCreateRenderPass(device, &info, 0, &renderpass);
    }
    VkShaderModule vert;{
        std::fstream file("vert.spv", std::ios::in | std::ios::binary);
        std::stringstream oss; oss << file.rdbuf();
        auto str = oss.str();
        VkShaderModuleCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
            .codeSize = str.size(),
            .pCode = reinterpret_cast<const uint32_t*>(str.data())
        }; if (file.is_open()) vkCreateShaderModule(device, &info, 0, &vert); else std::cout<<"no vert shader\n";
    }
    VkShaderModule frag;{
        std::fstream file("frag.spv", std::ios::in | std::ios::binary);
        std::stringstream oss; oss << file.rdbuf();
        auto str = oss.str();
        VkShaderModuleCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
            .codeSize = str.size(),
            .pCode = reinterpret_cast<const uint32_t*>(str.data())
        }; if (file.is_open()) vkCreateShaderModule(device, &info, 0, &frag); else std::cout<<"no frag shader\n";
    }
    VkPipelineLayout layout = 0; {
        VkPipelineLayoutCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO
        }; vkCreatePipelineLayout(device, &info, 0, &layout);
    }
    VkPipeline gfx_pipeline = 0; {
        VkPipelineShaderStageCreateInfo stages[] = {
            {
                .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
                .stage = VkShaderStageFlagBits::VK_SHADER_STAGE_VERTEX_BIT,
                .module = vert,
                .pName = "main"
            },
            {
                .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
                .stage = VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT,
                .module = frag,
                .pName = "main"
            }
        }; VkVertexInputBindingDescription vert_bind_desc[] = {
            {
                .binding = 0,
                .stride = sizeof(Vertex),
                .inputRate = VK_VERTEX_INPUT_RATE_VERTEX
            }
        }; VkVertexInputAttributeDescription vert_attr_desc[]  = {
            {
                .location = 0,
                .binding = 0,
                .format = VK_FORMAT_R32G32_SFLOAT,
                .offset = offsetof(Vertex, pos)
            },
            {
                .location = 1,
                .binding = 0,
                .format = VK_FORMAT_R8G8B8_UNORM,
                .offset = offsetof(Vertex, col)
            }
        }; VkPipelineVertexInputStateCreateInfo vertexInputs[] = {
            {
                .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
                .vertexBindingDescriptionCount = 1,
                .pVertexBindingDescriptions = vert_bind_desc,
                .vertexAttributeDescriptionCount = 2,
                .pVertexAttributeDescriptions = vert_attr_desc
            }
        }; VkPipelineInputAssemblyStateCreateInfo inputAssembly[] = {
            {
                .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
                .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
            }
        }; VkPipelineViewportStateCreateInfo viewport[] = {
            {
                .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
                .viewportCount = 1,
                .scissorCount = 1,
            }
        }; VkPipelineRasterizationStateCreateInfo raterizer[] = {
            {
                .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
                .polygonMode = VK_POLYGON_MODE_FILL,
                .cullMode = VK_CULL_MODE_BACK_BIT,
                .frontFace = VK_FRONT_FACE_CLOCKWISE,
                .lineWidth = 1.
            }
        }; VkPipelineMultisampleStateCreateInfo multisample[] = {
            {
                .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
                .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT
            }
        }; VkPipelineColorBlendAttachmentState colorblendAtt[] = {
            {
                .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
            }
        };
        VkPipelineColorBlendStateCreateInfo colorblend[] = {
            {
                .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
                .logicOp = VK_LOGIC_OP_COPY,
                .attachmentCount = 1,
                .pAttachments = colorblendAtt,
                .blendConstants = {.0, .0, .0, .0}
            }
        }; VkDynamicState dynamic_states[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};

        VkPipelineDynamicStateCreateInfo dynamics[] = {
            {
                .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
                .dynamicStateCount = 2,
                .pDynamicStates = dynamic_states,
            }
        }; 
        VkGraphicsPipelineCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
            .stageCount = 2,
            .pStages = stages,
            .pVertexInputState = vertexInputs,
            .pInputAssemblyState = inputAssembly,
            .pTessellationState = 0,
            .pViewportState = viewport,
            .pRasterizationState = raterizer,
            .pMultisampleState = multisample,
            .pDepthStencilState = 0,
            .pColorBlendState = colorblend,
            .pDynamicState = dynamics,
            .layout = layout,
            .renderPass = renderpass,
            .subpass = 0,
            .basePipelineHandle = 0,
            .basePipelineIndex = -1
        }; vkCreateGraphicsPipelines(device, 0, 1, &info, 0, &gfx_pipeline);
    }
    std::vector<VkFramebuffer> framebuffers(swapchain_views.size()); {
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        VkFramebufferCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
            .renderPass = renderpass,
            .attachmentCount = 1,
            .width = static_cast<uint32_t>(width),
            .height = static_cast<uint32_t>(height),
            .layers = 1
        }; uint32_t count = 0; for(auto&view:swapchain_views){
            info.pAttachments = &view;
            vkCreateFramebuffer(device, &info, 0, &framebuffers[count]);
            count+=1;
        }
    }

    VkQueue queue = 0; {
        vkGetDeviceQueue(device, 0, 0, &queue);
    }
    VkCommandPool pool = 0; {
        VkCommandPoolCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
            .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
            .queueFamilyIndex = 0
        }; vkCreateCommandPool(device, &info, 0, &pool);
    }
    std::vector<VkCommandBuffer> commandBuffers(framebuffers.size()); {
        VkCommandBufferAllocateInfo info = {
            .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
            .commandPool = pool,
            .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
            .commandBufferCount = 2
        }; vkAllocateCommandBuffers(device, &info, commandBuffers.data());
    }

    std::vector<VkFence> imgPresented(framebuffers.size()); {
        VkFenceCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
            .flags = VK_FENCE_CREATE_SIGNALED_BIT
        }; for(auto&fence:imgPresented) vkCreateFence(device, &info, 0, &fence);
    }
    std::vector<VkSemaphore> renderFinished(framebuffers.size());
    std::vector<VkSemaphore> imageAccquired(framebuffers.size()); {
        VkSemaphoreCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO
        };
        for(auto&sema:renderFinished) vkCreateSemaphore(device, &info, 0, &sema);
        for(auto&sema:imageAccquired) vkCreateSemaphore(device, &info, 0, &sema);
    }

    std::unordered_map<VkMemoryPropertyFlags ,const char*> memories(6);{
        memories[VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT] = "DEVICE_LOCAL";
        memories[VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT] = "HOST_VISIBLE";
        memories[VK_MEMORY_PROPERTY_HOST_COHERENT_BIT] = "HOST_COHERENT";
        memories[VK_MEMORY_PROPERTY_HOST_CACHED_BIT] = "HOST_CACHED";
        memories[VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT] = "LAZILY_ALLOCATED";
        memories[VK_MEMORY_PROPERTY_PROTECTED_BIT] = "PROTECTED";

    }
            
    auto types = [&memories](VkMemoryPropertyFlags flag) -> std::string {
        std::string str = ""; uint32_t bit = 1;
        for(uint32_t i = 1; i<32;i++){
            if (flag&bit) str = str + memories[bit] + " ";
            bit=bit<<1;
        }
        return str;
    };

    std::unordered_map<VkMemoryMapFlags, uint32_t> mem_indices; {
        VkPhysicalDeviceMemoryProperties memory_properties;
        vkGetPhysicalDeviceMemoryProperties(gpu, &memory_properties);
        mem_indices.reserve(memory_properties.memoryTypeCount);
        for(int i=0;i<memory_properties.memoryTypeCount;i++){
            mem_indices[memory_properties.memoryTypes[i].propertyFlags]=i;
        } std::cout<<"memory types : \n";

        for(auto&pair:mem_indices){
            std::bitset<sizeof(decltype(memory_properties.memoryTypes[0].propertyFlags))*8> the_bits(pair.first);
            std::cout<<"\tat index|"<<pair.second<<"| : "<<the_bits<<" ( "<<types(pair.first)<<")"<<std::endl;
        }
    }

    VkDeviceMemory vertexMemory = 0;
    VkBuffer vertexBuffer = 0; {
        VkBufferCreateInfo info = {
            .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
            .size = sizeof(vertices),
            .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
            .sharingMode = VK_SHARING_MODE_EXCLUSIVE
        }; vkCreateBuffer(device, &info, 0, &vertexBuffer);
        VkMemoryRequirements requirements;
        vkGetBufferMemoryRequirements(device, vertexBuffer, &requirements);
        if (mem_indices.find(requirements.memoryTypeBits|VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)==mem_indices.end()) goto CLEAN;
        std::cout<<"required : "<<types(requirements.memoryTypeBits)<<std::endl;
        std::cout<<"requesting : "<< types(requirements.memoryTypeBits|VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)<<std::endl;
        VkMemoryAllocateInfo alloc_info = {
            .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
            .allocationSize = requirements.size,
            .memoryTypeIndex = mem_indices[requirements.memoryTypeBits|VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|VK_MEMORY_PROPERTY_HOST_COHERENT_BIT]
        }; vkAllocateMemory(device, &alloc_info, 0, &vertexMemory);
        VkPhysicalDeviceFeatures feat; vkGetPhysicalDeviceFeatures(gpu, &feat);
        
        void* data = 0;

        vkMapMemory(device, vertexMemory, 0, sizeof(vertices), 0, &data);
        memcpy(data, vertices, sizeof(vertices));
        vkUnmapMemory(device, vertexMemory);
        vkBindBufferMemory(device, vertexBuffer, vertexMemory, 0);
    }
    VkRect2D extent; {
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        extent = {
            .offset = {
                .x = 0,
                .y = 0
            },
            .extent = {
                .width = static_cast<uint32_t>(width),
                .height = static_cast<uint32_t>(height)
            }
        };
    }
    VkViewport viewport{
        .x = 0,
        .y = 0,
        .width = (float)extent.extent.width,
        .height = (float)extent.extent.height,
        .minDepth = .0,
        .maxDepth = 1.
    };
    VkRect2D scissor{
        .offset = {0, 0},
        .extent = extent.extent
    };
    uint32_t curr = 0;
    while(!glfwWindowShouldClose(window)){
        glfwPollEvents();
        vkWaitForFences(device, 1, &imgPresented[curr], VK_TRUE, UINT64_MAX);
        vkResetFences(device, 1, &imgPresented[curr]);
        uint32_t imgIndex;
        vkAcquireNextImageKHR(device, swapchain, UINT64_MAX, imageAccquired[curr], 0, &imgIndex);
        vkResetCommandBuffer(commandBuffers[curr], 0);
        VkCommandBufferBeginInfo begin = {
            .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
        }; 
        vkBeginCommandBuffer(commandBuffers[curr], &begin); VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
        VkRenderPassBeginInfo renderpass_info = {
            .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
            .renderPass = renderpass,
            .framebuffer = framebuffers[imgIndex],
            .renderArea = {
                .offset = {0, 0},
                .extent = extent.extent
            },
            .clearValueCount = 1,
            .pClearValues = &clearColor
        }; 
        vkCmdBeginRenderPass(commandBuffers[curr], &renderpass_info, VK_SUBPASS_CONTENTS_INLINE);
        vkCmdBindPipeline(commandBuffers[curr], VK_PIPELINE_BIND_POINT_GRAPHICS, gfx_pipeline);
        vkCmdSetViewport(commandBuffers[curr], 0, 1, &viewport); vkCmdSetScissor(commandBuffers[curr], 0, 1, &scissor);
        VkDeviceSize offsets[]{0};
        vkCmdBindVertexBuffers(commandBuffers[curr], 0, 1, &vertexBuffer, offsets);
        vkCmdDraw(commandBuffers[curr], 3, 1, 0, 0);
        vkCmdEndRenderPass(commandBuffers[curr]);
        vkEndCommandBuffer(commandBuffers[curr]); VkPipelineStageFlags flag = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
        VkSubmitInfo submitInfo{
            .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
            .waitSemaphoreCount = 1,
            .pWaitSemaphores = &imageAccquired[curr],
            .pWaitDstStageMask = &flag,
            .commandBufferCount = 1,
            .pCommandBuffers = &commandBuffers[curr],
            .signalSemaphoreCount = 1,
            .pSignalSemaphores = &renderFinished[curr]
        };
        vkQueueSubmit(queue, 1, &submitInfo, imgPresented[curr]);
        VkPresentInfoKHR presentInfo{
            .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
            .waitSemaphoreCount = 1,
            .pWaitSemaphores = &renderFinished[curr],
            .swapchainCount = 1,
            .pSwapchains = &swapchain,
            .pImageIndices = &imgIndex
        };
        vkQueuePresentKHR(queue, &presentInfo);
        curr = (curr + 1) % 2;
    }

    vkQueueWaitIdle(queue);
    vkDeviceWaitIdle(device);

    vkFreeMemory(device, vertexMemory, 0);

CLEAN:
    vkDestroyBuffer(device, vertexBuffer, 0);
    for(auto&fence:imgPresented) vkDestroyFence(device, fence, 0);
    for(auto&sema:renderFinished) vkDestroySemaphore(device, sema, 0);
    for(auto&sema:imageAccquired) vkDestroySemaphore(device, sema, 0);
    vkFreeCommandBuffers(device, pool, 2, commandBuffers.data());
    vkDestroyCommandPool(device, pool, 0);
    vkDestroyPipeline(device, gfx_pipeline, 0);
    vkDestroyPipelineLayout(device, layout, 0);
    vkDestroyRenderPass(device, renderpass, 0);
    vkDestroyShaderModule(device, vert, 0);
    vkDestroyShaderModule(device, frag, 0);
    for(auto&frame:framebuffers) vkDestroyFramebuffer(device, frame, 0);
    for(auto&view:swapchain_views) vkDestroyImageView(device, view, 0);
    vkDestroySwapchainKHR(device, swapchain, 0);
    vkDestroyDevice(device, 0);
    vkDestroySurfaceKHR(instance, surface, 0);
    glfwDestroyWindow(window);
    vkDestroyInstance(instance, 0);
    glfwTerminate();
    return 0;
}

вершинный шейдер:

#version 450

layout(location = 0) in vec2 inPos;
layout(location = 1) in vec3 inCol;
layout(location = 0) out vec3 fragColor;

void main(){
    gl_Position = vec4(inPos, 0.0, 1.0);
    fragColor = inCol;
}

фрагментный шейдер:

#version 450

layout(location = 0) in vec3 fragColor;
layout(location = 0) out vec4 outCol;

void main(){
    outCol = vec4(fragColor, 1.0);
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш цветотип:

struct Color {float r, g, b;};

не соответствует указанному вами формату вершин:

ВК_FORMAT_R8G8B8_UNORM

Размер вашей фактической структуры цвета составляет 12 байт, но ваш конвейер просматривает только первые 3 байта структуры и преобразует их в цвет на основе значения 0–255 каждого из них.

Поскольку первый цвет имеет красное значение 1,0, он имеет двоичное значение 0x3f800000.
Тем не менее, ваш процессор почти наверняка имеет прямой порядок байтов, поэтому на самом деле он будет располагаться в памяти вот так 0x0000803f, и поскольку вы сказали ему, что формат основан на 8-битном формате, загрузка в графический процессор оставит его с этим прямым порядком байтов. макет.

Когда это будет интерпретировано шейдером, он увидит r: 0x00, g: 0x00, b: 0x80, и поскольку вы используете формат UNORM, который отображается в vec3(0, 0, 0.5) или темно-синий.

Либо измените формат цвета на VK_FORMAT_R3232B32_SFLOAT, либо измените тип Color на struct Color {uint8_t r, g, b, a;};. Я бы избегал искушения использовать uint8_t r, g, b;, даже если вы не собираетесь использовать альфа-канал, почти все, что вы отправляете в графический процессор, должно быть выровнено по 32 битам или, что еще лучше, по 128 битам.

Уровни проверки не смогут вам в этом помочь, поскольку они не смогут узнать, что ваша структура C++ не соответствует предоставляемому вами формату.

Однако такие инструменты, как Renderdoc, отлично подходят для обнаружения подобных вещей, поскольку позволяют напрямую проверять буфер вершин, используемый во время вызова отрисовки. Вы должны предоставить информацию о структуре буфера, что даст вам возможность обнаружить, что данные в буфере не соответствуют отправленному вами формату, и выяснить, почему.

Другие вопросы по теме