pull/1/head
ink-soul 2024-03-26 14:59:23 +08:00
parent 20a30d9192
commit a0b8b66f2b
5 changed files with 510 additions and 354 deletions

View File

@ -120,6 +120,7 @@ namespace vks
}
}
/**
* Get the index of a queue family that supports the requested queue flags
*

View File

@ -132,7 +132,7 @@ void VulkanExampleBase::prepare()
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
// This is the frame buffer attachment to where the multisampled image
// will be resolved to and which will be presented to the swapchain
@ -143,8 +143,15 @@ void VulkanExampleBase::prepare()
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
if (settings.headless)
{
attachments[1].finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
}
else
{
attachments[1].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
}
// Multisampled depth attachment we render to
attachments[2].format = depthFormat;
attachments[2].samples = settings.sampleCount;
@ -214,30 +221,39 @@ void VulkanExampleBase::prepare()
renderPassCI.pDependencies = dependencies.data();
VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderPass));
}
else {
std::array<VkAttachmentDescription, 2> attachments = {};
else
{
std::array<VkAttachmentDescription, 2> attachmentDescriptions = {};
// Color attachment
attachments[0].format = swapChain.colorFormat;
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
attachmentDescriptions[0].format = swapChain.colorFormat;
attachmentDescriptions[0].samples = VK_SAMPLE_COUNT_1_BIT;
attachmentDescriptions[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachmentDescriptions[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachmentDescriptions[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachmentDescriptions[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachmentDescriptions[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
if (settings.headless)
{
attachmentDescriptions[0].finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
}
else
{
attachmentDescriptions[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
}
// Depth attachment
attachments[1].format = depthFormat;
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachmentDescriptions[1].format = depthFormat;
attachmentDescriptions[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachmentDescriptions[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachmentDescriptions[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachmentDescriptions[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachmentDescriptions[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachmentDescriptions[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachmentDescriptions[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference colorReference = {};
colorReference.attachment = 0;
colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference depthReference = {};
depthReference.attachment = 1;
@ -275,13 +291,16 @@ void VulkanExampleBase::prepare()
VkRenderPassCreateInfo renderPassCI{};
renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCI.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassCI.pAttachments = attachments.data();
renderPassCI.attachmentCount = static_cast<uint32_t>(attachmentDescriptions.size());
renderPassCI.pAttachments = attachmentDescriptions.data();
renderPassCI.subpassCount = 1;
renderPassCI.pSubpasses = &subpassDescription;
renderPassCI.dependencyCount = static_cast<uint32_t>(dependencies.size());
renderPassCI.pDependencies = dependencies.data();
VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderPass));
}
/*
@ -299,189 +318,6 @@ void VulkanExampleBase::prepare()
void VulkanExampleBase::fileDropped(std::string filename) { }
void VulkanExampleBase::renderFrame()
{
auto tStart = std::chrono::high_resolution_clock::now();
render();
frameCounter++;
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
frameTimer = (float)tDiff / 1000.0f;
camera.update(frameTimer);
fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f) {
lastFPS = static_cast<uint32_t>((float)frameCounter * (1000.0f / fpsTimer));
fpsTimer = 0.0f;
frameCounter = 0;
}
}
void VulkanExampleBase::renderLoop()
{
destWidth = width;
destHeight = height;
#if defined(_WIN32)
MSG msg;
bool quitMessageReceived = false;
while (!quitMessageReceived) {
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT) {
quitMessageReceived = true;
break;
}
}
if (!IsIconic(window)) {
renderFrame();
}
}
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
while (1)
{
int ident;
int events;
struct android_poll_source* source;
bool destroy = false;
focused = true;
while ((ident = ALooper_pollAll(focused ? 0 : -1, NULL, &events, (void**)&source)) >= 0)
{
if (source != NULL)
{
source->process(androidApp, source);
}
if (androidApp->destroyRequested != 0)
{
LOGD("Android app destroy requested");
destroy = true;
break;
}
}
// App destruction requested
// Exit loop, example will be destroyed in application main
if (destroy)
{
break;
}
// Render frame
if (prepared)
{
auto tStart = std::chrono::high_resolution_clock::now();
render();
frameCounter++;
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
frameTimer = tDiff / 1000.0f;
camera.update(frameTimer);
fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f)
{
lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
fpsTimer = 0.0f;
frameCounter = 0;
}
// Check gamepad state
const float deadZone = 0.0015f;
// todo : check if gamepad is present
// todo : time based and relative axis positions
if (camera.type != Camera::CameraType::firstperson)
{
// Rotate
if (std::abs(gamePadState.axisLeft.x) > deadZone) {
camera.rotate(glm::vec3(0.0f, gamePadState.axisLeft.x * 0.5f, 0.0f));
}
if (std::abs(gamePadState.axisLeft.y) > deadZone) {
camera.rotate(glm::vec3(gamePadState.axisLeft.y * 0.5f, 0.0f, 0.0f));
}
} else {
camera.updatePad(gamePadState.axisLeft, gamePadState.axisRight, frameTimer);
}
}
}
#elif defined(_DIRECT2DISPLAY)
while (!quit)
{
auto tStart = std::chrono::high_resolution_clock::now();
render();
frameCounter++;
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
frameTimer = tDiff / 1000.0f;
camera.update(frameTimer);
fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f)
{
lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
fpsTimer = 0.0f;
frameCounter = 0;
}
}
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
while (!quit)
{
auto tStart = std::chrono::high_resolution_clock::now();
while (wl_display_prepare_read(display) != 0)
wl_display_dispatch_pending(display);
wl_display_flush(display);
wl_display_read_events(display);
wl_display_dispatch_pending(display);
render();
frameCounter++;
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
frameTimer = tDiff / 1000.0f;
camera.update(frameTimer);
fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f)
{
wl_shell_surface_set_title(shell_surface, title.c_str());
lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
fpsTimer = 0.0f;
frameCounter = 0;
}
}
#elif defined(VK_USE_PLATFORM_XCB_KHR)
xcb_flush(connection);
while (!quit)
{
auto tStart = std::chrono::high_resolution_clock::now();
xcb_generic_event_t *event;
while ((event = xcb_poll_for_event(connection)))
{
handleEvent(event);
free(event);
}
render();
frameCounter++;
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
frameTimer = tDiff / 1000.0f;
camera.update(frameTimer);
fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f)
{
xcb_change_property(connection, XCB_PROP_MODE_REPLACE,
window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
title.size(), title.c_str());
lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
fpsTimer = 0.0f;
frameCounter = 0;
}
}
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
[NSApp run];
#endif
// Flush device to make sure all resources can be freed
vkDeviceWaitIdle(device);
}
VulkanExampleBase::VulkanExampleBase()
{
@ -539,9 +375,9 @@ VulkanExampleBase::~VulkanExampleBase()
for (uint32_t i = 0; i < frameBuffers.size(); i++) {
vkDestroyFramebuffer(device, frameBuffers[i], nullptr);
}
vkDestroyImageView(device, depthStencil.view, nullptr);
vkDestroyImage(device, depthStencil.image, nullptr);
vkFreeMemory(device, depthStencil.mem, nullptr);
vkDestroyImageView(device, depthAttachment.view, nullptr);
vkDestroyImage(device, depthAttachment.image, nullptr);
vkFreeMemory(device, depthAttachment.memory, nullptr);
vkDestroyPipelineCache(device, pipelineCache, nullptr);
vkDestroyCommandPool(device, cmdPool, nullptr);
if (settings.multiSampling) {
@ -1822,8 +1658,9 @@ void VulkanExampleBase::setupFrameBuffer()
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCI.samples = settings.sampleCount;
imageCI.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageCI.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &multisampleTarget.color.image));
VkMemoryRequirements memReqs;
@ -1891,65 +1728,140 @@ void VulkanExampleBase::setupFrameBuffer()
imageViewCI.subresourceRange.levelCount = 1;
imageViewCI.subresourceRange.layerCount = 1;
VK_CHECK_RESULT(vkCreateImageView(device, &imageViewCI, nullptr, &multisampleTarget.depth.view));
VkImageCreateInfo image = {};
image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image.pNext = NULL;
image.imageType = VK_IMAGE_TYPE_2D;
image.format = depthFormat;
image.extent = { width, height, 1 };
image.mipLevels = 1;
image.arrayLayers = 1;
image.samples = VK_SAMPLE_COUNT_1_BIT;
image.tiling = VK_IMAGE_TILING_OPTIMAL;
image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
image.flags = 0;
VkMemoryAllocateInfo mem_alloc = {};
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mem_alloc.pNext = NULL;
mem_alloc.allocationSize = 0;
mem_alloc.memoryTypeIndex = 0;
VkImageViewCreateInfo depthStencilView = {};
depthStencilView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
depthStencilView.pNext = NULL;
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
depthStencilView.format = depthFormat;
depthStencilView.flags = 0;
depthStencilView.subresourceRange = {};
depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
depthStencilView.subresourceRange.baseMipLevel = 0;
depthStencilView.subresourceRange.levelCount = 1;
depthStencilView.subresourceRange.baseArrayLayer = 0;
depthStencilView.subresourceRange.layerCount = 1;
VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &depthAttachment.image));
vkGetImageMemoryRequirements(device, depthAttachment.image, &memReqs);
mem_alloc.allocationSize = memReqs.size;
mem_alloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device, &mem_alloc, nullptr, &depthAttachment.memory));
VK_CHECK_RESULT(vkBindImageMemory(device, depthAttachment.image, depthAttachment.memory, 0));
depthStencilView.image = depthAttachment.image;
VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthAttachment.view));
}
else // color attachment when MSAA is no enabled
{
VkFormat colorFormat = VK_FORMAT_B8G8R8A8_SRGB;
VkFormat depthFormat;
vks::tools::getSupportedDepthFormat(physicalDevice, &depthFormat);
// Color attachment
VkImageCreateInfo image = vks::initializers::imageCreateInfo();
image.imageType = VK_IMAGE_TYPE_2D;
image.format = colorFormat;
image.extent.width = width;
image.extent.height = height;
image.extent.depth = 1;
image.mipLevels = 1;
image.arrayLayers = 1;
image.samples = VK_SAMPLE_COUNT_1_BIT;
image.tiling = VK_IMAGE_TILING_OPTIMAL;
image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo();
VkMemoryRequirements memReqs;
VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &colorAttachment.image));
vkGetImageMemoryRequirements(device, colorAttachment.image, &memReqs);
memAlloc.allocationSize = memReqs.size;
memAlloc.memoryTypeIndex = vulkanDevice -> getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &colorAttachment.memory));
VK_CHECK_RESULT(vkBindImageMemory(device, colorAttachment.image, colorAttachment.memory, 0));
VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo();
colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
colorImageView.format = colorFormat;
colorImageView.subresourceRange = {};
colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
colorImageView.subresourceRange.baseMipLevel = 0;
colorImageView.subresourceRange.levelCount = 1;
colorImageView.subresourceRange.baseArrayLayer = 0;
colorImageView.subresourceRange.layerCount = 1;
colorImageView.image = colorAttachment.image;
VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &colorAttachment.view));
// Depth stencil attachment
image.format = depthFormat;
image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &depthAttachment.image));
vkGetImageMemoryRequirements(device, depthAttachment.image, &memReqs);
memAlloc.allocationSize = memReqs.size;
memAlloc.memoryTypeIndex = vulkanDevice -> getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &depthAttachment.memory));
VK_CHECK_RESULT(vkBindImageMemory(device, depthAttachment.image, depthAttachment.memory, 0));
VkImageViewCreateInfo depthStencilView = vks::initializers::imageViewCreateInfo();
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
depthStencilView.format = depthFormat;
depthStencilView.flags = 0;
depthStencilView.subresourceRange = {};
depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (depthFormat >= VK_FORMAT_D16_UNORM_S8_UINT)
depthStencilView.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
depthStencilView.subresourceRange.baseMipLevel = 0;
depthStencilView.subresourceRange.levelCount = 1;
depthStencilView.subresourceRange.baseArrayLayer = 0;
depthStencilView.subresourceRange.layerCount = 1;
depthStencilView.image = depthAttachment.image;
VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthAttachment.view));
}
int i = 0;
if (settings.multiSampling)
{
i = 4;
}
else
{
i = 2;
}
// Depth/Stencil attachment is the same for all frame buffers
VkImageCreateInfo image = {};
image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image.pNext = NULL;
image.imageType = VK_IMAGE_TYPE_2D;
image.format = depthFormat;
image.extent = { width, height, 1 };
image.mipLevels = 1;
image.arrayLayers = 1;
image.samples = VK_SAMPLE_COUNT_1_BIT;
image.tiling = VK_IMAGE_TILING_OPTIMAL;
image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
image.flags = 0;
VkMemoryAllocateInfo mem_alloc = {};
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mem_alloc.pNext = NULL;
mem_alloc.allocationSize = 0;
mem_alloc.memoryTypeIndex = 0;
VkImageViewCreateInfo depthStencilView = {};
depthStencilView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
depthStencilView.pNext = NULL;
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
depthStencilView.format = depthFormat;
depthStencilView.flags = 0;
depthStencilView.subresourceRange = {};
depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
depthStencilView.subresourceRange.baseMipLevel = 0;
depthStencilView.subresourceRange.levelCount = 1;
depthStencilView.subresourceRange.baseArrayLayer = 0;
depthStencilView.subresourceRange.layerCount = 1;
VkMemoryRequirements memReqs;
VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &depthStencil.image));
vkGetImageMemoryRequirements(device, depthStencil.image, &memReqs);
mem_alloc.allocationSize = memReqs.size;
mem_alloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device, &mem_alloc, nullptr, &depthStencil.mem));
VK_CHECK_RESULT(vkBindImageMemory(device, depthStencil.image, depthStencil.mem, 0));
depthStencilView.image = depthStencil.image;
VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthStencil.view));
//
VkImageView attachments[4];
VkImageView attachments[i];
if (settings.multiSampling) {
attachments[0] = multisampleTarget.color.view;
attachments[2] = multisampleTarget.depth.view;
attachments[3] = depthStencil.view;
attachments[3] = depthAttachment.view;
}
else {
attachments[1] = depthStencil.view;
attachments[1] = depthAttachment.view;
attachments[0] = colorAttachment.view;
}
VkFramebufferCreateInfo frameBufferCI{};
@ -1962,16 +1874,35 @@ void VulkanExampleBase::setupFrameBuffer()
frameBufferCI.height = height;
frameBufferCI.layers = 1;
// Create frame buffers for every swap chain image
frameBuffers.resize(swapChain.imageCount);
for (uint32_t i = 0; i < frameBuffers.size(); i++) {
if (settings.multiSampling) {
attachments[1] = swapChain.buffers[i].view;
if (settings.headless && ! settings.multiSampling)
{
VkImageView attachments[2];
attachments[0] = colorAttachment.view;
attachments[1] = depthAttachment.view;
VkFramebufferCreateInfo framebufferCreateInfo = vks::initializers::framebufferCreateInfo();
framebufferCreateInfo.renderPass = renderPass;
framebufferCreateInfo.attachmentCount = 2;
framebufferCreateInfo.pAttachments = attachments;
framebufferCreateInfo.width = width;
framebufferCreateInfo.height = height;
framebufferCreateInfo.layers = 1;
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffer));
}
else
{
// Create frame buffers for every swap chain image
frameBuffers.resize(swapChain.imageCount);
for (uint32_t i = 0; i < frameBuffers.size(); i++) {
if (settings.multiSampling) {
attachments[1] = swapChain.buffers[i].view;
}
else {
attachments[0] = swapChain.buffers[i].view;
}
VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCI, nullptr, &frameBuffers[i]));
}
else {
attachments[0] = swapChain.buffers[i].view;
}
VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCI, nullptr, &frameBuffers[i]));
}
}
@ -1994,9 +1925,9 @@ void VulkanExampleBase::windowResize()
vkDestroyImage(device, multisampleTarget.depth.image, nullptr);
vkFreeMemory(device, multisampleTarget.depth.memory, nullptr);
}
vkDestroyImageView(device, depthStencil.view, nullptr);
vkDestroyImage(device, depthStencil.image, nullptr);
vkFreeMemory(device, depthStencil.mem, nullptr);
vkDestroyImageView(device, depthAttachment.view, nullptr);
vkDestroyImage(device, depthAttachment.image, nullptr);
vkFreeMemory(device, depthAttachment.memory, nullptr);
for (uint32_t i = 0; i < frameBuffers.size(); i++) {
vkDestroyFramebuffer(device, frameBuffers[i], nullptr);
}

View File

@ -58,16 +58,7 @@
class VulkanExampleBase
{
private:
float fpsTimer = 0.0f;
uint32_t frameCounter = 0;
uint32_t destWidth;
uint32_t destHeight;
bool resizing = false;
void handleMouseMove(int32_t x, int32_t y);
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
VkDebugReportCallbackEXT debugReportCallback;
public:
struct MultisampleTarget {
struct {
VkImage image;
@ -80,6 +71,17 @@ private:
VkDeviceMemory memory;
} depth;
} multisampleTarget;
private:
uint32_t destWidth;
uint32_t destHeight;
bool resizing = false;
void handleMouseMove(int32_t x, int32_t y);
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
VkDebugReportCallbackEXT debugReportCallback;
protected:
VkInstance instance;
VkPhysicalDevice physicalDevice;
@ -90,6 +92,7 @@ protected:
vks::VulkanDevice *vulkanDevice;
VkQueue queue;
VkFormat depthFormat;
VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
VkCommandPool cmdPool;
VkRenderPass renderPass;
std::vector<VkFramebuffer>frameBuffers;
@ -106,25 +109,31 @@ public:
bool prepared = false;
uint32_t width = 1280;
uint32_t height = 720;
float frameTimer = 1.0f;
Camera camera;
glm::vec2 mousePos;
bool paused = false;
uint32_t lastFPS = 0;
struct Settings {
bool validation = true;
bool fullscreen = false;
bool vsync = false;
bool multiSampling = true;
bool rotateModel = false;
bool enableSaveToImageSequeue = false;
uint32_t outputFrameCount = 50;
bool takeScreenShot = false;
bool headless = true;
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT;
} settings;
struct DepthStencil {
struct FrameBufferAttachment {
VkImage image;
VkDeviceMemory mem;
VkDeviceMemory memory;
VkImageView view;
} depthStencil;
};
FrameBufferAttachment colorAttachment, depthAttachment;
VkFramebuffer framebuffer;
struct GamePadState {
glm::vec2 axisLeft = glm::vec2(0.0f);

View File

@ -189,6 +189,9 @@ PlumageRender::PlumageRender()
VK_CHECK_RESULT(vkEndCommandBuffer(currentCB));
}
}
@ -529,6 +532,7 @@ PlumageRender::PlumageRender()
rasterizationStateCI.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizationStateCI.lineWidth = 1.0f;
VkPipelineColorBlendAttachmentState blendAttachmentState{};
blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
@ -558,6 +562,10 @@ PlumageRender::PlumageRender()
if (settings.multiSampling) {
multisampleStateCI.rasterizationSamples = settings.sampleCount;
}
else
{
multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
}
std::vector<VkDynamicState> dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT,
@ -619,9 +627,7 @@ PlumageRender::PlumageRender()
pipelineCI.stageCount = static_cast<uint32_t>(shaderStages.size());
pipelineCI.pStages = shaderStages.data();
if (settings.multiSampling) {
multisampleStateCI.rasterizationSamples = settings.sampleCount;
}
// Skybox pipeline (background cube)
shaderStages = {
@ -1578,29 +1584,23 @@ PlumageRender::PlumageRender()
prepared = true;
}
void PlumageRender::submitWork(VkCommandBuffer cmdBuffer, VkQueue queue)
void PlumageRender::submitWork(VkCommandBuffer cmdBuffer, VkQueue queue, VkFence fence)
{
VkSubmitInfo submitInfo = vks::initializers::submitInfo();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmdBuffer;
VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo();
VkFence fence;
VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence));
VK_CHECK_RESULT(vkResetFences(device, 1, &fence));
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX));
vkDestroyFence(device, fence, nullptr);
//vkDestroyFence(device, fence, nullptr);
}
// todo :根据physicalDeviceIndex确定子文件夹路径frameIndex确定fileName
void PlumageRender::writeImageToFile(std::string filePath)
{
bool surpportBlit = true;
char* imageData;
// create dst image to copy
VkImageCreateInfo imageCreateInfo(vks::initializers::imageCreateInfo());
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
@ -1610,7 +1610,14 @@ PlumageRender::PlumageRender()
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.mipLevels = 1;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
if (settings.multiSampling)
{
imageCreateInfo.samples = settings.sampleCount;
}
else
{
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
}
imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR;
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
@ -1623,20 +1630,28 @@ PlumageRender::PlumageRender()
VkDeviceMemory dstImageMemory;
vkGetImageMemoryRequirements(device, dstImage, &memRequirements);
memAllocInfo.allocationSize = memRequirements.size;
memAllocInfo.memoryTypeIndex = getMemoryTypeIndex(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
memAllocInfo.memoryTypeIndex = vulkanDevice -> getMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
// allocate and bind memory
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &dstImageMemory));
VK_CHECK_RESULT(vkBindImageMemory(device, dstImage, dstImageMemory, 0));
// blit image and copy to host visualable memory
VkCommandBufferAllocateInfo cmdBufferAllocInfo;
VkCommandBufferAllocateInfo cmdBufferAllocInfo = vks::initializers::commandBufferAllocateInfo(cmdPool,VK_COMMAND_BUFFER_LEVEL_PRIMARY,1);
VkCommandBuffer copyCmd;
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufferAllocInfo, &copyCmd));
VkCommandBufferBeginInfo cmdBufferBeginInfo = vks::initializers::commandBufferBeginInfo();
VK_CHECK_RESULT(vkBeginCommandBuffer(copyCmd, &cmdBufferBeginInfo));
vks::tools::insertImageMemoryBarrier(copyCmd, dstImage, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1 });
vks::tools::insertImageMemoryBarrier(copyCmd,
dstImage,
0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1 });
VkImageCopy imageCopyRegion{};
imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@ -1647,14 +1662,50 @@ PlumageRender::PlumageRender()
imageCopyRegion.extent.height = height;
imageCopyRegion.extent.depth = 1;
vkCmdCopyImage(copyCmd, offscreen.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageCopyRegion);
VkImage srcImage;
if (settings.multiSampling)
{
srcImage = multisampleTarget.color.image;
}
else
{
srcImage = colorAttachment.image;
}
vks::tools::insertImageMemoryBarrier(copyCmd,
srcImage,
0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1 });
vkCmdCopyImage(copyCmd,
srcImage,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dstImage,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &imageCopyRegion);
// transition dst image to general layout for map memory
vks::tools::insertImageMemoryBarrier(copyCmd, dstImage, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1});
vks::tools::insertImageMemoryBarrier(copyCmd,
dstImage,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_MEMORY_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_GENERAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1});
VK_CHECK_RESULT(vkEndCommandBuffer(copyCmd));
submitWork(copyCmd, queue);
submitWork(copyCmd, queue,waitFences[frameIndex]);
vkDeviceWaitIdle(device);
// Get layout of the image
VkImageSubresource subResource{};
@ -1705,7 +1756,7 @@ PlumageRender::PlumageRender()
}
void PlumageRender::outputImageSequence()
void PlumageRender::outputImageSequence(uint32_t currentFrame)
{
std::string deviceFilePath = filePath.outputPath + "/device" + std::to_string(selectedPhysicalDeviceIndex);
@ -1713,33 +1764,34 @@ PlumageRender::PlumageRender()
{
_mkdir(deviceFilePath.c_str());
}
for (uint32_t i = 0; i < settings.outputFrameCount; i++)
{
std::string fileName = "/" + std::to_string(i) + "result.pmm";
std::string outputPath = deviceFilePath + fileName;
std::string fileName = "/" + std::to_string(currentFrame) + "result.pmm";
std::string outputPath = deviceFilePath + fileName;
//std::cout << outputPath << std::endl;
writeImageToFile(outputPath);
}
writeImageToFile(outputPath);
}
uint32_t PlumageRender::getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties)
void PlumageRender::renderFrame()
{
VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties);
for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++)
{
if ((typeBits & 1) == 1)
{
if ((deviceMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
{
return i;
}
}
typeBits >>= 1;
auto tStart = std::chrono::high_resolution_clock::now();
render();
frameCounter++;
//VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX));
outputImageSequence(frameCounter);
//VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex]));
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
frameTimer = (float)tDiff / 1000.0f;
camera.update(frameTimer);
fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f) {
lastFPS = static_cast<uint32_t>((float)frameCounter * (1000.0f / fpsTimer));
fpsTimer = 0.0f;
frameCounter = 0;
}
return 0;
}
void PlumageRender::render()
{
@ -1750,12 +1802,9 @@ PlumageRender::PlumageRender()
updateUIOverlay();
//加入写到文件的函数
//swapChainImage = swapChain.images[frameIndex];
//outputImageSequeue(swapChainImage,filePath.imageSequenceFilePath);
VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX));
VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex]));
//VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX));
//VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex]));
VkResult acquire = swapChain.acquireNextImage(presentCompleteSemaphores[frameIndex], &currentBuffer);
if ((acquire == VK_ERROR_OUT_OF_DATE_KHR) || (acquire == VK_SUBOPTIMAL_KHR)) {
@ -1764,7 +1813,6 @@ PlumageRender::PlumageRender()
else {
VK_CHECK_RESULT(acquire);
}
// Update UBOs
@ -1784,8 +1832,10 @@ PlumageRender::PlumageRender()
submitInfo.signalSemaphoreCount = 1;
submitInfo.pCommandBuffers = &commandBuffers[currentBuffer];
submitInfo.commandBufferCount = 1;
VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex]));
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, waitFences[frameIndex]));
VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, MAXINT64));
//显示队列
VkResult present = swapChain.queuePresent(queue, currentBuffer, renderCompleteSemaphores[frameIndex]);
if (!((present == VK_SUCCESS) || (present == VK_SUBOPTIMAL_KHR))) {
@ -1826,6 +1876,174 @@ PlumageRender::PlumageRender()
}
void PlumageRender::renderLoop()
{
destWidth = width;
destHeight = height;
#if defined(_WIN32)
MSG msg;
bool quitMessageReceived = false;
while (!quitMessageReceived) {
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT) {
quitMessageReceived = true;
break;
}
}
if (!IsIconic(window)) {
renderFrame();
}
}
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
while (1)
{
int ident;
int events;
struct android_poll_source* source;
bool destroy = false;
focused = true;
while ((ident = ALooper_pollAll(focused ? 0 : -1, NULL, &events, (void**)&source)) >= 0)
{
if (source != NULL)
{
source->process(androidApp, source);
}
if (androidApp->destroyRequested != 0)
{
LOGD("Android app destroy requested");
destroy = true;
break;
}
}
// App destruction requested
// Exit loop, example will be destroyed in application main
if (destroy)
{
break;
}
// Render frame
if (prepared)
{
auto tStart = std::chrono::high_resolution_clock::now();
render();
frameCounter++;
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
frameTimer = tDiff / 1000.0f;
camera.update(frameTimer);
fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f)
{
lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
fpsTimer = 0.0f;
frameCounter = 0;
}
// Check gamepad state
const float deadZone = 0.0015f;
// todo : check if gamepad is present
// todo : time based and relative axis positions
if (camera.type != Camera::CameraType::firstperson)
{
// Rotate
if (std::abs(gamePadState.axisLeft.x) > deadZone) {
camera.rotate(glm::vec3(0.0f, gamePadState.axisLeft.x * 0.5f, 0.0f));
}
if (std::abs(gamePadState.axisLeft.y) > deadZone) {
camera.rotate(glm::vec3(gamePadState.axisLeft.y * 0.5f, 0.0f, 0.0f));
}
}
else {
camera.updatePad(gamePadState.axisLeft, gamePadState.axisRight, frameTimer);
}
}
}
#elif defined(_DIRECT2DISPLAY)
while (!quit)
{
auto tStart = std::chrono::high_resolution_clock::now();
render();
frameCounter++;
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
frameTimer = tDiff / 1000.0f;
camera.update(frameTimer);
fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f)
{
lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
fpsTimer = 0.0f;
frameCounter = 0;
}
}
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
while (!quit)
{
auto tStart = std::chrono::high_resolution_clock::now();
while (wl_display_prepare_read(display) != 0)
wl_display_dispatch_pending(display);
wl_display_flush(display);
wl_display_read_events(display);
wl_display_dispatch_pending(display);
render();
frameCounter++;
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
frameTimer = tDiff / 1000.0f;
camera.update(frameTimer);
fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f)
{
wl_shell_surface_set_title(shell_surface, title.c_str());
lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
fpsTimer = 0.0f;
frameCounter = 0;
}
}
#elif defined(VK_USE_PLATFORM_XCB_KHR)
xcb_flush(connection);
while (!quit)
{
auto tStart = std::chrono::high_resolution_clock::now();
xcb_generic_event_t* event;
while ((event = xcb_poll_for_event(connection)))
{
handleEvent(event);
free(event);
}
render();
frameCounter++;
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
frameTimer = tDiff / 1000.0f;
camera.update(frameTimer);
fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f)
{
xcb_change_property(connection, XCB_PROP_MODE_REPLACE,
window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
title.size(), title.c_str());
lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
fpsTimer = 0.0f;
frameCounter = 0;
}
}
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
[NSApp run];
#endif
// Flush device to make sure all resources can be freed
vkDeviceWaitIdle(device);
}
void PlumageRender::fileDropped(std::string filename)
{
vkDeviceWaitIdle(device);

View File

@ -216,19 +216,6 @@ public:
VkDescriptorSet tonemappingDescriptorSet = VK_NULL_HANDLE;
};
struct Settings {
bool validation = true;
bool fullscreen = false;
bool vsync = false;
bool multiSampling = true;
bool rotateModel = true;
bool enableSaveToImageSequeue = false;
uint32_t outputFrameCount = 50;
bool takeScreenShot = false;
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT;
} settings;
struct DescriptorSetLayouts {
VkDescriptorSetLayout scene;
VkDescriptorSetLayout material;
@ -260,6 +247,7 @@ public:
glm::vec3 rotation = glm::vec3(75.0f, 40.0f, 0.0f);
} lightSource;
//cube map generation
@ -286,7 +274,14 @@ public:
} prefilterPushBlock;
UI* gui;
float frameTimer = 1.0f;
uint32_t lastFPS = 0;
float fpsTimer = 0.0f;
uint32_t frameCounter = 0;
uint32_t destWidth;
uint32_t destHeight;
PlumageRender();
~PlumageRender()
@ -345,12 +340,14 @@ public:
void updateShaderData();
void windowResized();
void prepare();
void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue);
void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue, VkFence fence);
void writeImageToFile(std::string filePath);
void outputImageSequence();
void outputImageSequence(uint32_t currentFrame);
void renderFrame();
void outputScreenShot();
uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties);
virtual void render();
void renderLoop();
virtual void updateUIOverlay();
virtual void fileDropped(std::string filename);
};