Skip to content

Commit

Permalink
added swap chain rebuild to enable resize
Browse files Browse the repository at this point in the history
  • Loading branch information
lromor committed Sep 2, 2020
1 parent 1c8f87d commit 3e39315
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 65 deletions.
86 changes: 56 additions & 30 deletions scene.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
//
// This file contains the basic ingredients to render a basic wireframed scene.
// This simple scene allows you to add meshes and a freely "movable" camera.

#include <unistd.h>
#include <iostream>
#include <optional>
Expand All @@ -36,11 +35,11 @@

#define FENCE_TIMEOUT 100000000

Scene::Scene(space::core::VkAppContext *vk_ctx)
: vk_ctx_(vk_ctx), current_buffer_(0),
Scene::Scene(space::core::VkAppContext *vk_ctx, const QueryExtentCallback &fn)
: vk_ctx_(vk_ctx), QueryExtent(fn), current_buffer_(0),
draw_fence_(vk_ctx->device->createFenceUnique(vk::FenceCreateInfo())),
camera_{glm::vec3(0.0f, 0.0f, -15.0f), glm::vec3(0.0f, 2.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)},
projection_matrices_(UpdateProjectionMatrices()) {}
projection_matrices_({0}) {}

void Scene::Init() {
vk::UniqueDevice &device = vk_ctx_->device;
Expand All @@ -67,30 +66,35 @@ void Scene::Init() {
pipeline_cache_ =
device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo());

CreateSwapChain();
CreateSwapChainContext();
}

void Scene::CreateSwapChain() {
void Scene::CreateSwapChainContext() {
vk::PhysicalDevice &physical_device = vk_ctx_->physical_device;
space::core::SurfaceData &surface_data = vk_ctx_->surface_data;
vk::UniqueSurfaceKHR &surface = vk_ctx_->surface;
vk::UniqueDevice &device = vk_ctx_->device;
const uint32_t graphics_queue_family_index = vk_ctx_->graphics_queue_family_index;
const uint32_t present_queue_family_index = vk_ctx_->present_queue_family_index;

const vk::Extent2D extent = QueryExtent();
vk::UniqueCommandBuffer command_buffer =
std::move(
device->allocateCommandBuffersUnique(
vk::CommandBufferAllocateInfo(
*command_pool_, vk::CommandBufferLevel::ePrimary, 1)).front());

// Wait device to be idle before destroying everything
if (swap_chain_context_)
device->waitIdle();

space::core::SwapChainData swap_chain_data(
physical_device, device, *surface_data.surface, surface_data.extent,
physical_device, device, *surface, extent,
vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc,
vk::UniqueSwapchainKHR(), graphics_queue_family_index,
present_queue_family_index);
swap_chain_context_ ? std::move(swap_chain_context_->swap_chain_data.swap_chain) : vk::UniqueSwapchainKHR(),
graphics_queue_family_index, present_queue_family_index);

space::core::DepthBufferData depth_buffer_data(
physical_device, device, vk::Format::eD16Unorm, surface_data.extent);
physical_device, device, vk::Format::eD16Unorm, swap_chain_data.extent);

space::core::BufferData uniform_buffer_data(
physical_device, device, sizeof(glm::mat4x4),
Expand All @@ -100,12 +104,12 @@ void Scene::CreateSwapChain() {
space::core::CreateRenderPass(
device, space::core::PickSurfaceFormat(
physical_device.getSurfaceFormatsKHR(
surface_data.surface.get()))->format, depth_buffer_data.format);
*surface))->format, depth_buffer_data.format);

std::vector<vk::UniqueFramebuffer> framebuffers =
space::core::CreateFramebuffers(
device, render_pass, swap_chain_data.image_views,
depth_buffer_data.image_view, surface_data.extent);
depth_buffer_data.image_view, swap_chain_data.extent);

vk::UniqueDescriptorPool descriptor_pool =
space::core::CreateDescriptorPool(device, { {vk::DescriptorType::eUniformBuffer, 1} });
Expand All @@ -127,6 +131,11 @@ void Scene::CreateSwapChain() {
std::move(descriptor_pool), std::move(descriptor_set)};

swap_chain_context_.reset(swap_chain_context);

for (const auto entity : entities_) {
entity->Register(vk_ctx_, &pipeline_layout_, &swap_chain_context_->render_pass,
&pipeline_cache_);
}
}

void Scene::AddEntity(space::Entity *entity) {
Expand All @@ -145,7 +154,6 @@ void Scene::SubmitRendering() {
const std::vector<vk::UniqueFramebuffer> &framebuffers = swap_chain_context_->framebuffers;
const vk::UniquePipelineLayout &pipeline_layout = pipeline_layout_;
const vk::UniqueDescriptorSet &descriptor_set = swap_chain_context_->descriptor_set;
const space::core::SurfaceData &surface_data = vk_ctx_->surface_data;
const space::core::BufferData &uniform_buffer_data = swap_chain_context_->uniform_buffer_data;

// Update the projection matrices with the current values of camera, model, fov, etc..
Expand All @@ -158,13 +166,27 @@ void Scene::SubmitRendering() {

// Get the index of the next available swapchain image:
vk::UniqueSemaphore imageAcquiredSemaphore = device->createSemaphoreUnique(vk::SemaphoreCreateInfo());
vk::ResultValue<uint32_t> res =
device->acquireNextImageKHR(
swap_chain_data.swap_chain.get(), FENCE_TIMEOUT,
imageAcquiredSemaphore.get(), nullptr);
assert(res.result == vk::Result::eSuccess);
assert(res.value < swap_chain_context_->framebuffers.size());
current_buffer_ = res.value;

bool out_of_date = false;
try {
vk::ResultValue<uint32_t> res =
device->acquireNextImageKHR(
swap_chain_data.swap_chain.get(), FENCE_TIMEOUT,
imageAcquiredSemaphore.get(), nullptr);
if (res.result == vk::Result::eSuboptimalKHR)
out_of_date = true;
assert(res.value < swap_chain_context_->framebuffers.size());
current_buffer_ = res.value;
} catch (vk::OutOfDateKHRError &) {
out_of_date = true;
}
if (out_of_date) {
// Re-create the swapchain context.
CreateSwapChainContext();
// Re-submit rendering
return SubmitRendering();
}

command_buffer->begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlags()));

vk::ClearValue clear_values[2];
Expand All @@ -174,7 +196,7 @@ void Scene::SubmitRendering() {
vk::ClearDepthStencilValue(1.0f, 0);
vk::RenderPassBeginInfo renderPassBeginInfo(
render_pass.get(), framebuffers[current_buffer_].get(),
vk::Rect2D(vk::Offset2D(0, 0), surface_data.extent), 2, clear_values);
vk::Rect2D(vk::Offset2D(0, 0), swap_chain_data.extent), 2, clear_values);

command_buffer->beginRenderPass(
renderPassBeginInfo, vk::SubpassContents::eInline);
Expand All @@ -185,10 +207,10 @@ void Scene::SubmitRendering() {
command_buffer->setViewport(
0, vk::Viewport(
0.0f, 0.0f,
static_cast<float>(surface_data.extent.width),
static_cast<float>(surface_data.extent.height), 0.0f, 1.0f));
static_cast<float>(swap_chain_data.extent.width),
static_cast<float>(swap_chain_data.extent.height), 0.0f, 1.0f));
command_buffer->setScissor(
0, vk::Rect2D(vk::Offset2D(0, 0), surface_data.extent));
0, vk::Rect2D(vk::Offset2D(0, 0), swap_chain_data.extent));

for (const auto entity : entities_) {
entity->Draw(&command_buffer);
Expand All @@ -210,14 +232,18 @@ void Scene::Present() {

while (vk::Result::eTimeout
== device->waitForFences(draw_fence_.get(), VK_TRUE, FENCE_TIMEOUT)) { usleep(1000); }
present_queue.presentKHR(
vk::PresentInfoKHR(0, nullptr, 1, &swap_chain_data.swap_chain.get(), &current_buffer_));
}

try {
present_queue.presentKHR(
vk::PresentInfoKHR(0, nullptr, 1, &swap_chain_data.swap_chain.get(), &current_buffer_));
} catch (vk::OutOfDateKHRError &) {
// Re-create the swapchain context.
CreateSwapChainContext();
}
}

struct Scene::Projection Scene::UpdateProjectionMatrices() {

vk::Extent2D &extent = vk_ctx_->surface_data.extent;
vk::Extent2D extent = swap_chain_context_->swap_chain_data.extent;

float fov = glm::radians(60.0f);
const auto aspect_ratio =
Expand Down
9 changes: 7 additions & 2 deletions scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ struct CameraControls {
// perform rendering of the entities.
class Scene {
public:
Scene(space::core::VkAppContext *context);

typedef std::function<vk::Extent2D()> QueryExtentCallback;

Scene(space::core::VkAppContext *context, const QueryExtentCallback &fn);

void Init();
void AddEntity(space::Entity *entity);
Expand All @@ -52,6 +55,8 @@ class Scene {

private:
space::core::VkAppContext *const vk_ctx_;
const QueryExtentCallback QueryExtent;

vk::UniqueCommandPool command_pool_;
vk::Queue graphics_queue_;
vk::Queue present_queue_;
Expand Down Expand Up @@ -87,7 +92,7 @@ class Scene {
std::unique_ptr<SwapChainContext> swap_chain_context_;

// Creates a new swapchain and returns the old one.
void CreateSwapChain();
void CreateSwapChainContext();

uint32_t current_buffer_;

Expand Down
21 changes: 19 additions & 2 deletions space.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://gnu.org/licenses/gpl-2.0.txt>

#include <X11/X.h>
#include <iostream>
#include <optional>
#include <memory>
Expand All @@ -28,6 +29,13 @@
#include "gamepad.h"
#include "curve.h"

std::optional<vk::Extent2D> get_xlib_window_extent(Display *display, Window window) {
XWindowAttributes attrs;
if (XGetWindowAttributes(display, window, &attrs)) {
return vk::Extent2D(attrs.width, attrs.height);
}
return {};
}

static void gamepad2camera(
CameraControls *camera_controls, const struct EventData &data) {
Expand Down Expand Up @@ -138,7 +146,12 @@ int main(int argc, char *argv[]) {
// as we want to avoid its destruction after
// the display is closed with XCloseDisplay().
{
Scene scene(&vk_ctx);
Scene scene(&vk_ctx, [display, window] () {
XWindowAttributes attrs;
XGetWindowAttributes(display, window, &attrs);
return vk::Extent2D(attrs.width, attrs.height);
});

scene.Init();
ReferenceGrid reference_grid;
Curve curve;
Expand All @@ -148,6 +161,7 @@ int main(int argc, char *argv[]) {
XSelectInput(display, window,
ExposureMask
| KeyPressMask
| StructureNotifyMask
| PointerMotionMask);
XMapWindow(display, window);
XFlush(display);
Expand Down Expand Up @@ -189,8 +203,11 @@ int main(int argc, char *argv[]) {
if (FD_ISSET(x11_fd, &read_fds)) {
while(XPending(display)) {
XNextEvent(display, &e);
if (e.type == KeyPress) {

switch (e.type) {
case KeyPress:
exit = true;
break;
}
}
}
Expand Down
29 changes: 8 additions & 21 deletions vulkan-core.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,6 @@ std::optional<std::pair<uint32_t, uint32_t>> FindGraphicsAndPresentQueueFamilyIn
return {};
}

std::optional<vk::Extent2D> get_xlib_window_extent(Display *display, Window window) {
XWindowAttributes attrs;
if (XGetWindowAttributes(display, window, &attrs)) {
return vk::Extent2D(attrs.width, attrs.height);
}
return {};
}

vk::UniqueDevice CreateDevice(
vk::PhysicalDevice physical_device, uint32_t queue_family_index,
std::vector<std::string> const& extensions = {},
Expand Down Expand Up @@ -321,23 +313,15 @@ namespace space {
// possibly configurable policy.
vk::PhysicalDevice physical_device = instance->enumeratePhysicalDevices().front();

vk::Extent2D extent;
if (auto res = get_xlib_window_extent(display, window)) {
extent = res.value();
} else {
fprintf(stderr, "Coudldn't guess the xlib window extent.");
return {};
}
// Init the surface
struct SurfaceData surface_data = {
vk::UniqueSurfaceKHR surface =
instance->createXlibSurfaceKHRUnique(
vk::XlibSurfaceCreateInfoKHR(vk::XlibSurfaceCreateFlagsKHR(), display, window)),
extent};
vk::XlibSurfaceCreateInfoKHR(vk::XlibSurfaceCreateFlagsKHR(), display, window));

// Find devices for present and graphics.
std::pair<uint32_t, uint32_t> graphics_and_present_queue_family_index;
if (const auto o = FindGraphicsAndPresentQueueFamilyIndex(
physical_device, *surface_data.surface)) {
physical_device, *surface)) {
graphics_and_present_queue_family_index = o.value();
} else {
fprintf(stderr, "Couldn't find suitable Present or Graphics queues.");
Expand All @@ -356,9 +340,12 @@ namespace space {
VULKAN_HPP_DEFAULT_DISPATCHER.init(*device);

return VkAppContext{
std::move(dl), std::move(instance), std::move(device),
std::move(dl),
std::move(instance),
std::move(surface),
std::move(device),
std::move(debug_utils_messenger),
physical_device, std::move(surface_data),
physical_device,
graphics_and_present_queue_family_index.first,
graphics_and_present_queue_family_index.second};
}
Expand Down
19 changes: 11 additions & 8 deletions vulkan-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// limitations under the License.
// Modifications copyright (C) 2020 Leonardo Romor <[email protected]>
//
// This file contains the represents an intermediate interface simplify vulkan.
// This file contains the represents an intermediate interface to simplify vulkan.

#ifndef __SPACE_CORE_H_
#define __SPACE_CORE_H_
Expand Down Expand Up @@ -47,26 +47,28 @@ VULKAN_HPP_INLINE TargetType checked_cast(SourceType value) {

namespace space {
namespace core {
// Vulkan initialization routines
struct SurfaceData {
vk::UniqueSurfaceKHR surface;
vk::Extent2D extent;
};

// Hold the Vulkan configuration data
// such as application name, engine,
// and requested instance layers and extensions.
struct VkAppConfig {
const char *app_name;
const char *engine_name;
std::vector<std::string> instance_layers;
std::vector<std::string> instance_extensions;
};

// Holds the vulkan datacstructures
// used to represent the vulkan implementation,
// instantiation and configuration. It does not
// include any rendering related vullkan calls or
// data structures.
struct VkAppContext {
vk::DynamicLoader dynamic_loader;
vk::UniqueInstance instance;
vk::UniqueSurfaceKHR surface;
vk::UniqueDevice device;
vk::UniqueDebugUtilsMessengerEXT debug_utils_messenger;
vk::PhysicalDevice physical_device;
SurfaceData surface_data;
uint32_t graphics_queue_family_index;
uint32_t present_queue_family_index;
};
Expand All @@ -86,6 +88,7 @@ namespace space {
uint32_t graphics_family_index,
uint32_t present_family_index);
vk::Format color_format;
vk::Extent2D extent;
vk::UniqueSwapchainKHR swap_chain;
std::vector<vk::Image> images;
std::vector<vk::UniqueImageView> image_views;
Expand Down
Loading

0 comments on commit 3e39315

Please sign in to comment.