Пробую Вулкан впервые. Я никогда не занимался графическим программированием. Я знаю, что мне, вероятно, следует начать с чего-то более простого, например, 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);
}





Ваш цветотип:
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, отлично подходят для обнаружения подобных вещей, поскольку позволяют напрямую проверять буфер вершин, используемый во время вызова отрисовки. Вы должны предоставить информацию о структуре буфера, что даст вам возможность обнаружить, что данные в буфере не соответствуют отправленному вами формату, и выяснить, почему.