Selaa lähdekoodia

Render triangle and output to PNG

master
Brian Ho 6 vuotta sitten
vanhempi
commit
136ca6fc5a
2 muutettua tiedostoa jossa 218 lisäystä ja 23 poistoa
  1. 3
    0
      Makefile
  2. 215
    23
      triangle.cc

+ 3
- 0
Makefile Näytä tiedosto

@@ -29,6 +29,8 @@ build: check
deploy: check
ifneq ($(target), local)
@echo Deploying to $(SSH_DUT)...
@scp ${NAME}.vert.spv $(SSH_DUT):~/${NAME}.vert.spv
@scp ${NAME}.frag.spv $(SSH_DUT):~/${NAME}.frag.spv
@scp ${NAME} $(SSH_DUT):~/
endif

@@ -36,6 +38,7 @@ run: check
ifneq ($(target), local)
@echo Running on $(SSH_DUT)...
@ssh $(SSH_DUT) '~/${NAME}'
@echo Copying artifacts back to local device...
@scp $(SSH_DUT):~/${NAME}.png .
else
@echo Running locally...

+ 215
- 23
triangle.cc Näytä tiedosto

@@ -7,8 +7,8 @@
#include <string>
#include <vector>

const uint32_t kWidth = 16;
const uint32_t kHeight = 16;
const uint32_t kWidth = 128;
const uint32_t kHeight = 128;
const VkFormat kVulkanFormat = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
const std::string kVertexShaderPath = "triangle.vert.spv";
const std::string kFragmentShaderPath = "triangle.frag.spv";
@@ -319,40 +319,232 @@ VkPipeline CreateVkPipeline(VkDevice device, VkRenderPass render_pass) {
return pipeline;
}

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);
VkRenderPass render_pass = CreateVkRenderPass(device);
VkPipeline pipeline = CreateVkPipeline(device, render_pass);

// Example code for exporting a PNG.
FILE *f = fopen("triangle.png", "wb");
VkImage CreateVkImage(VkDevice device) {
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 = VK_IMAGE_TILING_OPTIMAL;
create_info.tiling = VK_IMAGE_TILING_LINEAR;
create_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
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;
}

std::vector<uint8_t> pixels(kWidth * kHeight * 4);
for (size_t i = 0; i < kHeight; i++) {
for (size_t j = 0; j < kWidth; j++) {
uint32_t base_index = (i * kWidth * 4) + (j * 4);
pixels[base_index] = 255;
pixels[base_index + 1] = 255;
pixels[base_index + 2] = 0;
pixels[base_index + 3] = 255;
uint32_t FindMemoryType(uint32_t valid_image_memory_types,
VkPhysicalDeviceMemoryProperties device_memory_properties) {
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 &
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) {
return i;
}
}
ERROR("Unable to find suitable memory type index");
}

VkDeviceMemory AllocateAndBindMemory(VkPhysicalDevice physical_device, VkDevice device,
VkImage image) {
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);

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;
}

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;
}

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;
}

void Draw(VkDevice device, VkQueue queue, VkRenderPass render_pass, VkPipeline pipeline,
VkFramebuffer framebuffer, 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);
}

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);

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);
}

result = vkQueueWaitIdle(queue);
if (result != VK_SUCCESS) {
ERROR("Error in waiting for graphics queue to reach idle state: " << result);
}
}

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.data(), kWidth * 4, nullptr) == 0) {
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);
VkRenderPass render_pass = CreateVkRenderPass(device);
VkPipeline pipeline = CreateVkPipeline(device, render_pass);
VkImage image = CreateVkImage(device);
VkDeviceMemory image_memory = AllocateAndBindMemory(physical_device, device, image);
VkImageView image_view = CreateVkImageView(device, image);
VkFramebuffer framebuffer = CreateVkFramebuffer(device, render_pass, image_view);
VkCommandBuffer command_buffer = CreateVkCommandBuffer(device, command_pool);

Draw(device, queue, render_pass, pipeline, framebuffer, command_buffer);

uint8_t* pixels = MapVkDeviceMemory(device, image_memory);
WriteImage(pixels);

return EXIT_SUCCESS;
}

Loading…
Peruuta
Tallenna