123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643 |
- #include <png.h>
- #include <vulkan/vulkan.h>
-
- #include <fstream>
- #include <iostream>
- #include <sstream>
- #include <string>
- #include <vector>
-
- const uint32_t kWidth = 256;
- const uint32_t kHeight = 256;
- const VkFormat kVulkanFormat = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
- const std::string kVertexShaderPath = "triangle.vert.spv";
- const std::string kFragmentShaderPath = "triangle.frag.spv";
-
- #define ERROR(message) \
- std::cerr << message << std::endl; \
- std::exit(EXIT_FAILURE)
-
- VkInstance CreateVkInstance() {
- VkApplicationInfo app_info = {};
- app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
- app_info.apiVersion = VK_API_VERSION_1_1;
-
- VkInstanceCreateInfo create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
- create_info.pApplicationInfo = &app_info;
- create_info.enabledExtensionCount = 0;
- create_info.ppEnabledExtensionNames = nullptr;
- create_info.enabledLayerCount = 0;
- create_info.ppEnabledLayerNames = nullptr;
-
- VkInstance instance;
- VkResult result = vkCreateInstance(&create_info, nullptr, &instance);
- if (result != VK_SUCCESS) {
- ERROR("Error creating VkInstance: " << result);
- }
- return instance;
- }
-
- VkPhysicalDevice ChooseVkPhysicalDevice(VkInstance instance) {
- uint32_t device_count = 0;
- VkResult result = vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
- if (result != VK_SUCCESS) {
- ERROR("Error enumerating VkPhysicalDevices: " << result);
- }
- if (device_count == 0) {
- ERROR("No available VkPhysicalDevices");
- }
-
- std::vector<VkPhysicalDevice> devices(device_count);
- result = vkEnumeratePhysicalDevices(instance, &device_count, devices.data());
- if (result != VK_SUCCESS) {
- ERROR("Error fetching VkPhysicalDevices: " << result);
- }
-
- std::cout << "Found " << device_count << " device(s):" << std::endl;
- VkPhysicalDevice chosen_device = VK_NULL_HANDLE;
- for (VkPhysicalDevice device : devices) {
- VkPhysicalDeviceProperties device_props;
- vkGetPhysicalDeviceProperties(device, &device_props);
- std::cout << "\t- " << device_props.deviceName << " [V: " <<
- VK_VERSION_MAJOR(device_props.apiVersion) << "." <<
- VK_VERSION_MINOR(device_props.apiVersion) << "." <<
- VK_VERSION_PATCH(device_props.apiVersion) << "]" << std::endl;
- // Currently, any device with Vulkan API version 1.1 is fine.
- if (chosen_device == VK_NULL_HANDLE && device_props.apiVersion >= VK_API_VERSION_1_1) {
- chosen_device = device;
- }
- }
-
- if (chosen_device == VK_NULL_HANDLE) {
- ERROR("Unable to find suitable VkPhysicalDevice");
- }
- return chosen_device;
- }
-
- uint32_t ChooseDeviceQueueFamilyIndex(VkPhysicalDevice physical_device) {
- uint32_t props_count;
- vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &props_count, nullptr);
- std::vector<VkQueueFamilyProperties> props(props_count);
- vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &props_count, props.data());
-
- // Simply choose the first graphics queue.
- for (size_t i = 0; i < props_count; i++) {
- const VkQueueFamilyProperties& prop = props[i];
- if ((prop.queueFlags & VK_QUEUE_GRAPHICS_BIT) && prop.queueCount > 0) {
- return i;
- }
- }
-
- ERROR("Unable to find suitable queue family");
- }
-
- VkDevice CreateVkDevice(VkPhysicalDevice physical_device, uint32_t device_queue_family_index) {
- VkDeviceQueueCreateInfo queue_create_info = {};
- queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- queue_create_info.queueFamilyIndex = device_queue_family_index;
- queue_create_info.queueCount = 1;
- float queue_priority = 1.0f;
- queue_create_info.pQueuePriorities = &queue_priority;
-
- VkDeviceCreateInfo device_create_info = {};
- device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
- device_create_info.queueCreateInfoCount = 1;
- device_create_info.pQueueCreateInfos = &queue_create_info;
- // Let's not use any device extensions for now.
- device_create_info.enabledExtensionCount = 0;
- device_create_info.ppEnabledExtensionNames = nullptr;
-
- VkDevice device;
- VkResult result = vkCreateDevice(physical_device, &device_create_info, nullptr, &device);
- if (result != VK_SUCCESS) {
- ERROR("Unable to create logical device: " << result);
- }
- return device;
- }
-
- VkQueue GetVkQueue(VkDevice device, uint32_t device_queue_family_index) {
- VkQueue queue;
- vkGetDeviceQueue(device, device_queue_family_index, /*queueIndex*/ 0, &queue);
- return queue;
- }
-
- VkCommandPool CreateVkCommandPool(VkDevice device, uint32_t device_queue_family_index) {
- VkCommandPool command_pool;
- VkCommandPoolCreateInfo create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- create_info.flags = 0;
- create_info.queueFamilyIndex = device_queue_family_index;
- VkResult result = vkCreateCommandPool(device, &create_info, nullptr, &command_pool);
- if (result != VK_SUCCESS) {
- ERROR("Unable to create command pool: " << result);
- }
- return command_pool;
- }
-
- VkCommandBuffer CreateVkCommandBuffer(VkDevice device, VkCommandPool command_pool) {
- VkCommandBufferAllocateInfo allocate_info = {};
- allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- allocate_info.commandPool = command_pool;
- allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- allocate_info.commandBufferCount = 1;
-
- VkCommandBuffer command_buffer;
- VkResult result = vkAllocateCommandBuffers( device, &allocate_info, &command_buffer);
- if (result != VK_SUCCESS) {
- ERROR("Unable to create VkCommandBuffer: " << result);
- }
- return command_buffer;
- }
-
- VkRenderPass CreateVkRenderPass(VkDevice device) {
- VkAttachmentDescription attachment_description = {};
- attachment_description.format = kVulkanFormat;
- attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
- attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attachment_description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- attachment_description.finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-
- VkAttachmentReference attachment_reference = {};
- attachment_reference.attachment = 0;
- attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-
- VkSubpassDescription subpass_description = {};
- subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpass_description.colorAttachmentCount = 1;
- subpass_description.pColorAttachments = &attachment_reference;
-
- VkSubpassDependency subpass_dependency = {};
- subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
- subpass_dependency.dstSubpass = 0;
- subpass_dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- subpass_dependency.srcAccessMask = 0;
- subpass_dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- subpass_dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
- VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
-
- VkRenderPassCreateInfo render_pass_info = {};
- render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- render_pass_info.attachmentCount = 1;
- render_pass_info.pAttachments = &attachment_description;
- render_pass_info.subpassCount = 1;
- render_pass_info.pSubpasses = &subpass_description;
- render_pass_info.dependencyCount = 1;
- render_pass_info.pDependencies = &subpass_dependency;
-
- VkRenderPass render_pass;
- VkResult result = vkCreateRenderPass(device, &render_pass_info, nullptr, &render_pass);
- if (result != VK_SUCCESS) {
- ERROR("Unable to create render pass: " << result);
- }
- return render_pass;
- }
-
- VkShaderModule CreateVkShaderModule(VkDevice device, std::string path) {
- std::ifstream fstream(path);
- if (!fstream) {
- ERROR("Unable to open: " << path);
- }
- std::stringstream buffer;
- buffer << fstream.rdbuf();
- std::string spirv_source = buffer.str();
-
- VkShaderModuleCreateInfo create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
- create_info.codeSize = spirv_source.length();
- create_info.pCode = (const uint32_t*)spirv_source.c_str();
-
- VkShaderModule shader_module;
- VkResult result = vkCreateShaderModule(device, &create_info, nullptr, &shader_module);
- if (result != VK_SUCCESS) {
- ERROR("Unable to create shader module for " << path << ": ");
- }
- return shader_module;
- }
-
- VkPipeline CreateVkPipeline(VkDevice device, VkRenderPass render_pass) {
- VkShaderModule vertex_shader_module = CreateVkShaderModule(device, kVertexShaderPath);
- VkShaderModule fragment_shader_module = CreateVkShaderModule(device, kFragmentShaderPath);
-
- VkPipelineShaderStageCreateInfo vertex_shader_stage_info = {};
- vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
- vertex_shader_stage_info.module = vertex_shader_module;
- vertex_shader_stage_info.pName = "main";
-
- VkPipelineShaderStageCreateInfo fragment_shader_stage_info = {};
- fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
- fragment_shader_stage_info.module = fragment_shader_module;
- fragment_shader_stage_info.pName = "main";
-
- std::vector<VkPipelineShaderStageCreateInfo> shader_stages =
- {vertex_shader_stage_info, fragment_shader_stage_info};
-
- VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
- vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
- vertex_input_info.vertexBindingDescriptionCount = 0;
- vertex_input_info.pVertexBindingDescriptions = nullptr;
- vertex_input_info.vertexAttributeDescriptionCount = 0;
- vertex_input_info.pVertexAttributeDescriptions = nullptr;
-
- VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {};
- input_assembly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
- input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
- input_assembly_info.primitiveRestartEnable = VK_FALSE;
-
- VkViewport viewport = {};
- viewport.x = 0.0f;
- viewport.y = 0.0f;
- viewport.width = (float)kWidth;
- viewport.height = (float)kHeight;
- viewport.minDepth = 0.0f;
- viewport.maxDepth = 1.0f;
-
- VkExtent2D extent = {};
- extent.width = kWidth;
- extent.height = kHeight;
- VkRect2D scissor = {};
- scissor.offset = {0, 0};
- scissor.extent = extent;
-
- VkPipelineViewportStateCreateInfo viewport_state_info = {};
- viewport_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
- viewport_state_info.viewportCount = 1;
- viewport_state_info.pViewports = &viewport;
- viewport_state_info.scissorCount = 1;
- viewport_state_info.pScissors = &scissor;
-
- VkPipelineRasterizationStateCreateInfo rasterization_state_info = {};
- rasterization_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
- rasterization_state_info.depthClampEnable = VK_FALSE;
- rasterization_state_info.rasterizerDiscardEnable = VK_FALSE;
- rasterization_state_info.polygonMode = VK_POLYGON_MODE_FILL;
- rasterization_state_info.lineWidth = 1.0f;
- rasterization_state_info.cullMode = VK_CULL_MODE_BACK_BIT;
- rasterization_state_info.frontFace = VK_FRONT_FACE_CLOCKWISE;
- rasterization_state_info.depthBiasEnable = VK_FALSE;
-
- VkPipelineMultisampleStateCreateInfo multisampling_state_info = {};
- multisampling_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
- multisampling_state_info.sampleShadingEnable = VK_FALSE;
- multisampling_state_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
-
- VkPipelineColorBlendAttachmentState color_blend_attachment_state = {};
- color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
- VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
- color_blend_attachment_state.blendEnable = VK_FALSE;
-
- VkPipelineColorBlendStateCreateInfo color_blend_state = {};
- color_blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
- color_blend_state.logicOpEnable = VK_FALSE;
- color_blend_state.attachmentCount = 1;
- color_blend_state.pAttachments = &color_blend_attachment_state;
-
- VkPipelineLayoutCreateInfo pipeline_layout_create_info = {};
- pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
-
- VkPipelineLayout pipeline_layout;
- VkResult result = vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr,
- &pipeline_layout);
- if (result != VK_SUCCESS) {
- ERROR("Unable to create VkPipelineLayout: " << result);
- }
-
- VkGraphicsPipelineCreateInfo pipeline_create_info = {};
- pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
- pipeline_create_info.stageCount = 2;
- pipeline_create_info.pStages = shader_stages.data();
- pipeline_create_info.pVertexInputState = &vertex_input_info;
- pipeline_create_info.pInputAssemblyState = &input_assembly_info;
- pipeline_create_info.pViewportState = &viewport_state_info;
- pipeline_create_info.pRasterizationState = &rasterization_state_info;
- pipeline_create_info.pMultisampleState = &multisampling_state_info;
- pipeline_create_info.pDepthStencilState = nullptr;
- pipeline_create_info.pColorBlendState = &color_blend_state;
- pipeline_create_info.pDynamicState = nullptr;
- pipeline_create_info.layout = pipeline_layout;
- pipeline_create_info.renderPass = render_pass;
- pipeline_create_info.subpass = 0;
- pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
- pipeline_create_info.basePipelineIndex = -1;
-
- VkPipeline pipeline;
- result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_create_info, nullptr,
- &pipeline);
- if (result != VK_SUCCESS) {
- ERROR("Unable to create VkPipeline: " << result);
- }
- return pipeline;
- }
-
- VkImage CreateVkImage(VkDevice device, VkImageTiling image_tiling, VkImageUsageFlags usage) {
- VkImageCreateInfo create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- create_info.pNext = nullptr;
- create_info.imageType = VK_IMAGE_TYPE_2D;
- create_info.format = kVulkanFormat;
- VkExtent3D extent = {};
- extent.width = kWidth;
- extent.height = kHeight;
- extent.depth = 1;
- create_info.extent = extent;
- create_info.mipLevels = 1;
- create_info.arrayLayers = 1;
- create_info.samples = VK_SAMPLE_COUNT_1_BIT;
- create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- create_info.tiling = image_tiling;
- create_info.usage = usage;
- create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-
- VkImage image;
- VkResult result = vkCreateImage(device, &create_info, nullptr, &image);
- if (result != VK_SUCCESS) {
- ERROR("Unable to create VkImage: " << result);
- }
- return image;
- }
-
- inline VkImage CreateRenderVkImage(VkDevice device) {
- return CreateVkImage(device, VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
- }
-
- inline VkImage CreateScanoutVkImage(VkDevice device) {
- return CreateVkImage(device, VK_IMAGE_TILING_LINEAR,
- VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
- }
-
- uint32_t FindMemoryType(uint32_t valid_image_memory_types,
- VkPhysicalDeviceMemoryProperties device_memory_properties,
- VkMemoryPropertyFlags memory_property_flags) {
- for (uint32_t i = 0; i < device_memory_properties.memoryTypeCount; i++) {
- // We don't care about performance, so just choose the first mappable memory type.
- if ((valid_image_memory_types & (1 << i)) &&
- ((device_memory_properties.memoryTypes[i].propertyFlags & memory_property_flags) ==
- memory_property_flags)) {
- return i;
- }
- }
- ERROR("Unable to find suitable memory type index");
- }
-
- VkDeviceMemory AllocateAndBindMemory(VkPhysicalDevice physical_device, VkDevice device,
- VkImage image, VkMemoryPropertyFlags memory_property_flags) {
- VkMemoryRequirements image_memory_requirements;
- vkGetImageMemoryRequirements(device, image, &image_memory_requirements);
-
- VkPhysicalDeviceMemoryProperties device_memory_properties;
- vkGetPhysicalDeviceMemoryProperties(physical_device, &device_memory_properties);
-
- VkMemoryAllocateInfo memory_allocate_info = {};
- memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- memory_allocate_info.allocationSize = image_memory_requirements.size;
- memory_allocate_info.memoryTypeIndex = FindMemoryType(
- image_memory_requirements.memoryTypeBits, device_memory_properties,
- memory_property_flags);
-
- VkDeviceMemory image_memory;
- VkResult result = vkAllocateMemory(device, &memory_allocate_info, nullptr, &image_memory);
- if (result != VK_SUCCESS) {
- ERROR("Unable to allocate image memory: " << result);
- }
-
- result = vkBindImageMemory(device, image, image_memory, 0);
- if (result != VK_SUCCESS) {
- ERROR("Unable to bind image memory: " << result);
- }
- return image_memory;
- }
-
- inline VkDeviceMemory AllocateAndBindRenderMemory(VkPhysicalDevice physical_device,
- VkDevice device, VkImage image) {
- return AllocateAndBindMemory(physical_device, device, image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
- }
-
- inline VkDeviceMemory AllocateAndBindScanoutMemory(VkPhysicalDevice physical_device,
- VkDevice device, VkImage image) {
- return AllocateAndBindMemory(physical_device, device, image, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
- }
-
- VkImageView CreateVkImageView(VkDevice device, VkImage image) {
- VkImageViewCreateInfo create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- create_info.image = image;
- create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
- create_info.format = kVulkanFormat;
-
- VkComponentMapping component_mapping = {};
- component_mapping.r = VK_COMPONENT_SWIZZLE_IDENTITY;
- component_mapping.b = VK_COMPONENT_SWIZZLE_IDENTITY;
- component_mapping.g = VK_COMPONENT_SWIZZLE_IDENTITY;
- component_mapping.a = VK_COMPONENT_SWIZZLE_IDENTITY;
- create_info.components = component_mapping;
-
- VkImageSubresourceRange subresource_range = {};
- subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- subresource_range.baseMipLevel = 0;
- subresource_range.levelCount = 1;
- subresource_range.baseArrayLayer = 0;
- subresource_range.layerCount = 1;
- create_info.subresourceRange = subresource_range;
-
- VkImageView image_view;
- VkResult result = vkCreateImageView(device, &create_info, nullptr, &image_view);
- if (result != VK_SUCCESS) {
- ERROR("Unable to create VkImageView: " << result);
- }
- return image_view;
- }
-
- VkFramebuffer CreateVkFramebuffer(VkDevice device, VkRenderPass render_pass,
- VkImageView image_view) {
- VkFramebufferCreateInfo create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
- create_info.renderPass = render_pass;
- create_info.attachmentCount = 1;
- create_info.pAttachments = &image_view;
- create_info.width = kWidth;
- create_info.height = kHeight;
- create_info.layers = 1;
-
- VkFramebuffer framebuffer;
- VkResult result = vkCreateFramebuffer(device, &create_info, nullptr, &framebuffer);
- if (result != VK_SUCCESS) {
- ERROR("Unable to create VkFramebuffer: " << result);
- }
- return framebuffer;
- }
-
- void BeginCommandBuffer(VkCommandBuffer command_buffer) {
- VkCommandBufferBeginInfo command_buffer_begin_info = {};
- command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
- VkResult result = vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info);
- if (result != VK_SUCCESS) {
- ERROR("Unable to begin command buffer recording: " << result);
- }
- }
-
- void EndCommandBufferAndSubmit(VkCommandBuffer command_buffer, VkQueue queue) {
- VkResult result = vkEndCommandBuffer(command_buffer);
- if (result != VK_SUCCESS) {
- ERROR("Unable to end command buffer recording: " << result);
- }
-
- VkSubmitInfo submit_info = {};
- submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submit_info.commandBufferCount = 1;
- submit_info.pCommandBuffers = &command_buffer;
- result = vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
- if (result != VK_SUCCESS) {
- ERROR("Error in submitting command buffer to queue: " << result);
- }
- }
-
- void WaitForIdle(VkQueue queue) {
- // In a real application, we should use real synchronization primitives to figure out when the
- // command buffers have been executed. Waiting on an idle queue is simple, but it can cause
- // deadlock if we continue to submit to the queue while we wait for idle.
- VkResult result = vkQueueWaitIdle(queue);
- if (result != VK_SUCCESS) {
- ERROR("Error in waiting for graphics queue to reach idle state: " << result);
- }
- }
-
- void Draw(VkDevice device, VkQueue queue, VkRenderPass render_pass, VkPipeline pipeline,
- VkFramebuffer framebuffer, VkCommandBuffer command_buffer) {
- BeginCommandBuffer(command_buffer);
- VkRenderPassBeginInfo render_pass_begin_info = {};
- render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- render_pass_begin_info.renderPass = render_pass;
- render_pass_begin_info.framebuffer = framebuffer;
- VkRect2D render_area = {};
- render_area.offset = { 0, 0 };
- render_area.extent = { kWidth, kHeight };
- render_pass_begin_info.renderArea = render_area;
- render_pass_begin_info.clearValueCount = 1;
- VkClearValue clear_value = {};
- clear_value.color.float32[0] = 1.0f;
- clear_value.color.float32[1] = 1.0f;
- clear_value.color.float32[2] = 0.0f;
- clear_value.color.float32[3] = 1.0f;
- render_pass_begin_info.pClearValues = &clear_value;
- vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
-
- vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
- vkCmdDraw(command_buffer, 3, 1, 0, 0);
- vkCmdEndRenderPass(command_buffer);
- }
-
- void BlitToScanoutImage(VkQueue queue, VkCommandBuffer command_buffer, VkImage source_image,
- VkImage dest_image) {
- // We need to make sure the writes of the render pass have executed before actually scanning out
- // the rendered image. Also, we need to transition the layout of the scanout image to
- // VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.
- VkImageMemoryBarrier image_memory_barrier = {};
- image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
- image_memory_barrier.pNext = nullptr;
- image_memory_barrier.srcAccessMask = 0;
- image_memory_barrier.dstAccessMask = 0;
- image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
- image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- image_memory_barrier.image = dest_image;
- VkImageSubresourceRange subresource_range = {};
- subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- subresource_range.baseMipLevel = 0;
- subresource_range.levelCount = 1;
- subresource_range.baseArrayLayer = 0;
- subresource_range.layerCount = 1;
- image_memory_barrier.subresourceRange = subresource_range;
- vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
- VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
-
- VkOffset3D blit_start = {};
- blit_start.x = 0;
- blit_start.y = 0;
- blit_start.z = 0;
- VkOffset3D blit_end = {};
- blit_end.x = kWidth;
- blit_end.y = kHeight;
- blit_end.z = 1;
- VkImageSubresourceLayers subresource_layers = {};
- subresource_layers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- subresource_layers.mipLevel = 0;
- subresource_layers.baseArrayLayer = 0;
- subresource_layers.layerCount = 1;
- VkImageBlit image_blit = {};
- image_blit.srcSubresource = subresource_layers;
- image_blit.srcOffsets[0] = blit_start;
- image_blit.srcOffsets[1] = blit_end;
- image_blit.dstSubresource = subresource_layers;
- image_blit.dstOffsets[0] = blit_start;
- image_blit.dstOffsets[1] = blit_end;
- // TODO(brkho): Support multi-planar formats.
- vkCmdBlitImage(command_buffer, source_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dest_image,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_blit, VK_FILTER_NEAREST);
-
- EndCommandBufferAndSubmit(command_buffer, queue);
- }
-
- uint8_t* MapVkDeviceMemory(VkDevice device, VkDeviceMemory image_memory) {
- void* mapped_memory = nullptr;
- VkResult result = vkMapMemory(device, image_memory, 0, kWidth * kHeight * 4, 0, &mapped_memory);
- if (result != VK_SUCCESS) {
- ERROR("Unable to map device memory: " << result);
- }
- return static_cast<uint8_t*>(mapped_memory);
- }
-
- void WriteImage(uint8_t* pixels) {
- FILE *f = fopen("triangle.png", "wb");
-
- png_image image_info = {};
- image_info.version = PNG_IMAGE_VERSION;
- image_info.width = kWidth;
- image_info.height = kHeight;
- image_info.format = PNG_FORMAT_RGBA;
- if (png_image_write_to_stdio(&image_info, f, 0, pixels, kWidth * 4, nullptr) == 0) {
- ERROR("Error writing PNG: " << image_info.message);
- }
-
- fclose(f);
- }
-
- int main() {
- VkInstance instance = CreateVkInstance();
- VkPhysicalDevice physical_device = ChooseVkPhysicalDevice(instance);
- uint32_t device_queue_family_index = ChooseDeviceQueueFamilyIndex(physical_device);
- VkDevice device = CreateVkDevice(physical_device, device_queue_family_index);
- VkQueue queue = GetVkQueue(device, device_queue_family_index);
- VkCommandPool command_pool = CreateVkCommandPool(device, device_queue_family_index);
- VkCommandBuffer command_buffer = CreateVkCommandBuffer(device, command_pool);
-
- VkRenderPass render_pass = CreateVkRenderPass(device);
- VkPipeline pipeline = CreateVkPipeline(device, render_pass);
-
- VkImage render_image = CreateRenderVkImage(device);
- AllocateAndBindRenderMemory(physical_device, device, render_image);
- VkImageView render_image_view = CreateVkImageView(device, render_image);
- VkFramebuffer framebuffer = CreateVkFramebuffer(device, render_pass, render_image_view);
-
- VkImage scanout_image = CreateScanoutVkImage(device);
- VkDeviceMemory scanout_image_memory =
- AllocateAndBindScanoutMemory(physical_device, device, scanout_image);
-
- Draw(device, queue, render_pass, pipeline, framebuffer, command_buffer);
- // Since the render target is created with VK_IMAGE_TILING_OPTIMAL, we need to copy it to a linear
- // format before scanning out.
- BlitToScanoutImage(queue, command_buffer, render_image, scanout_image);
- WaitForIdle(queue);
-
- uint8_t* pixels = MapVkDeviceMemory(device, scanout_image_memory);
- WriteImage(pixels);
-
- return EXIT_SUCCESS;
- }
|