First attempt for general frame begin/end vulkan functionality.

Test code to draw q3 cinematic.
Bugs to fix when things will settle down a bit: cinematic leaks memory, render_view function invalidates command buffer when multiple scenes are rendered in a single frame.
This commit is contained in:
Artem Kharytoniuk 2017-03-23 23:19:44 +02:00
parent ab66921e14
commit f944034d17
4 changed files with 184 additions and 164 deletions

View File

@ -21,6 +21,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "tr_local.h" #include "tr_local.h"
// VULKAN
#include "vk_init.h"
#include "vk_demo.h"
#include "vk_utils.h"
backEndData_t *backEndData[SMP_FRAMES]; backEndData_t *backEndData[SMP_FRAMES];
backEndState_t backEnd; backEndState_t backEnd;
@ -639,6 +644,9 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
#ifdef __MACOS__ #ifdef __MACOS__
Sys_PumpEvents(); // crutch up the mac's limited buffer queue size Sys_PumpEvents(); // crutch up the mac's limited buffer queue size
#endif #endif
// VULKAN
vulkan_demo->render_view();
} }
@ -727,11 +735,23 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
// VULKAN
vkDestroyImage(get_device(), tr.scratchImage[client]->vk_image, nullptr);
vkDestroyImageView(get_device(), tr.scratchImage[client]->vk_image_view, nullptr);
tr.scratchImage[client]->vk_image = vulkan_demo->create_texture(data, 4, cols, rows, tr.scratchImage[client]->vk_image_view);
vulkan_demo->cinematic_image_view = tr.scratchImage[client]->vk_image_view;
} else { } else {
if (dirty) { if (dirty) {
// otherwise, just subimage upload it so that drivers can tell we are going to be changing // otherwise, just subimage upload it so that drivers can tell we are going to be changing
// it and don't try and do a texture compression // it and don't try and do a texture compression
qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
// VULKAN
vkDestroyImage(get_device(), tr.scratchImage[client]->vk_image, nullptr);
vkDestroyImageView(get_device(), tr.scratchImage[client]->vk_image_view, nullptr);
tr.scratchImage[client]->vk_image = vulkan_demo->create_texture(data, 4, cols, rows, tr.scratchImage[client]->vk_image_view);
vulkan_demo->cinematic_image_view = tr.scratchImage[client]->vk_image_view;
} }
} }
@ -754,6 +774,9 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *
qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows ); qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows );
qglVertex2f (x, y+h); qglVertex2f (x, y+h);
qglEnd (); qglEnd ();
// VULKAN
vulkan_demo->render_cinematic_frame();
} }
void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
@ -918,6 +941,28 @@ const void *RB_DrawBuffer( const void *data ) {
qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
} }
// VULKAN
VkResult result = vkAcquireNextImageKHR(get_device(), get_swapchain(), UINT64_MAX, vulkan_demo->image_acquired, VK_NULL_HANDLE, &vulkan_demo->swapchain_image_index);
check_vk_result(result, "vkAcquireNextImageKHR");
result = vkWaitForFences(get_device(), 1, &vulkan_demo->rendering_finished_fence, VK_FALSE, 1e9);
check_vk_result(result, "vkWaitForFences");
result = vkResetFences(get_device(), 1, &vulkan_demo->rendering_finished_fence);
check_vk_result(result, "vkResetFences");
VkCommandBufferBeginInfo begin_info;
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.pNext = nullptr;
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
begin_info.pInheritanceInfo = nullptr;
extern FILE* logfile;
fprintf(logfile, "begin\n");
fflush(logfile);
result = vkBeginCommandBuffer(vulkan_demo->command_buffer, &begin_info);
check_vk_result(result, "vkBeginCommandBuffer");
return (const void *)(cmd + 1); return (const void *)(cmd + 1);
} }
@ -1032,6 +1077,43 @@ const void *RB_SwapBuffers( const void *data ) {
backEnd.projection2D = qfalse; backEnd.projection2D = qfalse;
// VULKAN
extern FILE* logfile;
fprintf(logfile, "present\n");
fflush(logfile);
VkResult result = vkEndCommandBuffer(vulkan_demo->command_buffer);
check_vk_result(result, "vkEndCommandBuffer");
VkPipelineStageFlags wait_dst_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = nullptr;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &vulkan_demo->image_acquired;
submit_info.pWaitDstStageMask = &wait_dst_stage_mask;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &vulkan_demo->command_buffer;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &vulkan_demo->rendering_finished;
result = vkQueueSubmit(get_queue(), 1, &submit_info, vulkan_demo->rendering_finished_fence);
check_vk_result(result, "vkQueueSubmit");
VkSwapchainKHR swapchain = get_swapchain();
VkPresentInfoKHR present_info;
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.pNext = nullptr;
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = &vulkan_demo->rendering_finished;
present_info.swapchainCount = 1;
present_info.pSwapchains = &swapchain;
present_info.pImageIndices = &vulkan_demo->swapchain_image_index;
present_info.pResults = nullptr;
result = vkQueuePresentKHR(get_queue(), &present_info);
check_vk_result(result, "vkQueuePresentKHR");
return (const void *)(cmd + 1); return (const void *)(cmd + 1);
} }

View File

@ -397,7 +397,4 @@ void RE_RenderScene( const refdef_t *fd ) {
r_firstScenePoly = r_numpolys; r_firstScenePoly = r_numpolys;
tr.frontEndMsec += ri.Milliseconds() - startTime; tr.frontEndMsec += ri.Milliseconds() - startTime;
// VULKAN
vulkan_demo->run_frame();
} }

View File

@ -101,6 +101,8 @@ static VkFormat find_depth_format(VkPhysicalDevice physical_device) {
VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
} }
FILE* logfile;
Vulkan_Demo::Vulkan_Demo(int window_width, int window_height, const SDL_SysWMinfo& window_sys_info) Vulkan_Demo::Vulkan_Demo(int window_width, int window_height, const SDL_SysWMinfo& window_sys_info)
: window_width(window_width) : window_width(window_width)
, window_height(window_height) , window_height(window_height)
@ -110,6 +112,8 @@ Vulkan_Demo::Vulkan_Demo(int window_width, int window_height, const SDL_SysWMinf
get_resource_manager()->initialize(get_device()); get_resource_manager()->initialize(get_device());
create_command_pool(); create_command_pool();
logfile = fopen("debuglog.txt", "w");
image_acquired = get_resource_manager()->create_semaphore(); image_acquired = get_resource_manager()->create_semaphore();
rendering_finished = get_resource_manager()->create_semaphore(); rendering_finished = get_resource_manager()->create_semaphore();
@ -135,17 +139,7 @@ Vulkan_Demo::Vulkan_Demo(int window_width, int window_height, const SDL_SysWMinf
create_pipeline(); create_pipeline();
upload_geometry(); upload_geometry();
update_ubo_descriptor();
{
VkCommandBufferAllocateInfo alloc_info;
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
alloc_info.pNext = nullptr;
alloc_info.commandPool = command_pool;
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
alloc_info.commandBufferCount = 1;
result = vkAllocateCommandBuffers(get_device(), &alloc_info, &render_scene_command_buffer);
check_vk_result(result, "vkAllocateCommandBuffers");
}
{ {
VkCommandBufferAllocateInfo alloc_info; VkCommandBufferAllocateInfo alloc_info;
@ -153,9 +147,8 @@ Vulkan_Demo::Vulkan_Demo(int window_width, int window_height, const SDL_SysWMinf
alloc_info.pNext = nullptr; alloc_info.pNext = nullptr;
alloc_info.commandPool = command_pool; alloc_info.commandPool = command_pool;
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
alloc_info.commandBufferCount = static_cast<uint32_t>(get_swapchain_image_views().size()); alloc_info.commandBufferCount = 1;
render_frame_command_buffers.resize(get_swapchain_image_views().size()); result = vkAllocateCommandBuffers(get_device(), &alloc_info, &command_buffer);
result = vkAllocateCommandBuffers(get_device(), &alloc_info, render_frame_command_buffers.data());
check_vk_result(result, "vkAllocateCommandBuffers"); check_vk_result(result, "vkAllocateCommandBuffers");
} }
} }
@ -482,7 +475,7 @@ void Vulkan_Demo::create_pipeline() {
rasterization_state.depthClampEnable = VK_FALSE; rasterization_state.depthClampEnable = VK_FALSE;
rasterization_state.rasterizerDiscardEnable = VK_FALSE; rasterization_state.rasterizerDiscardEnable = VK_FALSE;
rasterization_state.polygonMode = VK_POLYGON_MODE_FILL; rasterization_state.polygonMode = VK_POLYGON_MODE_FILL;
rasterization_state.cullMode = VK_CULL_MODE_BACK_BIT; rasterization_state.cullMode = VK_CULL_MODE_NONE/*VK_CULL_MODE_BACK_BIT*/;
rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterization_state.depthBiasEnable = VK_FALSE; rasterization_state.depthBiasEnable = VK_FALSE;
rasterization_state.depthBiasConstantFactor = 0.0f; rasterization_state.depthBiasConstantFactor = 0.0f;
@ -600,57 +593,12 @@ void Vulkan_Demo::upload_geometry() {
} }
} }
void Vulkan_Demo::record_render_scene() {
VkCommandBufferInheritanceInfo inheritance_info;
inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
inheritance_info.pNext = nullptr;
inheritance_info.renderPass = render_pass;
inheritance_info.subpass = 0;
inheritance_info.framebuffer = VK_NULL_HANDLE;
inheritance_info.occlusionQueryEnable = VK_FALSE;
inheritance_info.queryFlags = 0;
inheritance_info.pipelineStatistics = 0;
VkCommandBufferBeginInfo begin_info;
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.pNext = nullptr;
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT | VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
begin_info.pInheritanceInfo = &inheritance_info;
VkResult result = vkBeginCommandBuffer(render_scene_command_buffer, &begin_info);
check_vk_result(result, "vkBeginCommandBuffer");
const VkDeviceSize offset = 0;
vkCmdBindVertexBuffers(render_scene_command_buffer, 0, 1, &vertex_buffer, &offset);
vkCmdBindIndexBuffer(render_scene_command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdBindDescriptorSets(render_scene_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set, 0, nullptr);
vkCmdBindPipeline(render_scene_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdDrawIndexed(render_scene_command_buffer, model_indices_count, 1, 0, 0, 0);
result = vkEndCommandBuffer(render_scene_command_buffer);
check_vk_result(result, "vkEndCommandBuffer");
}
void Vulkan_Demo::record_render_frame() { void Vulkan_Demo::record_render_frame() {
VkCommandBufferBeginInfo begin_info; VkBufferCopy region;
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; region.srcOffset = 0;
begin_info.pNext = nullptr; region.dstOffset = 0;
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; region.size = sizeof(Uniform_Buffer_Object);
begin_info.pInheritanceInfo = nullptr; vkCmdCopyBuffer(command_buffer, uniform_staging_buffer, uniform_buffer, 1, &region);
std::array<VkClearValue, 2> clear_values;
clear_values[0].color = {0.3f, 0.2f, 0.1f, 0.0f};
clear_values[1].depthStencil = {1.0, 0};
VkRenderPassBeginInfo render_pass_begin_info;
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_begin_info.pNext = nullptr;
render_pass_begin_info.renderPass = render_pass;
render_pass_begin_info.framebuffer = VK_NULL_HANDLE; // will be initialized later in the recording loop
render_pass_begin_info.renderArea.offset = {0, 0};
render_pass_begin_info.renderArea.extent = {(uint32_t)window_width, (uint32_t)window_height};
render_pass_begin_info.clearValueCount = static_cast<uint32_t>(clear_values.size());
render_pass_begin_info.pClearValues = clear_values.data();
VkBufferMemoryBarrier barrier; VkBufferMemoryBarrier barrier;
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
@ -663,51 +611,42 @@ void Vulkan_Demo::record_render_frame() {
barrier.offset = 0; barrier.offset = 0;
barrier.size = sizeof(Uniform_Buffer_Object); barrier.size = sizeof(Uniform_Buffer_Object);
for (std::size_t i = 0; i < render_frame_command_buffers.size(); i++) { vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0,
VkResult result = vkBeginCommandBuffer(render_frame_command_buffers[i], &begin_info);
check_vk_result(result, "vkBeginCommandBuffer");
VkBufferCopy region;
region.srcOffset = 0;
region.dstOffset = 0;
region.size = sizeof(Uniform_Buffer_Object);
vkCmdCopyBuffer(render_frame_command_buffers[i], uniform_staging_buffer, uniform_buffer, 1, &region);
vkCmdPipelineBarrier(render_frame_command_buffers[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0,
0, nullptr, 1, &barrier, 0, nullptr); 0, nullptr, 1, &barrier, 0, nullptr);
render_pass_begin_info.framebuffer = framebuffers[i]; std::array<VkClearValue, 2> clear_values;
vkCmdBeginRenderPass(render_frame_command_buffers[i], &render_pass_begin_info, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); clear_values[0].color = {0.3f, 0.2f, 0.1f, 0.0f};
vkCmdExecuteCommands(render_frame_command_buffers[i], 1, &render_scene_command_buffer); clear_values[1].depthStencil = {1.0, 0};
vkCmdEndRenderPass(render_frame_command_buffers[i]);
result = vkEndCommandBuffer(render_frame_command_buffers[i]); VkRenderPassBeginInfo render_pass_begin_info;
check_vk_result(result, "vkEndCommandBuffer"); render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
} render_pass_begin_info.pNext = nullptr;
} render_pass_begin_info.renderPass = render_pass;
render_pass_begin_info.framebuffer = framebuffers[swapchain_image_index];
void Vulkan_Demo::update_descriptor_set() { render_pass_begin_info.renderArea.offset = {0, 0};
static auto start_time = std::chrono::high_resolution_clock::now(); render_pass_begin_info.renderArea.extent = {(uint32_t)window_width, (uint32_t)window_height};
auto current_time = std::chrono::high_resolution_clock::now(); render_pass_begin_info.clearValueCount = static_cast<uint32_t>(clear_values.size());
int time = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - start_time).count(); render_pass_begin_info.pClearValues = clear_values.data();
static int image_index = 0;
vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
if (time > 500) {
start_time = current_time; const VkDeviceSize offset = 0;
image_index = 37 + (image_index + 1) % (tr.numImages - 37); vkCmdBindVertexBuffers(command_buffer, 0, 1, &vertex_buffer, &offset);
vkCmdBindIndexBuffer(command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set, 0, nullptr);
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdDrawIndexed(command_buffer, model_indices_count, 1, 0, 0, 0);
vkCmdEndRenderPass(command_buffer);
} }
void Vulkan_Demo::update_ubo_descriptor() {
VkDescriptorBufferInfo buffer_info; VkDescriptorBufferInfo buffer_info;
buffer_info.buffer = uniform_buffer; buffer_info.buffer = uniform_buffer;
buffer_info.offset = 0; buffer_info.offset = 0;
buffer_info.range = sizeof(Uniform_Buffer_Object); buffer_info.range = sizeof(Uniform_Buffer_Object);
VkDescriptorImageInfo image_info; std::array<VkWriteDescriptorSet, 1> descriptor_writes;
image_info.sampler = texture_image_sampler;
image_info.imageView = tr.images[image_index]->vk_image_view;
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
std::array<VkWriteDescriptorSet, 2> descriptor_writes;
descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_writes[0].pNext = nullptr; descriptor_writes[0].pNext = nullptr;
descriptor_writes[0].dstSet = descriptor_set; descriptor_writes[0].dstSet = descriptor_set;
@ -719,26 +658,53 @@ void Vulkan_Demo::update_descriptor_set() {
descriptor_writes[0].pBufferInfo = &buffer_info; descriptor_writes[0].pBufferInfo = &buffer_info;
descriptor_writes[0].pTexelBufferView = nullptr; descriptor_writes[0].pTexelBufferView = nullptr;
descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; vkUpdateDescriptorSets(get_device(), (uint32_t)descriptor_writes.size(), descriptor_writes.data(), 0, nullptr);
descriptor_writes[1].dstSet = descriptor_set; }
descriptor_writes[1].dstBinding = 1;
descriptor_writes[1].dstArrayElement = 0; void Vulkan_Demo::update_image_descriptor(bool cinematic) {
descriptor_writes[1].descriptorCount = 1; VkImageView image_view;
descriptor_writes[1].pNext = nullptr;
descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; if (cinematic) {
descriptor_writes[1].pImageInfo = &image_info; image_view = cinematic_image_view;
descriptor_writes[1].pBufferInfo = nullptr; } else {
descriptor_writes[1].pTexelBufferView = nullptr; static auto start_time = std::chrono::high_resolution_clock::now();
auto current_time = std::chrono::high_resolution_clock::now();
int time = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - start_time).count();
static int image_index = 0;
if (time > 200) {
start_time = current_time;
image_index = (image_index + 1) % tr.numImages;
}
image_view = tr.images[image_index]->vk_image_view;
}
VkDescriptorImageInfo image_info;
image_info.sampler = texture_image_sampler;
image_info.imageView = image_view;
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
std::array<VkWriteDescriptorSet, 1> descriptor_writes;
descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_writes[0].dstSet = descriptor_set;
descriptor_writes[0].dstBinding = 1;
descriptor_writes[0].dstArrayElement = 0;
descriptor_writes[0].descriptorCount = 1;
descriptor_writes[0].pNext = nullptr;
descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptor_writes[0].pImageInfo = &image_info;
descriptor_writes[0].pBufferInfo = nullptr;
descriptor_writes[0].pTexelBufferView = nullptr;
vkUpdateDescriptorSets(get_device(), (uint32_t)descriptor_writes.size(), descriptor_writes.data(), 0, nullptr); vkUpdateDescriptorSets(get_device(), (uint32_t)descriptor_writes.size(), descriptor_writes.data(), 0, nullptr);
} }
void Vulkan_Demo::update_uniform_buffer() { void Vulkan_Demo::update_uniform_buffer(bool cinematic) {
static auto start_time = std::chrono::high_resolution_clock::now(); static auto start_time = std::chrono::high_resolution_clock::now();
auto current_time = std::chrono::high_resolution_clock::now(); auto current_time = std::chrono::high_resolution_clock::now();
float time = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - start_time).count() / 1000.f; float time = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - start_time).count() / 1000.f;
time = 0.0; if (cinematic) time = 0.0;
Uniform_Buffer_Object ubo; Uniform_Buffer_Object ubo;
ubo.model = glm::rotate(glm::mat4(), time * glm::radians(30.0f), glm::vec3(0, 1, 0)); ubo.model = glm::rotate(glm::mat4(), time * glm::radians(30.0f), glm::vec3(0, 1, 0));
@ -761,48 +727,20 @@ void Vulkan_Demo::update_uniform_buffer() {
vkUnmapMemory(get_device(), uniform_staging_buffer_memory); vkUnmapMemory(get_device(), uniform_staging_buffer_memory);
} }
void Vulkan_Demo::run_frame() { void Vulkan_Demo::render_view() {
VkResult result = vkWaitForFences(get_device(), 1, &rendering_finished_fence, VK_FALSE, 1e9); fprintf(logfile, "render_view\n");
check_vk_result(result, "vkWaitForFences"); fflush(logfile);
result = vkResetFences(get_device(), 1, &rendering_finished_fence);
check_vk_result(result, "vkResetFences"); update_image_descriptor(false);
update_descriptor_set();
record_render_scene(); // record secondary command buffer before primary ones
record_render_frame(); record_render_frame();
update_uniform_buffer(false);
update_uniform_buffer(); }
uint32_t swapchain_image_index; void Vulkan_Demo::render_cinematic_frame() {
result = vkAcquireNextImageKHR(get_device(), get_swapchain(), UINT64_MAX, image_acquired, VK_NULL_HANDLE, &swapchain_image_index); fprintf(logfile, "render_cinematic_frame\n");
check_vk_result(result, "vkAcquireNextImageKHR"); fflush(logfile);
VkPipelineStageFlags wait_dst_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; update_image_descriptor(true);
record_render_frame();
VkSubmitInfo submit_info; update_uniform_buffer(true);
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = nullptr;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &image_acquired;
submit_info.pWaitDstStageMask = &wait_dst_stage_mask;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &render_frame_command_buffers[swapchain_image_index];
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &rendering_finished;
result = vkQueueSubmit(get_queue(), 1, &submit_info, rendering_finished_fence);
check_vk_result(result, "vkQueueSubmit");
VkSwapchainKHR swapchain = get_swapchain();
VkPresentInfoKHR present_info;
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.pNext = nullptr;
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = &rendering_finished;
present_info.swapchainCount = 1;
present_info.pSwapchains = &swapchain;
present_info.pImageIndices = &swapchain_image_index;
present_info.pResults = nullptr;
result = vkQueuePresentKHR(get_queue(), &present_info);
check_vk_result(result, "vkQueuePresentKHR");
} }

View File

@ -11,7 +11,8 @@ public:
Vulkan_Demo(int window_width, int window_height, const SDL_SysWMinfo& window_sys_info); Vulkan_Demo(int window_width, int window_height, const SDL_SysWMinfo& window_sys_info);
~Vulkan_Demo(); ~Vulkan_Demo();
void run_frame(); void render_view();
void render_cinematic_frame();
public: public:
void create_command_pool(); void create_command_pool();
@ -30,12 +31,12 @@ public:
void create_pipeline(); void create_pipeline();
void upload_geometry(); void upload_geometry();
void record_render_scene();
void record_render_frame(); void record_render_frame();
void update_descriptor_set(); void update_ubo_descriptor();
void update_uniform_buffer(); void update_image_descriptor(bool cinematic);
void update_uniform_buffer(bool cinematic);
private: public:
const int window_width = 0; const int window_width = 0;
const int window_height = 0; const int window_height = 0;
@ -65,6 +66,8 @@ private:
VkBuffer index_buffer = VK_NULL_HANDLE; VkBuffer index_buffer = VK_NULL_HANDLE;
uint32_t model_indices_count = 0; uint32_t model_indices_count = 0;
std::vector<VkCommandBuffer> render_frame_command_buffers; // command buffer per swapchain image VkCommandBuffer command_buffer = VK_NULL_HANDLE;
VkCommandBuffer render_scene_command_buffer;
uint32_t swapchain_image_index = -1;
VkImageView cinematic_image_view = VK_NULL_HANDLE;
}; };