2016-02-16 15:07:25 +01:00
|
|
|
/*
|
|
|
|
|
* Vulkan Example base class
|
|
|
|
|
*
|
2017-08-13 10:24:25 +02:00
|
|
|
* Copyright (C) 2016-2017 by Sascha Willems - www.saschawillems.de
|
2016-02-16 15:07:25 +01:00
|
|
|
*
|
|
|
|
|
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "vulkanexamplebase.h"
|
|
|
|
|
|
2016-11-10 22:56:15 +01:00
|
|
|
std::vector<const char*> VulkanExampleBase::args;
|
2016-11-10 22:29:55 +01:00
|
|
|
|
2016-02-16 15:07:25 +01:00
|
|
|
VkResult VulkanExampleBase::createInstance(bool enableValidation)
|
|
|
|
|
{
|
2017-01-22 13:38:57 +01:00
|
|
|
this->settings.validation = enableValidation;
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2017-06-15 11:27:49 +02:00
|
|
|
// Validation can also be forced via a define
|
|
|
|
|
#if defined(_VALIDATION)
|
|
|
|
|
this->settings.validation = true;
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-02-16 15:07:25 +01:00
|
|
|
VkApplicationInfo appInfo = {};
|
|
|
|
|
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
|
|
|
|
appInfo.pApplicationName = name.c_str();
|
|
|
|
|
appInfo.pEngineName = name.c_str();
|
2018-06-01 18:42:18 +02:00
|
|
|
appInfo.apiVersion = apiVersion;
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2017-02-09 19:22:48 +01:00
|
|
|
std::vector<const char*> instanceExtensions = { VK_KHR_SURFACE_EXTENSION_NAME };
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2016-03-20 14:55:46 +01:00
|
|
|
// Enable surface extensions depending on os
|
|
|
|
|
#if defined(_WIN32)
|
2017-02-09 19:22:48 +01:00
|
|
|
instanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
2017-08-13 10:24:25 +02:00
|
|
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
2017-02-09 19:22:48 +01:00
|
|
|
instanceExtensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
2016-11-04 13:32:58 -07:00
|
|
|
#elif defined(_DIRECT2DISPLAY)
|
2017-02-09 19:22:48 +01:00
|
|
|
instanceExtensions.push_back(VK_KHR_DISPLAY_EXTENSION_NAME);
|
2017-02-02 08:54:56 +00:00
|
|
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
2017-02-09 19:22:48 +01:00
|
|
|
instanceExtensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
2017-08-13 10:24:25 +02:00
|
|
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
2017-02-09 19:22:48 +01:00
|
|
|
instanceExtensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
2017-06-30 21:55:17 -04:00
|
|
|
#elif defined(VK_USE_PLATFORM_IOS_MVK)
|
2017-07-29 19:31:00 +02:00
|
|
|
instanceExtensions.push_back(VK_MVK_IOS_SURFACE_EXTENSION_NAME);
|
2017-06-30 21:55:17 -04:00
|
|
|
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
2017-07-29 19:31:00 +02:00
|
|
|
instanceExtensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
|
2016-02-16 15:07:25 +01:00
|
|
|
#endif
|
|
|
|
|
|
2018-03-03 11:49:46 +01:00
|
|
|
if (enabledInstanceExtensions.size() > 0) {
|
|
|
|
|
for (auto enabledExtension : enabledInstanceExtensions) {
|
|
|
|
|
instanceExtensions.push_back(enabledExtension);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-16 15:07:25 +01:00
|
|
|
VkInstanceCreateInfo instanceCreateInfo = {};
|
|
|
|
|
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
|
|
|
instanceCreateInfo.pNext = NULL;
|
|
|
|
|
instanceCreateInfo.pApplicationInfo = &appInfo;
|
2017-02-09 19:22:48 +01:00
|
|
|
if (instanceExtensions.size() > 0)
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
2017-01-22 13:38:57 +01:00
|
|
|
if (settings.validation)
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
2017-02-09 19:22:48 +01:00
|
|
|
instanceExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
2017-02-09 19:22:48 +01:00
|
|
|
instanceCreateInfo.enabledExtensionCount = (uint32_t)instanceExtensions.size();
|
|
|
|
|
instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.data();
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
2017-01-22 13:38:57 +01:00
|
|
|
if (settings.validation)
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
2017-02-12 11:33:04 +01:00
|
|
|
instanceCreateInfo.enabledLayerCount = vks::debug::validationLayerCount;
|
|
|
|
|
instanceCreateInfo.ppEnabledLayerNames = vks::debug::validationLayerNames;
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
return vkCreateInstance(&instanceCreateInfo, nullptr, &instance);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-13 16:51:00 +01:00
|
|
|
std::string VulkanExampleBase::getWindowTitle()
|
|
|
|
|
{
|
|
|
|
|
std::string device(deviceProperties.deviceName);
|
|
|
|
|
std::string windowTitle;
|
2016-07-24 21:18:25 +02:00
|
|
|
windowTitle = title + " - " + device;
|
2017-10-29 11:41:43 +01:00
|
|
|
if (!settings.overlay) {
|
2016-07-24 21:18:25 +02:00
|
|
|
windowTitle += " - " + std::to_string(frameCounter) + " fps";
|
|
|
|
|
}
|
2016-03-13 16:51:00 +01:00
|
|
|
return windowTitle;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-14 12:00:05 -04:00
|
|
|
#if !(defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
|
|
|
|
|
// iOS & macOS: VulkanExampleBase::getAssetPath() implemented externally to allow access to Objective-C components
|
2016-03-21 20:10:09 +01:00
|
|
|
const std::string VulkanExampleBase::getAssetPath()
|
|
|
|
|
{
|
2017-08-13 10:24:25 +02:00
|
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
2016-03-21 20:10:09 +01:00
|
|
|
return "";
|
2017-07-03 14:49:18 +03:00
|
|
|
#elif defined(VK_EXAMPLE_DATA_DIR)
|
|
|
|
|
return VK_EXAMPLE_DATA_DIR;
|
2016-03-21 20:10:09 +01:00
|
|
|
#else
|
|
|
|
|
return "./../data/";
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2017-04-14 12:00:05 -04:00
|
|
|
#endif
|
2016-03-21 20:10:09 +01:00
|
|
|
|
2016-02-16 15:07:25 +01:00
|
|
|
bool VulkanExampleBase::checkCommandBuffers()
|
|
|
|
|
{
|
|
|
|
|
for (auto& cmdBuffer : drawCmdBuffers)
|
|
|
|
|
{
|
|
|
|
|
if (cmdBuffer == VK_NULL_HANDLE)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::createCommandBuffers()
|
|
|
|
|
{
|
2016-08-10 20:39:01 +02:00
|
|
|
// Create one command buffer for each swap chain image and reuse for rendering
|
2016-02-16 15:07:25 +01:00
|
|
|
drawCmdBuffers.resize(swapChain.imageCount);
|
|
|
|
|
|
2016-03-13 17:15:44 +01:00
|
|
|
VkCommandBufferAllocateInfo cmdBufAllocateInfo =
|
2017-02-12 11:12:42 +01:00
|
|
|
vks::initializers::commandBufferAllocateInfo(
|
2016-02-16 15:07:25 +01:00
|
|
|
cmdPool,
|
|
|
|
|
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
2016-06-21 23:07:16 +02:00
|
|
|
static_cast<uint32_t>(drawCmdBuffers.size()));
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2016-05-22 20:27:06 +02:00
|
|
|
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, drawCmdBuffers.data()));
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::destroyCommandBuffers()
|
|
|
|
|
{
|
2016-06-21 23:07:16 +02:00
|
|
|
vkFreeCommandBuffers(device, cmdPool, static_cast<uint32_t>(drawCmdBuffers.size()), drawCmdBuffers.data());
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
2016-04-16 14:42:41 +02:00
|
|
|
VkCommandBuffer VulkanExampleBase::createCommandBuffer(VkCommandBufferLevel level, bool begin)
|
|
|
|
|
{
|
|
|
|
|
VkCommandBuffer cmdBuffer;
|
|
|
|
|
|
|
|
|
|
VkCommandBufferAllocateInfo cmdBufAllocateInfo =
|
2017-02-12 11:12:42 +01:00
|
|
|
vks::initializers::commandBufferAllocateInfo(
|
2016-04-16 14:42:41 +02:00
|
|
|
cmdPool,
|
|
|
|
|
level,
|
|
|
|
|
1);
|
|
|
|
|
|
2016-05-20 21:19:43 +02:00
|
|
|
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &cmdBuffer));
|
2016-04-16 14:42:41 +02:00
|
|
|
|
|
|
|
|
// If requested, also start the new command buffer
|
|
|
|
|
if (begin)
|
|
|
|
|
{
|
2017-02-12 11:12:42 +01:00
|
|
|
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
|
2016-05-20 21:19:43 +02:00
|
|
|
VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo));
|
2016-04-16 14:42:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmdBuffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free)
|
|
|
|
|
{
|
|
|
|
|
if (commandBuffer == VK_NULL_HANDLE)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-20 21:19:43 +02:00
|
|
|
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
|
2016-04-16 14:42:41 +02:00
|
|
|
|
|
|
|
|
VkSubmitInfo submitInfo = {};
|
|
|
|
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
|
|
|
submitInfo.commandBufferCount = 1;
|
|
|
|
|
submitInfo.pCommandBuffers = &commandBuffer;
|
|
|
|
|
|
2016-05-20 21:19:43 +02:00
|
|
|
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
|
|
|
|
VK_CHECK_RESULT(vkQueueWaitIdle(queue));
|
2016-04-16 14:42:41 +02:00
|
|
|
|
|
|
|
|
if (free)
|
|
|
|
|
{
|
|
|
|
|
vkFreeCommandBuffers(device, cmdPool, 1, &commandBuffer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-16 15:07:25 +01:00
|
|
|
void VulkanExampleBase::createPipelineCache()
|
|
|
|
|
{
|
|
|
|
|
VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {};
|
|
|
|
|
pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
|
2016-05-22 20:27:06 +02:00
|
|
|
VK_CHECK_RESULT(vkCreatePipelineCache(device, &pipelineCacheCreateInfo, nullptr, &pipelineCache));
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::prepare()
|
|
|
|
|
{
|
2017-10-21 16:51:39 +02:00
|
|
|
if (vulkanDevice->enableDebugMarkers) {
|
2017-02-12 11:33:04 +01:00
|
|
|
vks::debugmarker::setup(device);
|
2016-05-07 14:06:47 +02:00
|
|
|
}
|
2017-10-21 16:51:39 +02:00
|
|
|
initSwapchain();
|
2016-02-16 15:07:25 +01:00
|
|
|
createCommandPool();
|
|
|
|
|
setupSwapChain();
|
|
|
|
|
createCommandBuffers();
|
2018-06-03 09:38:14 +02:00
|
|
|
createSynchronizationPrimitives();
|
2016-02-16 15:07:25 +01:00
|
|
|
setupDepthStencil();
|
|
|
|
|
setupRenderPass();
|
|
|
|
|
createPipelineCache();
|
|
|
|
|
setupFrameBuffer();
|
2017-10-29 11:41:43 +01:00
|
|
|
settings.overlay = settings.overlay && (!benchmark.active);
|
|
|
|
|
if (settings.overlay) {
|
2017-11-03 11:17:09 +01:00
|
|
|
vks::UIOverlayCreateInfo overlayCreateInfo = {};
|
|
|
|
|
// Setup default overlay creation info
|
|
|
|
|
overlayCreateInfo.device = vulkanDevice;
|
|
|
|
|
overlayCreateInfo.copyQueue = queue;
|
|
|
|
|
overlayCreateInfo.width = width;
|
|
|
|
|
overlayCreateInfo.height = height;
|
|
|
|
|
// Virtual function call for example to customize overlay creation
|
|
|
|
|
OnSetupUIOverlay(overlayCreateInfo);
|
|
|
|
|
// Load default shaders if not specified by example
|
|
|
|
|
if (overlayCreateInfo.shaders.size() == 0) {
|
|
|
|
|
overlayCreateInfo.shaders = {
|
|
|
|
|
loadShader(getAssetPath() + "shaders/base/uioverlay.vert.spv", VK_SHADER_STAGE_VERTEX_BIT),
|
|
|
|
|
loadShader(getAssetPath() + "shaders/base/uioverlay.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
UIOverlay = new vks::UIOverlay(overlayCreateInfo);
|
2018-08-29 20:49:13 +02:00
|
|
|
UIOverlay->preparePipeline(pipelineCache, renderPass);
|
2017-10-29 11:41:43 +01:00
|
|
|
updateOverlay();
|
2016-05-15 18:31:31 +02:00
|
|
|
}
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-21 20:10:09 +01:00
|
|
|
VkPipelineShaderStageCreateInfo VulkanExampleBase::loadShader(std::string fileName, VkShaderStageFlagBits stage)
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
|
|
|
|
VkPipelineShaderStageCreateInfo shaderStage = {};
|
|
|
|
|
shaderStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
|
|
|
shaderStage.stage = stage;
|
2017-08-13 10:24:25 +02:00
|
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
2017-04-23 11:51:31 +02:00
|
|
|
shaderStage.module = vks::tools::loadShader(androidApp->activity->assetManager, fileName.c_str(), device);
|
2016-03-20 15:45:40 +01:00
|
|
|
#else
|
2017-04-23 11:51:31 +02:00
|
|
|
shaderStage.module = vks::tools::loadShader(fileName.c_str(), device);
|
2016-03-20 15:45:40 +01:00
|
|
|
#endif
|
2016-02-16 15:07:25 +01:00
|
|
|
shaderStage.pName = "main"; // todo : make param
|
2017-02-15 10:42:39 +00:00
|
|
|
assert(shaderStage.module != VK_NULL_HANDLE);
|
2016-02-16 15:07:25 +01:00
|
|
|
shaderModules.push_back(shaderStage.module);
|
|
|
|
|
return shaderStage;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-14 12:00:05 -04:00
|
|
|
void VulkanExampleBase::renderFrame()
|
|
|
|
|
{
|
2017-07-29 19:31:00 +02:00
|
|
|
auto tStart = std::chrono::high_resolution_clock::now();
|
|
|
|
|
if (viewUpdated)
|
|
|
|
|
{
|
|
|
|
|
viewUpdated = false;
|
|
|
|
|
viewChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
if (camera.moving())
|
|
|
|
|
{
|
|
|
|
|
viewUpdated = true;
|
|
|
|
|
}
|
|
|
|
|
// Convert to clamped timer value
|
|
|
|
|
if (!paused)
|
|
|
|
|
{
|
|
|
|
|
timer += timerSpeed * frameTimer;
|
|
|
|
|
if (timer > 1.0)
|
|
|
|
|
{
|
|
|
|
|
timer -= 1.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fpsTimer += (float)tDiff;
|
|
|
|
|
if (fpsTimer > 1000.0f)
|
|
|
|
|
{
|
2018-01-21 18:27:06 +01:00
|
|
|
lastFPS = static_cast<uint32_t>((float)frameCounter * (1000.0f / fpsTimer));
|
2017-07-29 19:31:00 +02:00
|
|
|
#if defined(_WIN32)
|
2017-10-29 11:41:43 +01:00
|
|
|
if (!settings.overlay) {
|
2017-07-29 19:31:00 +02:00
|
|
|
std::string windowTitle = getWindowTitle();
|
|
|
|
|
SetWindowText(window, windowTitle.c_str());
|
|
|
|
|
}
|
2017-04-14 12:00:05 -04:00
|
|
|
#endif
|
2017-07-29 19:31:00 +02:00
|
|
|
fpsTimer = 0.0f;
|
|
|
|
|
frameCounter = 0;
|
|
|
|
|
}
|
2017-10-29 11:41:43 +01:00
|
|
|
// TODO: Cap UI overlay update rates
|
|
|
|
|
updateOverlay();
|
2017-07-29 19:31:00 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-16 15:07:25 +01:00
|
|
|
void VulkanExampleBase::renderLoop()
|
|
|
|
|
{
|
2017-07-29 19:31:00 +02:00
|
|
|
if (benchmark.active) {
|
2018-01-19 21:43:00 +01:00
|
|
|
benchmark.run([=] { render(); }, vulkanDevice->properties);
|
2017-08-26 14:05:48 +02:00
|
|
|
vkDeviceWaitIdle(device);
|
2018-01-19 21:43:00 +01:00
|
|
|
if (benchmark.filename != "") {
|
|
|
|
|
benchmark.saveResults();
|
|
|
|
|
}
|
2017-07-29 19:31:00 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-03 21:22:45 +02:00
|
|
|
destWidth = width;
|
|
|
|
|
destHeight = height;
|
2016-03-20 14:55:46 +01:00
|
|
|
#if defined(_WIN32)
|
2016-02-16 15:07:25 +01:00
|
|
|
MSG msg;
|
2017-06-27 09:03:26 +02:00
|
|
|
bool quitMessageReceived = false;
|
2017-07-29 19:31:00 +02:00
|
|
|
while (!quitMessageReceived) {
|
|
|
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
2016-07-31 12:41:50 +02:00
|
|
|
TranslateMessage(&msg);
|
|
|
|
|
DispatchMessage(&msg);
|
2017-07-29 19:31:00 +02:00
|
|
|
if (msg.message == WM_QUIT) {
|
2017-06-27 09:03:26 +02:00
|
|
|
quitMessageReceived = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-07-31 12:41:50 +02:00
|
|
|
}
|
2018-06-30 21:56:23 +02:00
|
|
|
if (!IsIconic(window)) {
|
|
|
|
|
renderFrame();
|
|
|
|
|
}
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
2017-08-13 10:24:25 +02:00
|
|
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
2016-03-20 20:04:27 +01:00
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
int ident;
|
|
|
|
|
int events;
|
|
|
|
|
struct android_poll_source* source;
|
2016-03-26 12:58:35 +01:00
|
|
|
bool destroy = false;
|
2016-03-20 20:04:27 +01:00
|
|
|
|
2016-03-26 12:58:35 +01:00
|
|
|
focused = true;
|
|
|
|
|
|
|
|
|
|
while ((ident = ALooper_pollAll(focused ? 0 : -1, NULL, &events, (void**)&source)) >= 0)
|
2016-03-20 20:04:27 +01:00
|
|
|
{
|
|
|
|
|
if (source != NULL)
|
|
|
|
|
{
|
|
|
|
|
source->process(androidApp, source);
|
|
|
|
|
}
|
|
|
|
|
if (androidApp->destroyRequested != 0)
|
|
|
|
|
{
|
2016-03-26 12:58:35 +01:00
|
|
|
LOGD("Android app destroy requested");
|
|
|
|
|
destroy = true;
|
|
|
|
|
break;
|
2016-03-20 20:04:27 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-26 12:58:35 +01:00
|
|
|
// App destruction requested
|
|
|
|
|
// Exit loop, example will be destroyed in application main
|
|
|
|
|
if (destroy)
|
|
|
|
|
{
|
2018-06-01 18:41:26 +02:00
|
|
|
ANativeActivity_finish(androidApp->activity);
|
2016-03-26 12:58:35 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 20:04:27 +01:00
|
|
|
// Render frame
|
|
|
|
|
if (prepared)
|
|
|
|
|
{
|
2016-03-23 22:16:05 +01:00
|
|
|
auto tStart = std::chrono::high_resolution_clock::now();
|
2016-03-20 20:04:27 +01:00
|
|
|
render();
|
2016-03-23 22:16:05 +01:00
|
|
|
frameCounter++;
|
|
|
|
|
auto tEnd = std::chrono::high_resolution_clock::now();
|
|
|
|
|
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
|
|
|
|
|
frameTimer = tDiff / 1000.0f;
|
2016-06-11 15:54:16 +02:00
|
|
|
camera.update(frameTimer);
|
2016-03-24 22:43:33 +01:00
|
|
|
// Convert to clamped timer value
|
|
|
|
|
if (!paused)
|
|
|
|
|
{
|
|
|
|
|
timer += timerSpeed * frameTimer;
|
|
|
|
|
if (timer > 1.0)
|
|
|
|
|
{
|
|
|
|
|
timer -= 1.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-04-15 21:24:50 +02:00
|
|
|
fpsTimer += (float)tDiff;
|
|
|
|
|
if (fpsTimer > 1000.0f)
|
|
|
|
|
{
|
2017-12-01 13:10:07 +01:00
|
|
|
lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
|
2016-04-15 21:24:50 +02:00
|
|
|
fpsTimer = 0.0f;
|
2016-05-22 20:27:06 +02:00
|
|
|
frameCounter = 0;
|
2016-04-15 21:24:50 +02:00
|
|
|
}
|
2017-03-06 22:11:19 +01:00
|
|
|
|
2017-11-01 13:29:57 +01:00
|
|
|
// TODO: Cap UI overlay update rates/only issue when update requested
|
|
|
|
|
updateOverlay();
|
|
|
|
|
|
2017-03-06 22:11:19 +01:00
|
|
|
bool updateView = false;
|
|
|
|
|
|
|
|
|
|
// Check touch state (for movement)
|
|
|
|
|
if (touchDown) {
|
|
|
|
|
touchTimer += frameTimer;
|
|
|
|
|
}
|
|
|
|
|
if (touchTimer >= 1.0) {
|
|
|
|
|
camera.keys.up = true;
|
|
|
|
|
viewChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 21:46:49 +01:00
|
|
|
// Check gamepad state
|
2016-03-26 00:07:12 +01:00
|
|
|
const float deadZone = 0.0015f;
|
2016-03-20 21:46:49 +01:00
|
|
|
// todo : check if gamepad is present
|
|
|
|
|
// todo : time based and relative axis positions
|
2016-06-20 22:08:50 +02:00
|
|
|
if (camera.type != Camera::CameraType::firstperson)
|
2016-03-20 21:46:49 +01:00
|
|
|
{
|
2016-06-20 22:08:50 +02:00
|
|
|
// Rotate
|
|
|
|
|
if (std::abs(gamePadState.axisLeft.x) > deadZone)
|
|
|
|
|
{
|
|
|
|
|
rotation.y += gamePadState.axisLeft.x * 0.5f * rotationSpeed;
|
|
|
|
|
camera.rotate(glm::vec3(0.0f, gamePadState.axisLeft.x * 0.5f, 0.0f));
|
|
|
|
|
updateView = true;
|
|
|
|
|
}
|
|
|
|
|
if (std::abs(gamePadState.axisLeft.y) > deadZone)
|
|
|
|
|
{
|
|
|
|
|
rotation.x -= gamePadState.axisLeft.y * 0.5f * rotationSpeed;
|
|
|
|
|
camera.rotate(glm::vec3(gamePadState.axisLeft.y * 0.5f, 0.0f, 0.0f));
|
|
|
|
|
updateView = true;
|
|
|
|
|
}
|
|
|
|
|
// Zoom
|
|
|
|
|
if (std::abs(gamePadState.axisRight.y) > deadZone)
|
|
|
|
|
{
|
|
|
|
|
zoom -= gamePadState.axisRight.y * 0.01f * zoomSpeed;
|
|
|
|
|
updateView = true;
|
|
|
|
|
}
|
|
|
|
|
if (updateView)
|
|
|
|
|
{
|
|
|
|
|
viewChanged();
|
|
|
|
|
}
|
2016-03-20 21:46:49 +01:00
|
|
|
}
|
2016-06-20 22:08:50 +02:00
|
|
|
else
|
2016-03-20 21:46:49 +01:00
|
|
|
{
|
2016-06-20 22:08:50 +02:00
|
|
|
updateView = camera.updatePad(gamePadState.axisLeft, gamePadState.axisRight, frameTimer);
|
|
|
|
|
if (updateView)
|
|
|
|
|
{
|
|
|
|
|
viewChanged();
|
|
|
|
|
}
|
2016-03-20 21:46:49 +01:00
|
|
|
}
|
2016-03-20 20:04:27 +01:00
|
|
|
}
|
|
|
|
|
}
|
2016-11-04 13:32:58 -07:00
|
|
|
#elif defined(_DIRECT2DISPLAY)
|
|
|
|
|
while (!quit)
|
|
|
|
|
{
|
|
|
|
|
auto tStart = std::chrono::high_resolution_clock::now();
|
|
|
|
|
if (viewUpdated)
|
|
|
|
|
{
|
|
|
|
|
viewUpdated = false;
|
|
|
|
|
viewChanged();
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
if (camera.moving())
|
|
|
|
|
{
|
|
|
|
|
viewUpdated = true;
|
|
|
|
|
}
|
|
|
|
|
// Convert to clamped timer value
|
|
|
|
|
if (!paused)
|
|
|
|
|
{
|
|
|
|
|
timer += timerSpeed * frameTimer;
|
|
|
|
|
if (timer > 1.0)
|
|
|
|
|
{
|
|
|
|
|
timer -= 1.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fpsTimer += (float)tDiff;
|
|
|
|
|
if (fpsTimer > 1000.0f)
|
|
|
|
|
{
|
2017-12-01 13:10:07 +01:00
|
|
|
lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
|
2016-11-04 13:32:58 -07:00
|
|
|
fpsTimer = 0.0f;
|
|
|
|
|
frameCounter = 0;
|
|
|
|
|
}
|
2017-11-01 13:29:57 +01:00
|
|
|
updateOverlay();
|
2016-11-04 13:32:58 -07:00
|
|
|
}
|
2017-02-02 08:54:56 +00:00
|
|
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
|
|
|
while (!quit)
|
|
|
|
|
{
|
|
|
|
|
auto tStart = std::chrono::high_resolution_clock::now();
|
|
|
|
|
if (viewUpdated)
|
|
|
|
|
{
|
|
|
|
|
viewUpdated = false;
|
|
|
|
|
viewChanged();
|
|
|
|
|
}
|
2017-02-14 18:52:02 +00:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
2017-02-02 08:54:56 +00:00
|
|
|
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);
|
|
|
|
|
if (camera.moving())
|
|
|
|
|
{
|
|
|
|
|
viewUpdated = true;
|
|
|
|
|
}
|
|
|
|
|
// Convert to clamped timer value
|
|
|
|
|
if (!paused)
|
|
|
|
|
{
|
|
|
|
|
timer += timerSpeed * frameTimer;
|
|
|
|
|
if (timer > 1.0)
|
|
|
|
|
{
|
|
|
|
|
timer -= 1.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fpsTimer += (float)tDiff;
|
|
|
|
|
if (fpsTimer > 1000.0f)
|
|
|
|
|
{
|
2017-10-30 18:03:48 +01:00
|
|
|
if (!settings.overlay)
|
2017-02-02 08:54:56 +00:00
|
|
|
{
|
|
|
|
|
std::string windowTitle = getWindowTitle();
|
|
|
|
|
wl_shell_surface_set_title(shell_surface, windowTitle.c_str());
|
|
|
|
|
}
|
2017-12-01 13:10:07 +01:00
|
|
|
lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
|
2017-02-02 08:54:56 +00:00
|
|
|
fpsTimer = 0.0f;
|
|
|
|
|
frameCounter = 0;
|
|
|
|
|
}
|
2017-11-01 13:29:57 +01:00
|
|
|
updateOverlay();
|
2017-02-02 08:54:56 +00:00
|
|
|
}
|
2017-08-13 10:24:25 +02:00
|
|
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
2016-02-16 15:07:25 +01:00
|
|
|
xcb_flush(connection);
|
|
|
|
|
while (!quit)
|
|
|
|
|
{
|
|
|
|
|
auto tStart = std::chrono::high_resolution_clock::now();
|
2016-08-03 20:44:31 +02:00
|
|
|
if (viewUpdated)
|
|
|
|
|
{
|
|
|
|
|
viewUpdated = false;
|
|
|
|
|
viewChanged();
|
|
|
|
|
}
|
2016-02-16 15:07:25 +01:00
|
|
|
xcb_generic_event_t *event;
|
2016-08-03 20:44:31 +02:00
|
|
|
while ((event = xcb_poll_for_event(connection)))
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
|
|
|
|
handleEvent(event);
|
|
|
|
|
free(event);
|
|
|
|
|
}
|
|
|
|
|
render();
|
2016-03-13 17:15:44 +01:00
|
|
|
frameCounter++;
|
2016-02-16 15:07:25 +01:00
|
|
|
auto tEnd = std::chrono::high_resolution_clock::now();
|
|
|
|
|
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
|
|
|
|
|
frameTimer = tDiff / 1000.0f;
|
2016-06-11 15:54:16 +02:00
|
|
|
camera.update(frameTimer);
|
2016-08-03 20:44:31 +02:00
|
|
|
if (camera.moving())
|
|
|
|
|
{
|
|
|
|
|
viewUpdated = true;
|
|
|
|
|
}
|
2016-03-13 17:15:44 +01:00
|
|
|
// Convert to clamped timer value
|
|
|
|
|
if (!paused)
|
|
|
|
|
{
|
|
|
|
|
timer += timerSpeed * frameTimer;
|
|
|
|
|
if (timer > 1.0)
|
|
|
|
|
{
|
|
|
|
|
timer -= 1.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fpsTimer += (float)tDiff;
|
|
|
|
|
if (fpsTimer > 1000.0f)
|
|
|
|
|
{
|
2017-10-30 18:03:48 +01:00
|
|
|
if (!settings.overlay)
|
2016-05-15 18:31:31 +02:00
|
|
|
{
|
|
|
|
|
std::string windowTitle = getWindowTitle();
|
|
|
|
|
xcb_change_property(connection, XCB_PROP_MODE_REPLACE,
|
|
|
|
|
window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
|
|
|
|
|
windowTitle.size(), windowTitle.c_str());
|
|
|
|
|
}
|
2017-12-01 13:10:07 +01:00
|
|
|
lastFPS = (float)frameCounter * (1000.0f / fpsTimer);
|
2016-03-13 17:15:44 +01:00
|
|
|
fpsTimer = 0.0f;
|
2016-05-22 20:27:06 +02:00
|
|
|
frameCounter = 0;
|
2016-03-13 17:15:44 +01:00
|
|
|
}
|
2017-11-01 13:29:57 +01:00
|
|
|
updateOverlay();
|
2016-03-20 14:55:46 +01:00
|
|
|
}
|
2016-02-16 15:07:25 +01:00
|
|
|
#endif
|
2018-05-01 11:23:36 +02:00
|
|
|
// Flush device to make sure all resources can be freed
|
2018-06-01 18:41:26 +02:00
|
|
|
if (device != VK_NULL_HANDLE) {
|
|
|
|
|
vkDeviceWaitIdle(device);
|
|
|
|
|
}
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-29 11:41:43 +01:00
|
|
|
void VulkanExampleBase::updateOverlay()
|
2016-05-15 18:31:31 +02:00
|
|
|
{
|
2017-10-29 11:41:43 +01:00
|
|
|
if (!settings.overlay)
|
2016-05-15 18:31:31 +02:00
|
|
|
return;
|
|
|
|
|
|
2017-10-29 11:41:43 +01:00
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
2016-05-15 18:31:31 +02:00
|
|
|
|
2017-10-29 11:41:43 +01:00
|
|
|
io.DisplaySize = ImVec2((float)width, (float)height);
|
|
|
|
|
io.DeltaTime = frameTimer;
|
2016-05-15 18:31:31 +02:00
|
|
|
|
2017-10-29 11:41:43 +01:00
|
|
|
io.MousePos = ImVec2(mousePos.x, mousePos.y);
|
|
|
|
|
io.MouseDown[0] = mouseButtons.left;
|
|
|
|
|
io.MouseDown[1] = mouseButtons.right;
|
2016-05-15 18:31:31 +02:00
|
|
|
|
2017-10-29 11:41:43 +01:00
|
|
|
ImGui::NewFrame();
|
|
|
|
|
|
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
|
|
|
|
|
ImGui::SetNextWindowPos(ImVec2(10, 10));
|
|
|
|
|
ImGui::SetNextWindowSize(ImVec2(0, 0), ImGuiSetCond_FirstUseEver);
|
|
|
|
|
ImGui::Begin("Vulkan Example", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove);
|
2017-11-02 09:08:47 +01:00
|
|
|
ImGui::TextUnformatted(title.c_str());
|
|
|
|
|
ImGui::TextUnformatted(deviceProperties.deviceName);
|
2017-11-03 16:35:38 +01:00
|
|
|
ImGui::Text("%.2f ms/frame (%.1d fps)", (1000.0f / lastFPS), lastFPS);
|
2017-10-29 11:41:43 +01:00
|
|
|
|
2017-11-02 09:08:47 +01:00
|
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 5.0f * UIOverlay->scale));
|
|
|
|
|
#endif
|
|
|
|
|
ImGui::PushItemWidth(110.0f * UIOverlay->scale);
|
2017-10-30 12:36:44 +01:00
|
|
|
OnUpdateUIOverlay(UIOverlay);
|
|
|
|
|
ImGui::PopItemWidth();
|
2017-11-02 09:08:47 +01:00
|
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
|
|
|
ImGui::PopStyleVar();
|
|
|
|
|
#endif
|
2016-05-15 18:31:31 +02:00
|
|
|
|
2017-10-29 11:41:43 +01:00
|
|
|
ImGui::End();
|
|
|
|
|
ImGui::PopStyleVar();
|
|
|
|
|
ImGui::Render();
|
|
|
|
|
|
2018-08-29 20:49:13 +02:00
|
|
|
if (UIOverlay->update()) {
|
|
|
|
|
buildCommandBuffers();
|
|
|
|
|
}
|
2017-11-02 17:07:07 +01:00
|
|
|
|
|
|
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
|
|
|
if (mouseButtons.left) {
|
|
|
|
|
mouseButtons.left = false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2016-05-15 18:31:31 +02:00
|
|
|
}
|
|
|
|
|
|
2018-08-29 20:49:13 +02:00
|
|
|
void VulkanExampleBase::drawUI(const VkCommandBuffer commandBuffer)
|
|
|
|
|
{
|
|
|
|
|
if (settings.overlay) {
|
|
|
|
|
UIOverlay->draw(commandBuffer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-15 20:11:28 +02:00
|
|
|
void VulkanExampleBase::prepareFrame()
|
|
|
|
|
{
|
2017-04-15 10:27:12 +02:00
|
|
|
// Acquire the next image from the swap chain
|
|
|
|
|
VkResult err = swapChain.acquireNextImage(semaphores.presentComplete, ¤tBuffer);
|
|
|
|
|
// Recreate the swapchain if it's no longer compatible with the surface (OUT_OF_DATE) or no longer optimal for presentation (SUBOPTIMAL)
|
|
|
|
|
if ((err == VK_ERROR_OUT_OF_DATE_KHR) || (err == VK_SUBOPTIMAL_KHR)) {
|
|
|
|
|
windowResize();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
VK_CHECK_RESULT(err);
|
|
|
|
|
}
|
2016-05-15 20:11:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::submitFrame()
|
|
|
|
|
{
|
2018-08-29 20:49:13 +02:00
|
|
|
VkResult res = swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete);
|
2018-06-30 21:55:29 +02:00
|
|
|
if (!((res == VK_SUCCESS) || (res == VK_SUBOPTIMAL_KHR))) {
|
|
|
|
|
if (res == VK_ERROR_OUT_OF_DATE_KHR) {
|
|
|
|
|
// Swap chain is no longer compatible with the surface and needs to be recreated
|
|
|
|
|
windowResize();
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
VK_CHECK_RESULT(res);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-05-15 20:11:28 +02:00
|
|
|
VK_CHECK_RESULT(vkQueueWaitIdle(queue));
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-14 20:17:15 +01:00
|
|
|
VulkanExampleBase::VulkanExampleBase(bool enableValidation)
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
2017-08-13 10:24:25 +02:00
|
|
|
#if !defined(VK_USE_PLATFORM_ANDROID_KHR)
|
2017-01-27 19:02:55 +01:00
|
|
|
// Check for a valid asset path
|
|
|
|
|
struct stat info;
|
|
|
|
|
if (stat(getAssetPath().c_str(), &info) != 0)
|
|
|
|
|
{
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
|
std::string msg = "Could not locate asset path in \"" + getAssetPath() + "\" !";
|
|
|
|
|
MessageBox(NULL, msg.c_str(), "Fatal error", MB_OK | MB_ICONERROR);
|
|
|
|
|
#else
|
|
|
|
|
std::cerr << "Error: Could not find asset path in " << getAssetPath() << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
exit(-1);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-01-22 13:38:57 +01:00
|
|
|
settings.validation = enableValidation;
|
|
|
|
|
|
2018-01-12 21:54:01 +01:00
|
|
|
char* numConvPtr;
|
|
|
|
|
|
2016-11-10 22:29:55 +01:00
|
|
|
// Parse command line arguments
|
2017-01-22 12:29:27 +01:00
|
|
|
for (size_t i = 0; i < args.size(); i++)
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
2017-07-29 19:31:00 +02:00
|
|
|
if (args[i] == std::string("-validation")) {
|
2017-01-22 13:38:57 +01:00
|
|
|
settings.validation = true;
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
2017-07-29 19:31:00 +02:00
|
|
|
if (args[i] == std::string("-vsync")) {
|
2017-01-22 13:38:57 +01:00
|
|
|
settings.vsync = true;
|
|
|
|
|
}
|
2018-01-27 14:37:23 +01:00
|
|
|
if ((args[i] == std::string("-f")) || (args[i] == std::string("--fullscreen"))) {
|
2017-01-22 13:38:57 +01:00
|
|
|
settings.fullscreen = true;
|
2016-06-12 17:20:42 +02:00
|
|
|
}
|
2017-07-29 19:31:00 +02:00
|
|
|
if ((args[i] == std::string("-w")) || (args[i] == std::string("-width"))) {
|
2018-01-12 21:54:01 +01:00
|
|
|
uint32_t w = strtol(args[i + 1], &numConvPtr, 10);
|
|
|
|
|
if (numConvPtr != args[i + 1]) { width = w; };
|
2017-01-22 12:29:27 +01:00
|
|
|
}
|
2017-07-29 19:31:00 +02:00
|
|
|
if ((args[i] == std::string("-h")) || (args[i] == std::string("-height"))) {
|
2018-01-12 21:54:01 +01:00
|
|
|
uint32_t h = strtol(args[i + 1], &numConvPtr, 10);
|
|
|
|
|
if (numConvPtr != args[i + 1]) { height = h; };
|
2017-01-22 12:29:27 +01:00
|
|
|
}
|
2018-01-13 10:39:03 +01:00
|
|
|
// Benchmark
|
|
|
|
|
if ((args[i] == std::string("-b")) || (args[i] == std::string("--benchmark"))) {
|
2017-07-29 19:31:00 +02:00
|
|
|
benchmark.active = true;
|
2018-01-21 10:58:30 +01:00
|
|
|
vks::tools::errorModeSilent = true;
|
2018-01-13 10:39:03 +01:00
|
|
|
}
|
|
|
|
|
// Warmup time (in seconds)
|
|
|
|
|
if ((args[i] == std::string("-bw")) || (args[i] == std::string("--benchwarmup"))) {
|
2017-07-29 19:31:00 +02:00
|
|
|
if (args.size() > i + 1) {
|
2018-01-12 21:54:01 +01:00
|
|
|
uint32_t num = strtol(args[i + 1], &numConvPtr, 10);
|
|
|
|
|
if (numConvPtr != args[i + 1]) {
|
|
|
|
|
benchmark.warmup = num;
|
|
|
|
|
} else {
|
|
|
|
|
std::cerr << "Warmup time for benchmark mode must be specified as a number!" << std::endl;
|
|
|
|
|
}
|
2017-08-13 11:10:41 +02:00
|
|
|
}
|
2018-01-13 10:39:03 +01:00
|
|
|
}
|
|
|
|
|
// Benchmark runtime (in seconds)
|
|
|
|
|
if ((args[i] == std::string("-br")) || (args[i] == std::string("--benchruntime"))) {
|
|
|
|
|
if (args.size() > i + 1) {
|
|
|
|
|
uint32_t num = strtol(args[i + 1], &numConvPtr, 10);
|
|
|
|
|
if (numConvPtr != args[i + 1]) {
|
2018-01-12 21:54:01 +01:00
|
|
|
benchmark.duration = num;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
std::cerr << "Benchmark run duration must be specified as a number!" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-13 10:39:03 +01:00
|
|
|
}
|
|
|
|
|
// Bench result save filename (overrides default)
|
|
|
|
|
if ((args[i] == std::string("-bf")) || (args[i] == std::string("--benchfilename"))) {
|
|
|
|
|
if (args.size() > i + 1) {
|
|
|
|
|
if (args[i + 1][0] == '-') {
|
2018-01-12 21:54:01 +01:00
|
|
|
std::cerr << "Filename for benchmark results must not start with a hyphen!" << std::endl;
|
|
|
|
|
} else {
|
2018-01-13 10:39:03 +01:00
|
|
|
benchmark.filename = args[i + 1];
|
2018-01-12 21:54:01 +01:00
|
|
|
}
|
2017-07-29 19:31:00 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-01-13 10:39:03 +01:00
|
|
|
// Output frame times to benchmark result file
|
|
|
|
|
if ((args[i] == std::string("-bt")) || (args[i] == std::string("--benchframetimes"))) {
|
|
|
|
|
benchmark.outputFrameTimes = true;
|
|
|
|
|
}
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
2017-01-27 19:02:55 +01:00
|
|
|
|
2017-08-13 10:24:25 +02:00
|
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
2016-03-20 14:55:46 +01:00
|
|
|
// Vulkan library is loaded dynamically on Android
|
2017-03-10 17:23:17 +01:00
|
|
|
bool libLoaded = vks::android::loadVulkanLibrary();
|
2016-03-20 14:55:46 +01:00
|
|
|
assert(libLoaded);
|
2016-11-04 13:32:58 -07:00
|
|
|
#elif defined(_DIRECT2DISPLAY)
|
|
|
|
|
|
2017-02-02 08:54:56 +00:00
|
|
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
|
|
|
initWaylandConnection();
|
2017-08-13 10:24:25 +02:00
|
|
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
2016-02-16 15:07:25 +01:00
|
|
|
initxcbConnection();
|
|
|
|
|
#endif
|
2016-03-20 14:55:46 +01:00
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
2016-02-16 15:07:25 +01:00
|
|
|
// Enable console if validation is active
|
|
|
|
|
// Debug message callback will output to it
|
2017-01-22 13:38:57 +01:00
|
|
|
if (this->settings.validation)
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
2017-01-22 12:29:27 +01:00
|
|
|
setupConsole("Vulkan validation output");
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
2018-04-23 21:28:35 +03:00
|
|
|
setupDPIAwareness();
|
2016-02-16 15:07:25 +01:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VulkanExampleBase::~VulkanExampleBase()
|
|
|
|
|
{
|
|
|
|
|
// Clean up Vulkan resources
|
|
|
|
|
swapChain.cleanup();
|
2016-04-02 12:47:08 +02:00
|
|
|
if (descriptorPool != VK_NULL_HANDLE)
|
|
|
|
|
{
|
|
|
|
|
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
|
|
|
|
|
}
|
2016-02-16 15:07:25 +01:00
|
|
|
destroyCommandBuffers();
|
|
|
|
|
vkDestroyRenderPass(device, renderPass, nullptr);
|
|
|
|
|
for (uint32_t i = 0; i < frameBuffers.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
vkDestroyFramebuffer(device, frameBuffers[i], nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto& shaderModule : shaderModules)
|
|
|
|
|
{
|
|
|
|
|
vkDestroyShaderModule(device, shaderModule, nullptr);
|
|
|
|
|
}
|
|
|
|
|
vkDestroyImageView(device, depthStencil.view, nullptr);
|
|
|
|
|
vkDestroyImage(device, depthStencil.image, nullptr);
|
|
|
|
|
vkFreeMemory(device, depthStencil.mem, nullptr);
|
|
|
|
|
|
|
|
|
|
vkDestroyPipelineCache(device, pipelineCache, nullptr);
|
|
|
|
|
|
|
|
|
|
vkDestroyCommandPool(device, cmdPool, nullptr);
|
|
|
|
|
|
2016-03-06 19:22:41 +01:00
|
|
|
vkDestroySemaphore(device, semaphores.presentComplete, nullptr);
|
|
|
|
|
vkDestroySemaphore(device, semaphores.renderComplete, nullptr);
|
2018-06-03 09:38:14 +02:00
|
|
|
for (auto& fence : waitFences) {
|
|
|
|
|
vkDestroyFence(device, fence, nullptr);
|
|
|
|
|
}
|
2016-05-15 18:31:31 +02:00
|
|
|
|
2017-10-29 11:41:43 +01:00
|
|
|
if (UIOverlay) {
|
|
|
|
|
delete UIOverlay;
|
2016-05-15 18:31:31 +02:00
|
|
|
}
|
2016-03-06 12:57:23 +01:00
|
|
|
|
2016-07-22 20:45:48 +02:00
|
|
|
delete vulkanDevice;
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2017-01-22 13:38:57 +01:00
|
|
|
if (settings.validation)
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
2017-02-12 11:33:04 +01:00
|
|
|
vks::debug::freeDebugCallback(instance);
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vkDestroyInstance(instance, nullptr);
|
|
|
|
|
|
2016-11-04 13:32:58 -07:00
|
|
|
#if defined(_DIRECT2DISPLAY)
|
|
|
|
|
|
2017-02-02 08:54:56 +00:00
|
|
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
|
|
|
wl_shell_surface_destroy(shell_surface);
|
|
|
|
|
wl_surface_destroy(surface);
|
|
|
|
|
if (keyboard)
|
|
|
|
|
wl_keyboard_destroy(keyboard);
|
|
|
|
|
if (pointer)
|
|
|
|
|
wl_pointer_destroy(pointer);
|
|
|
|
|
wl_seat_destroy(seat);
|
|
|
|
|
wl_shell_destroy(shell);
|
|
|
|
|
wl_compositor_destroy(compositor);
|
|
|
|
|
wl_registry_destroy(registry);
|
|
|
|
|
wl_display_disconnect(display);
|
2017-08-13 10:24:25 +02:00
|
|
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
2016-03-20 14:55:46 +01:00
|
|
|
// todo : android cleanup (if required)
|
2017-08-13 10:24:25 +02:00
|
|
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
2016-02-16 15:07:25 +01:00
|
|
|
xcb_destroy_window(connection, window);
|
|
|
|
|
xcb_disconnect(connection);
|
2016-03-13 17:15:44 +01:00
|
|
|
#endif
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
2018-05-01 11:23:36 +02:00
|
|
|
bool VulkanExampleBase::initVulkan()
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
|
|
|
|
VkResult err;
|
|
|
|
|
|
|
|
|
|
// Vulkan instance
|
2017-01-22 13:38:57 +01:00
|
|
|
err = createInstance(settings.validation);
|
2017-08-26 15:05:59 +02:00
|
|
|
if (err) {
|
2018-01-21 18:28:17 +01:00
|
|
|
vks::tools::exitFatal("Could not create Vulkan instance : \n" + vks::tools::errorString(err), err);
|
2018-05-01 11:23:36 +02:00
|
|
|
return false;
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-08-13 10:24:25 +02:00
|
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
2017-03-10 17:23:17 +01:00
|
|
|
vks::android::loadVulkanFunctions(instance);
|
2016-03-20 14:55:46 +01:00
|
|
|
#endif
|
|
|
|
|
|
2016-07-22 22:24:27 +02:00
|
|
|
// If requested, we enable the default validation layers for debugging
|
2017-01-22 13:38:57 +01:00
|
|
|
if (settings.validation)
|
2016-07-22 22:24:27 +02:00
|
|
|
{
|
|
|
|
|
// The report flags determine what type of messages for the layers will be displayed
|
|
|
|
|
// For validating (debugging) an appplication the error and warning bits should suffice
|
2017-03-13 19:24:07 +01:00
|
|
|
VkDebugReportFlagsEXT debugReportFlags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
|
2016-07-22 22:24:27 +02:00
|
|
|
// Additional flags include performance info, loader and layer debug messages, etc.
|
2017-02-12 11:33:04 +01:00
|
|
|
vks::debug::setupDebugging(instance, debugReportFlags, VK_NULL_HANDLE);
|
2016-07-22 22:24:27 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-16 15:07:25 +01:00
|
|
|
// Physical device
|
2016-02-17 18:37:36 +01:00
|
|
|
uint32_t gpuCount = 0;
|
|
|
|
|
// Get number of available physical devices
|
2016-05-22 20:27:06 +02:00
|
|
|
VK_CHECK_RESULT(vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr));
|
2016-02-17 18:37:36 +01:00
|
|
|
assert(gpuCount > 0);
|
|
|
|
|
// Enumerate devices
|
|
|
|
|
std::vector<VkPhysicalDevice> physicalDevices(gpuCount);
|
|
|
|
|
err = vkEnumeratePhysicalDevices(instance, &gpuCount, physicalDevices.data());
|
2017-08-26 15:05:59 +02:00
|
|
|
if (err) {
|
2018-01-21 18:28:17 +01:00
|
|
|
vks::tools::exitFatal("Could not enumerate physical devices : \n" + vks::tools::errorString(err), err);
|
2018-05-01 11:23:36 +02:00
|
|
|
return false;
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-04 13:52:41 +01:00
|
|
|
// GPU selection
|
|
|
|
|
|
|
|
|
|
// Select physical device to be used for the Vulkan example
|
|
|
|
|
// Defaults to the first device unless specified by command line
|
|
|
|
|
uint32_t selectedDevice = 0;
|
|
|
|
|
|
2017-08-13 10:24:25 +02:00
|
|
|
#if !defined(VK_USE_PLATFORM_ANDROID_KHR)
|
2017-02-04 13:52:41 +01:00
|
|
|
// GPU selection via command line argument
|
|
|
|
|
for (size_t i = 0; i < args.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
// Select GPU
|
|
|
|
|
if ((args[i] == std::string("-g")) || (args[i] == std::string("-gpu")))
|
|
|
|
|
{
|
|
|
|
|
char* endptr;
|
|
|
|
|
uint32_t index = strtol(args[i + 1], &endptr, 10);
|
|
|
|
|
if (endptr != args[i + 1])
|
|
|
|
|
{
|
|
|
|
|
if (index > gpuCount - 1)
|
|
|
|
|
{
|
|
|
|
|
std::cerr << "Selected device index " << index << " is out of range, reverting to device 0 (use -listgpus to show available Vulkan devices)" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Selected Vulkan device " << index << std::endl;
|
|
|
|
|
selectedDevice = index;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// List available GPUs
|
|
|
|
|
if (args[i] == std::string("-listgpus"))
|
|
|
|
|
{
|
|
|
|
|
uint32_t gpuCount = 0;
|
|
|
|
|
VK_CHECK_RESULT(vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr));
|
|
|
|
|
if (gpuCount == 0)
|
|
|
|
|
{
|
|
|
|
|
std::cerr << "No Vulkan devices found!" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Enumerate devices
|
|
|
|
|
std::cout << "Available Vulkan devices" << std::endl;
|
|
|
|
|
std::vector<VkPhysicalDevice> devices(gpuCount);
|
|
|
|
|
VK_CHECK_RESULT(vkEnumeratePhysicalDevices(instance, &gpuCount, devices.data()));
|
|
|
|
|
for (uint32_t i = 0; i < gpuCount; i++) {
|
|
|
|
|
VkPhysicalDeviceProperties deviceProperties;
|
|
|
|
|
vkGetPhysicalDeviceProperties(devices[i], &deviceProperties);
|
|
|
|
|
std::cout << "Device [" << i << "] : " << deviceProperties.deviceName << std::endl;
|
2017-02-12 13:10:05 +01:00
|
|
|
std::cout << " Type: " << vks::tools::physicalDeviceTypeString(deviceProperties.deviceType) << std::endl;
|
2017-02-04 13:52:41 +01:00
|
|
|
std::cout << " API: " << (deviceProperties.apiVersion >> 22) << "." << ((deviceProperties.apiVersion >> 12) & 0x3ff) << "." << (deviceProperties.apiVersion & 0xfff) << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
physicalDevice = physicalDevices[selectedDevice];
|
2016-02-17 18:37:36 +01:00
|
|
|
|
2017-03-08 21:29:38 +01:00
|
|
|
// Store properties (including limits), features and memory properties of the phyiscal device (so that examples can check against them)
|
|
|
|
|
vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
|
|
|
|
|
vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
|
|
|
|
|
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties);
|
|
|
|
|
|
|
|
|
|
// Derived examples can override this to set actual features (based on above readings) to enable for logical device creation
|
|
|
|
|
getEnabledFeatures();
|
|
|
|
|
|
2016-07-16 17:36:35 +02:00
|
|
|
// Vulkan device creation
|
2016-07-22 22:24:27 +02:00
|
|
|
// This is handled by a separate class that gets a logical device representation
|
|
|
|
|
// and encapsulates functions related to a device
|
2017-02-12 10:16:07 +01:00
|
|
|
vulkanDevice = new vks::VulkanDevice(physicalDevice);
|
2018-03-03 11:49:46 +01:00
|
|
|
VkResult res = vulkanDevice->createLogicalDevice(enabledFeatures, enabledDeviceExtensions);
|
2017-02-09 19:22:48 +01:00
|
|
|
if (res != VK_SUCCESS) {
|
2018-01-21 18:28:17 +01:00
|
|
|
vks::tools::exitFatal("Could not create Vulkan device: \n" + vks::tools::errorString(res), res);
|
2018-05-01 11:23:36 +02:00
|
|
|
return false;
|
2017-02-09 19:22:48 +01:00
|
|
|
}
|
2016-07-22 20:45:48 +02:00
|
|
|
device = vulkanDevice->logicalDevice;
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2016-07-22 22:24:27 +02:00
|
|
|
// Get a graphics queue from the device
|
|
|
|
|
vkGetDeviceQueue(device, vulkanDevice->queueFamilyIndices.graphics, 0, &queue);
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2016-02-18 22:09:47 +01:00
|
|
|
// Find a suitable depth format
|
2017-02-12 13:10:05 +01:00
|
|
|
VkBool32 validDepthFormat = vks::tools::getSupportedDepthFormat(physicalDevice, &depthFormat);
|
2016-02-18 21:44:26 +01:00
|
|
|
assert(validDepthFormat);
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2016-02-23 22:00:09 +01:00
|
|
|
swapChain.connect(instance, physicalDevice, device);
|
2016-03-06 12:57:23 +01:00
|
|
|
|
2016-03-06 19:22:41 +01:00
|
|
|
// Create synchronization objects
|
2017-02-12 11:12:42 +01:00
|
|
|
VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo();
|
2016-03-06 12:57:23 +01:00
|
|
|
// Create a semaphore used to synchronize image presentation
|
2016-03-06 19:22:41 +01:00
|
|
|
// Ensures that the image is displayed before we start submitting new commands to the queu
|
2016-05-15 18:31:31 +02:00
|
|
|
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &semaphores.presentComplete));
|
2016-03-06 19:22:41 +01:00
|
|
|
// Create a semaphore used to synchronize command submission
|
|
|
|
|
// Ensures that the image is not presented until all commands have been sumbitted and executed
|
2016-05-15 18:31:31 +02:00
|
|
|
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &semaphores.renderComplete));
|
2016-03-06 19:22:41 +01:00
|
|
|
|
|
|
|
|
// Set up submit info structure
|
|
|
|
|
// Semaphores will stay the same during application lifetime
|
|
|
|
|
// Command buffer submission info is set by each example
|
2017-02-12 11:12:42 +01:00
|
|
|
submitInfo = vks::initializers::submitInfo();
|
2016-03-06 19:22:41 +01:00
|
|
|
submitInfo.pWaitDstStageMask = &submitPipelineStages;
|
|
|
|
|
submitInfo.waitSemaphoreCount = 1;
|
|
|
|
|
submitInfo.pWaitSemaphores = &semaphores.presentComplete;
|
|
|
|
|
submitInfo.signalSemaphoreCount = 1;
|
|
|
|
|
submitInfo.pSignalSemaphores = &semaphores.renderComplete;
|
2017-03-06 21:54:06 +01:00
|
|
|
|
2017-08-13 10:24:25 +02:00
|
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
2017-03-06 21:54:06 +01:00
|
|
|
// Get Android device name and manufacturer (to display along GPU name)
|
|
|
|
|
androidProduct = "";
|
|
|
|
|
char prop[PROP_VALUE_MAX+1];
|
|
|
|
|
int len = __system_property_get("ro.product.manufacturer", prop);
|
|
|
|
|
if (len > 0) {
|
|
|
|
|
androidProduct += std::string(prop) + " ";
|
|
|
|
|
};
|
|
|
|
|
len = __system_property_get("ro.product.model", prop);
|
|
|
|
|
if (len > 0) {
|
|
|
|
|
androidProduct += std::string(prop);
|
|
|
|
|
};
|
|
|
|
|
LOGD("androidProduct = %s", androidProduct.c_str());
|
|
|
|
|
#endif
|
2018-05-01 11:23:36 +02:00
|
|
|
|
|
|
|
|
return true;
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-20 14:55:46 +01:00
|
|
|
#if defined(_WIN32)
|
2016-02-16 15:07:25 +01:00
|
|
|
// Win32 : Sets up a console window and redirects standard output to it
|
|
|
|
|
void VulkanExampleBase::setupConsole(std::string title)
|
|
|
|
|
{
|
|
|
|
|
AllocConsole();
|
|
|
|
|
AttachConsole(GetCurrentProcessId());
|
2016-05-22 20:27:06 +02:00
|
|
|
FILE *stream;
|
|
|
|
|
freopen_s(&stream, "CONOUT$", "w+", stdout);
|
2017-02-04 13:52:41 +01:00
|
|
|
freopen_s(&stream, "CONOUT$", "w+", stderr);
|
2016-02-16 15:07:25 +01:00
|
|
|
SetConsoleTitle(TEXT(title.c_str()));
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-23 21:28:35 +03:00
|
|
|
void VulkanExampleBase::setupDPIAwareness()
|
|
|
|
|
{
|
|
|
|
|
using SetProcessDpiAwarenessFunc = HRESULT(*)(PROCESS_DPI_AWARENESS);
|
|
|
|
|
|
|
|
|
|
HMODULE shCore = LoadLibraryA("Shcore.dll");
|
|
|
|
|
if (shCore)
|
|
|
|
|
{
|
|
|
|
|
SetProcessDpiAwarenessFunc setProcessDpiAwareness =
|
|
|
|
|
(SetProcessDpiAwarenessFunc)GetProcAddress(shCore, "SetProcessDpiAwareness");
|
|
|
|
|
|
|
|
|
|
if (setProcessDpiAwareness != nullptr)
|
|
|
|
|
{
|
|
|
|
|
setProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FreeLibrary(shCore);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-16 15:07:25 +01:00
|
|
|
HWND VulkanExampleBase::setupWindow(HINSTANCE hinstance, WNDPROC wndproc)
|
|
|
|
|
{
|
|
|
|
|
this->windowInstance = hinstance;
|
|
|
|
|
|
|
|
|
|
WNDCLASSEX wndClass;
|
|
|
|
|
|
|
|
|
|
wndClass.cbSize = sizeof(WNDCLASSEX);
|
|
|
|
|
wndClass.style = CS_HREDRAW | CS_VREDRAW;
|
|
|
|
|
wndClass.lpfnWndProc = wndproc;
|
|
|
|
|
wndClass.cbClsExtra = 0;
|
|
|
|
|
wndClass.cbWndExtra = 0;
|
|
|
|
|
wndClass.hInstance = hinstance;
|
|
|
|
|
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
|
|
|
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
2016-02-27 22:27:09 +01:00
|
|
|
wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
2016-02-16 15:07:25 +01:00
|
|
|
wndClass.lpszMenuName = NULL;
|
|
|
|
|
wndClass.lpszClassName = name.c_str();
|
|
|
|
|
wndClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
|
|
|
|
|
|
|
|
|
|
if (!RegisterClassEx(&wndClass))
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Could not register window class!\n";
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
|
|
|
|
|
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
|
|
|
|
|
|
2017-01-22 13:38:57 +01:00
|
|
|
if (settings.fullscreen)
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
|
|
|
|
DEVMODE dmScreenSettings;
|
|
|
|
|
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
|
|
|
|
|
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
|
|
|
|
|
dmScreenSettings.dmPelsWidth = screenWidth;
|
|
|
|
|
dmScreenSettings.dmPelsHeight = screenHeight;
|
|
|
|
|
dmScreenSettings.dmBitsPerPel = 32;
|
|
|
|
|
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
|
|
|
|
|
|
2017-04-22 16:54:25 +02:00
|
|
|
if ((width != (uint32_t)screenWidth) && (height != (uint32_t)screenHeight))
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
|
|
|
|
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
|
|
|
|
|
{
|
|
|
|
|
if (MessageBox(NULL, "Fullscreen Mode not supported!\n Switch to window mode?", "Error", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
|
|
|
|
|
{
|
2017-01-22 13:38:57 +01:00
|
|
|
settings.fullscreen = false;
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-04-22 11:47:34 +02:00
|
|
|
return nullptr;
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD dwExStyle;
|
|
|
|
|
DWORD dwStyle;
|
|
|
|
|
|
2017-01-22 13:38:57 +01:00
|
|
|
if (settings.fullscreen)
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
|
|
|
|
dwExStyle = WS_EX_APPWINDOW;
|
|
|
|
|
dwStyle = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
|
|
|
|
|
dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RECT windowRect;
|
2016-07-28 23:07:04 +02:00
|
|
|
windowRect.left = 0L;
|
|
|
|
|
windowRect.top = 0L;
|
2017-01-22 13:38:57 +01:00
|
|
|
windowRect.right = settings.fullscreen ? (long)screenWidth : (long)width;
|
|
|
|
|
windowRect.bottom = settings.fullscreen ? (long)screenHeight : (long)height;
|
2016-02-16 15:07:25 +01:00
|
|
|
|
|
|
|
|
AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);
|
|
|
|
|
|
2016-03-13 16:51:00 +01:00
|
|
|
std::string windowTitle = getWindowTitle();
|
2016-02-16 15:07:25 +01:00
|
|
|
window = CreateWindowEx(0,
|
|
|
|
|
name.c_str(),
|
2016-03-13 16:51:00 +01:00
|
|
|
windowTitle.c_str(),
|
2016-02-16 15:07:25 +01:00
|
|
|
dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
2016-07-28 23:07:04 +02:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
windowRect.right - windowRect.left,
|
|
|
|
|
windowRect.bottom - windowRect.top,
|
2016-02-16 15:07:25 +01:00
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
hinstance,
|
|
|
|
|
NULL);
|
|
|
|
|
|
2017-01-22 13:38:57 +01:00
|
|
|
if (!settings.fullscreen)
|
2016-07-28 23:07:04 +02:00
|
|
|
{
|
|
|
|
|
// Center on screen
|
|
|
|
|
uint32_t x = (GetSystemMetrics(SM_CXSCREEN) - windowRect.right) / 2;
|
|
|
|
|
uint32_t y = (GetSystemMetrics(SM_CYSCREEN) - windowRect.bottom) / 2;
|
|
|
|
|
SetWindowPos(window, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-13 17:15:44 +01:00
|
|
|
if (!window)
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
|
|
|
|
printf("Could not create window!\n");
|
|
|
|
|
fflush(stdout);
|
2017-04-22 11:47:34 +02:00
|
|
|
return nullptr;
|
2016-02-16 15:07:25 +01:00
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ShowWindow(window, SW_SHOW);
|
|
|
|
|
SetForegroundWindow(window);
|
|
|
|
|
SetFocus(window);
|
|
|
|
|
|
|
|
|
|
return window;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
|
|
{
|
|
|
|
|
switch (uMsg)
|
|
|
|
|
{
|
|
|
|
|
case WM_CLOSE:
|
|
|
|
|
prepared = false;
|
|
|
|
|
DestroyWindow(hWnd);
|
|
|
|
|
PostQuitMessage(0);
|
|
|
|
|
break;
|
|
|
|
|
case WM_PAINT:
|
|
|
|
|
ValidateRect(window, NULL);
|
|
|
|
|
break;
|
|
|
|
|
case WM_KEYDOWN:
|
|
|
|
|
switch (wParam)
|
|
|
|
|
{
|
2016-08-04 20:58:02 +02:00
|
|
|
case KEY_P:
|
2016-02-16 15:07:25 +01:00
|
|
|
paused = !paused;
|
|
|
|
|
break;
|
2016-08-04 20:58:02 +02:00
|
|
|
case KEY_F1:
|
2017-10-29 11:41:43 +01:00
|
|
|
if (settings.overlay) {
|
|
|
|
|
UIOverlay->visible = !UIOverlay->visible;
|
2016-05-15 20:11:28 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2016-08-04 21:18:48 +02:00
|
|
|
case KEY_ESCAPE:
|
2016-05-19 20:25:09 +02:00
|
|
|
PostQuitMessage(0);
|
2016-02-16 15:07:25 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2016-06-11 15:54:16 +02:00
|
|
|
|
2016-06-20 22:08:50 +02:00
|
|
|
if (camera.firstperson)
|
2016-06-11 15:54:16 +02:00
|
|
|
{
|
|
|
|
|
switch (wParam)
|
|
|
|
|
{
|
2016-08-04 21:18:48 +02:00
|
|
|
case KEY_W:
|
2016-06-11 15:54:16 +02:00
|
|
|
camera.keys.up = true;
|
|
|
|
|
break;
|
2016-08-04 21:18:48 +02:00
|
|
|
case KEY_S:
|
2016-06-11 15:54:16 +02:00
|
|
|
camera.keys.down = true;
|
|
|
|
|
break;
|
2016-08-04 21:18:48 +02:00
|
|
|
case KEY_A:
|
2016-06-11 15:54:16 +02:00
|
|
|
camera.keys.left = true;
|
|
|
|
|
break;
|
2016-08-04 21:18:48 +02:00
|
|
|
case KEY_D:
|
2016-06-11 15:54:16 +02:00
|
|
|
camera.keys.right = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-03 16:41:57 +01:00
|
|
|
keyPressed((uint32_t)wParam);
|
2016-02-16 15:07:25 +01:00
|
|
|
break;
|
2016-06-11 15:54:16 +02:00
|
|
|
case WM_KEYUP:
|
2016-06-20 22:08:50 +02:00
|
|
|
if (camera.firstperson)
|
2016-06-11 15:54:16 +02:00
|
|
|
{
|
|
|
|
|
switch (wParam)
|
|
|
|
|
{
|
2016-08-04 21:18:48 +02:00
|
|
|
case KEY_W:
|
2016-06-11 15:54:16 +02:00
|
|
|
camera.keys.up = false;
|
|
|
|
|
break;
|
2016-08-04 21:18:48 +02:00
|
|
|
case KEY_S:
|
2016-06-11 15:54:16 +02:00
|
|
|
camera.keys.down = false;
|
|
|
|
|
break;
|
2016-08-04 21:18:48 +02:00
|
|
|
case KEY_A:
|
2016-06-11 15:54:16 +02:00
|
|
|
camera.keys.left = false;
|
|
|
|
|
break;
|
2016-08-04 21:18:48 +02:00
|
|
|
case KEY_D:
|
2016-06-11 15:54:16 +02:00
|
|
|
camera.keys.right = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-02-16 15:07:25 +01:00
|
|
|
case WM_LBUTTONDOWN:
|
2017-10-05 21:22:10 +02:00
|
|
|
mousePos = glm::vec2((float)LOWORD(lParam), (float)HIWORD(lParam));
|
|
|
|
|
mouseButtons.left = true;
|
|
|
|
|
break;
|
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
|
mousePos = glm::vec2((float)LOWORD(lParam), (float)HIWORD(lParam));
|
|
|
|
|
mouseButtons.right = true;
|
|
|
|
|
break;
|
2016-03-30 22:48:58 +02:00
|
|
|
case WM_MBUTTONDOWN:
|
2017-10-05 21:22:10 +02:00
|
|
|
mousePos = glm::vec2((float)LOWORD(lParam), (float)HIWORD(lParam));
|
|
|
|
|
mouseButtons.middle = true;
|
|
|
|
|
break;
|
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
|
mouseButtons.left = false;
|
|
|
|
|
break;
|
|
|
|
|
case WM_RBUTTONUP:
|
|
|
|
|
mouseButtons.right = false;
|
|
|
|
|
break;
|
|
|
|
|
case WM_MBUTTONUP:
|
|
|
|
|
mouseButtons.middle = false;
|
2016-02-16 15:07:25 +01:00
|
|
|
break;
|
2016-03-17 20:20:43 +01:00
|
|
|
case WM_MOUSEWHEEL:
|
|
|
|
|
{
|
|
|
|
|
short wheelDelta = GET_WHEEL_DELTA_WPARAM(wParam);
|
|
|
|
|
zoom += (float)wheelDelta * 0.005f * zoomSpeed;
|
2016-06-11 15:54:16 +02:00
|
|
|
camera.translate(glm::vec3(0.0f, 0.0f, (float)wheelDelta * 0.005f * zoomSpeed));
|
2016-07-31 12:41:50 +02:00
|
|
|
viewUpdated = true;
|
2016-03-17 20:20:43 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2016-02-16 15:07:25 +01:00
|
|
|
case WM_MOUSEMOVE:
|
2017-10-05 21:22:10 +02:00
|
|
|
{
|
2017-11-02 13:40:27 +01:00
|
|
|
handleMouseMove(LOWORD(lParam), HIWORD(lParam));
|
2016-02-16 15:07:25 +01:00
|
|
|
break;
|
2017-10-05 21:22:10 +02:00
|
|
|
}
|
2016-04-10 11:12:04 +02:00
|
|
|
case WM_SIZE:
|
|
|
|
|
if ((prepared) && (wParam != SIZE_MINIMIZED))
|
|
|
|
|
{
|
2016-10-16 17:39:30 +02:00
|
|
|
if ((resizing) || ((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED)))
|
2016-04-10 11:12:04 +02:00
|
|
|
{
|
2016-10-16 17:39:30 +02:00
|
|
|
destWidth = LOWORD(lParam);
|
|
|
|
|
destHeight = HIWORD(lParam);
|
2016-04-10 11:12:04 +02:00
|
|
|
windowResize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-10-16 17:39:30 +02:00
|
|
|
case WM_ENTERSIZEMOVE:
|
|
|
|
|
resizing = true;
|
|
|
|
|
break;
|
2016-04-10 11:12:04 +02:00
|
|
|
case WM_EXITSIZEMOVE:
|
2016-10-16 17:39:30 +02:00
|
|
|
resizing = false;
|
2016-04-10 11:12:04 +02:00
|
|
|
break;
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
2017-08-13 10:24:25 +02:00
|
|
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
2016-03-20 21:46:49 +01:00
|
|
|
int32_t VulkanExampleBase::handleAppInput(struct android_app* app, AInputEvent* event)
|
|
|
|
|
{
|
2016-08-02 20:41:16 +02:00
|
|
|
VulkanExampleBase* vulkanExample = reinterpret_cast<VulkanExampleBase*>(app->userData);
|
2016-03-20 21:46:49 +01:00
|
|
|
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
|
|
|
|
|
{
|
2017-03-06 21:16:51 +01:00
|
|
|
int32_t eventSource = AInputEvent_getSource(event);
|
|
|
|
|
switch (eventSource) {
|
|
|
|
|
case AINPUT_SOURCE_JOYSTICK: {
|
|
|
|
|
// Left thumbstick
|
|
|
|
|
vulkanExample->gamePadState.axisLeft.x = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_X, 0);
|
|
|
|
|
vulkanExample->gamePadState.axisLeft.y = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_Y, 0);
|
|
|
|
|
// Right thumbstick
|
|
|
|
|
vulkanExample->gamePadState.axisRight.x = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_Z, 0);
|
|
|
|
|
vulkanExample->gamePadState.axisRight.y = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_RZ, 0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case AINPUT_SOURCE_TOUCHSCREEN: {
|
|
|
|
|
int32_t action = AMotionEvent_getAction(event);
|
|
|
|
|
|
|
|
|
|
switch (action) {
|
2017-03-06 22:11:19 +01:00
|
|
|
case AMOTION_EVENT_ACTION_UP: {
|
2017-03-25 11:51:32 +01:00
|
|
|
vulkanExample->lastTapTime = AMotionEvent_getEventTime(event);
|
|
|
|
|
vulkanExample->touchPos.x = AMotionEvent_getX(event, 0);
|
|
|
|
|
vulkanExample->touchPos.y = AMotionEvent_getY(event, 0);
|
2017-03-06 22:11:19 +01:00
|
|
|
vulkanExample->touchTimer = 0.0;
|
|
|
|
|
vulkanExample->touchDown = false;
|
|
|
|
|
vulkanExample->camera.keys.up = false;
|
2017-11-02 17:07:07 +01:00
|
|
|
|
|
|
|
|
// Detect single tap
|
|
|
|
|
int64_t eventTime = AMotionEvent_getEventTime(event);
|
|
|
|
|
int64_t downTime = AMotionEvent_getDownTime(event);
|
|
|
|
|
if (eventTime - downTime <= vks::android::TAP_TIMEOUT) {
|
|
|
|
|
float deadZone = (160.f / vks::android::screenDensity) * vks::android::TAP_SLOP * vks::android::TAP_SLOP;
|
|
|
|
|
float x = AMotionEvent_getX(event, 0) - vulkanExample->touchPos.x;
|
|
|
|
|
float y = AMotionEvent_getY(event, 0) - vulkanExample->touchPos.y;
|
|
|
|
|
if ((x * x + y * y) < deadZone) {
|
|
|
|
|
vulkanExample->mouseButtons.left = true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-03-06 22:11:19 +01:00
|
|
|
return 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-03-06 21:16:51 +01:00
|
|
|
case AMOTION_EVENT_ACTION_DOWN: {
|
2017-03-25 11:51:32 +01:00
|
|
|
// Detect double tap
|
|
|
|
|
int64_t eventTime = AMotionEvent_getEventTime(event);
|
|
|
|
|
if (eventTime - vulkanExample->lastTapTime <= vks::android::DOUBLE_TAP_TIMEOUT) {
|
|
|
|
|
float deadZone = (160.f / vks::android::screenDensity) * vks::android::DOUBLE_TAP_SLOP * vks::android::DOUBLE_TAP_SLOP;
|
|
|
|
|
float x = AMotionEvent_getX(event, 0) - vulkanExample->touchPos.x;
|
|
|
|
|
float y = AMotionEvent_getY(event, 0) - vulkanExample->touchPos.y;
|
|
|
|
|
if ((x * x + y * y) < deadZone) {
|
|
|
|
|
vulkanExample->keyPressed(TOUCH_DOUBLE_TAP);
|
|
|
|
|
vulkanExample->touchDown = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
vulkanExample->touchDown = true;
|
|
|
|
|
}
|
2017-03-06 21:16:51 +01:00
|
|
|
vulkanExample->touchPos.x = AMotionEvent_getX(event, 0);
|
|
|
|
|
vulkanExample->touchPos.y = AMotionEvent_getY(event, 0);
|
2017-11-02 17:07:07 +01:00
|
|
|
vulkanExample->mousePos.x = AMotionEvent_getX(event, 0);
|
|
|
|
|
vulkanExample->mousePos.y = AMotionEvent_getY(event, 0);
|
2017-03-06 21:16:51 +01:00
|
|
|
break;
|
2017-11-02 17:07:07 +01:00
|
|
|
}
|
2017-03-06 21:16:51 +01:00
|
|
|
case AMOTION_EVENT_ACTION_MOVE: {
|
2017-11-02 17:07:07 +01:00
|
|
|
bool handled = false;
|
|
|
|
|
if (vulkanExample->settings.overlay) {
|
|
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
|
|
|
handled = io.WantCaptureMouse;
|
|
|
|
|
}
|
|
|
|
|
if (!handled) {
|
|
|
|
|
int32_t eventX = AMotionEvent_getX(event, 0);
|
|
|
|
|
int32_t eventY = AMotionEvent_getY(event, 0);
|
2017-03-06 21:16:51 +01:00
|
|
|
|
2017-11-02 17:07:07 +01:00
|
|
|
float deltaX = (float)(vulkanExample->touchPos.y - eventY) * vulkanExample->rotationSpeed * 0.5f;
|
|
|
|
|
float deltaY = (float)(vulkanExample->touchPos.x - eventX) * vulkanExample->rotationSpeed * 0.5f;
|
2017-03-06 21:22:11 +01:00
|
|
|
|
2017-11-02 17:07:07 +01:00
|
|
|
vulkanExample->camera.rotate(glm::vec3(deltaX, 0.0f, 0.0f));
|
|
|
|
|
vulkanExample->camera.rotate(glm::vec3(0.0f, -deltaY, 0.0f));
|
2017-03-06 21:22:11 +01:00
|
|
|
|
2017-11-02 17:07:07 +01:00
|
|
|
vulkanExample->rotation.x += deltaX;
|
|
|
|
|
vulkanExample->rotation.y -= deltaY;
|
2017-03-06 21:22:11 +01:00
|
|
|
|
2017-11-02 17:07:07 +01:00
|
|
|
vulkanExample->viewChanged();
|
2017-03-06 21:16:51 +01:00
|
|
|
|
2017-11-02 17:07:07 +01:00
|
|
|
vulkanExample->touchPos.x = eventX;
|
|
|
|
|
vulkanExample->touchPos.y = eventY;
|
|
|
|
|
}
|
2017-03-06 21:16:51 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
2016-03-20 21:46:49 +01:00
|
|
|
}
|
|
|
|
|
}
|
2016-05-15 11:13:14 +02:00
|
|
|
|
|
|
|
|
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
|
|
|
|
|
{
|
|
|
|
|
int32_t keyCode = AKeyEvent_getKeyCode((const AInputEvent*)event);
|
|
|
|
|
int32_t action = AKeyEvent_getAction((const AInputEvent*)event);
|
|
|
|
|
int32_t button = 0;
|
|
|
|
|
|
|
|
|
|
if (action == AKEY_EVENT_ACTION_UP)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
switch (keyCode)
|
|
|
|
|
{
|
|
|
|
|
case AKEYCODE_BUTTON_A:
|
|
|
|
|
vulkanExample->keyPressed(GAMEPAD_BUTTON_A);
|
|
|
|
|
break;
|
|
|
|
|
case AKEYCODE_BUTTON_B:
|
|
|
|
|
vulkanExample->keyPressed(GAMEPAD_BUTTON_B);
|
|
|
|
|
break;
|
|
|
|
|
case AKEYCODE_BUTTON_X:
|
|
|
|
|
vulkanExample->keyPressed(GAMEPAD_BUTTON_X);
|
|
|
|
|
break;
|
|
|
|
|
case AKEYCODE_BUTTON_Y:
|
|
|
|
|
vulkanExample->keyPressed(GAMEPAD_BUTTON_Y);
|
|
|
|
|
break;
|
|
|
|
|
case AKEYCODE_BUTTON_L1:
|
|
|
|
|
vulkanExample->keyPressed(GAMEPAD_BUTTON_L1);
|
|
|
|
|
break;
|
|
|
|
|
case AKEYCODE_BUTTON_R1:
|
|
|
|
|
vulkanExample->keyPressed(GAMEPAD_BUTTON_R1);
|
|
|
|
|
break;
|
|
|
|
|
case AKEYCODE_BUTTON_START:
|
2016-07-18 21:33:59 +02:00
|
|
|
vulkanExample->paused = !vulkanExample->paused;
|
2016-05-15 11:13:14 +02:00
|
|
|
break;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
LOGD("Button %d pressed", keyCode);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 21:46:49 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 17:35:54 +01:00
|
|
|
void VulkanExampleBase::handleAppCommand(android_app * app, int32_t cmd)
|
|
|
|
|
{
|
|
|
|
|
assert(app->userData != NULL);
|
2016-08-02 20:41:16 +02:00
|
|
|
VulkanExampleBase* vulkanExample = reinterpret_cast<VulkanExampleBase*>(app->userData);
|
2016-03-20 17:35:54 +01:00
|
|
|
switch (cmd)
|
|
|
|
|
{
|
|
|
|
|
case APP_CMD_SAVE_STATE:
|
2016-03-26 12:58:35 +01:00
|
|
|
LOGD("APP_CMD_SAVE_STATE");
|
2016-03-20 17:35:54 +01:00
|
|
|
/*
|
|
|
|
|
vulkanExample->app->savedState = malloc(sizeof(struct saved_state));
|
|
|
|
|
*((struct saved_state*)vulkanExample->app->savedState) = vulkanExample->state;
|
|
|
|
|
vulkanExample->app->savedStateSize = sizeof(struct saved_state);
|
|
|
|
|
*/
|
|
|
|
|
break;
|
|
|
|
|
case APP_CMD_INIT_WINDOW:
|
|
|
|
|
LOGD("APP_CMD_INIT_WINDOW");
|
2017-01-18 19:21:40 +01:00
|
|
|
if (androidApp->window != NULL)
|
2016-03-20 17:35:54 +01:00
|
|
|
{
|
2018-05-01 11:23:36 +02:00
|
|
|
if (vulkanExample->initVulkan()) {
|
|
|
|
|
vulkanExample->prepare();
|
|
|
|
|
assert(vulkanExample->prepared);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
LOGE("Could not initialize Vulkan, exiting!");
|
2018-06-01 18:41:26 +02:00
|
|
|
androidApp->destroyRequested = 1;
|
2018-05-01 11:23:36 +02:00
|
|
|
}
|
2016-03-20 17:35:54 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LOGE("No window assigned!");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case APP_CMD_LOST_FOCUS:
|
2016-03-26 12:58:35 +01:00
|
|
|
LOGD("APP_CMD_LOST_FOCUS");
|
|
|
|
|
vulkanExample->focused = false;
|
|
|
|
|
break;
|
|
|
|
|
case APP_CMD_GAINED_FOCUS:
|
|
|
|
|
LOGD("APP_CMD_GAINED_FOCUS");
|
|
|
|
|
vulkanExample->focused = true;
|
2016-03-20 17:35:54 +01:00
|
|
|
break;
|
2016-08-31 20:41:32 +02:00
|
|
|
case APP_CMD_TERM_WINDOW:
|
|
|
|
|
// Window is hidden or closed, clean up resources
|
|
|
|
|
LOGD("APP_CMD_TERM_WINDOW");
|
2018-05-01 11:23:36 +02:00
|
|
|
if (vulkanExample->prepared) {
|
|
|
|
|
vulkanExample->swapChain.cleanup();
|
|
|
|
|
}
|
2016-08-31 20:41:32 +02:00
|
|
|
break;
|
2016-03-20 17:35:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
2017-04-14 12:00:05 -04:00
|
|
|
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
|
|
|
|
|
void* VulkanExampleBase::setupWindow(void* view)
|
|
|
|
|
{
|
2017-07-29 19:31:00 +02:00
|
|
|
this->view = view;
|
|
|
|
|
return view;
|
2017-04-14 12:00:05 -04:00
|
|
|
}
|
2016-11-04 13:32:58 -07:00
|
|
|
#elif defined(_DIRECT2DISPLAY)
|
2017-02-02 08:54:56 +00:00
|
|
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
|
|
|
/*static*/void VulkanExampleBase::registryGlobalCb(void *data,
|
|
|
|
|
wl_registry *registry, uint32_t name, const char *interface,
|
|
|
|
|
uint32_t version)
|
|
|
|
|
{
|
|
|
|
|
VulkanExampleBase *self = reinterpret_cast<VulkanExampleBase *>(data);
|
|
|
|
|
self->registryGlobal(registry, name, interface, version);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/void VulkanExampleBase::seatCapabilitiesCb(void *data, wl_seat *seat,
|
|
|
|
|
uint32_t caps)
|
|
|
|
|
{
|
|
|
|
|
VulkanExampleBase *self = reinterpret_cast<VulkanExampleBase *>(data);
|
|
|
|
|
self->seatCapabilities(seat, caps);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/void VulkanExampleBase::pointerEnterCb(void *data,
|
|
|
|
|
wl_pointer *pointer, uint32_t serial, wl_surface *surface,
|
|
|
|
|
wl_fixed_t sx, wl_fixed_t sy)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/void VulkanExampleBase::pointerLeaveCb(void *data,
|
|
|
|
|
wl_pointer *pointer, uint32_t serial, wl_surface *surface)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/void VulkanExampleBase::pointerMotionCb(void *data,
|
|
|
|
|
wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
|
|
|
|
|
{
|
|
|
|
|
VulkanExampleBase *self = reinterpret_cast<VulkanExampleBase *>(data);
|
|
|
|
|
self->pointerMotion(pointer, time, sx, sy);
|
|
|
|
|
}
|
2017-11-02 13:40:27 +01:00
|
|
|
void VulkanExampleBase::pointerMotion(wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
|
2017-02-02 08:54:56 +00:00
|
|
|
{
|
2017-11-02 13:40:27 +01:00
|
|
|
handleMouseMove(wl_fixed_to_int(sx), wl_fixed_to_int(sy));
|
2017-02-02 08:54:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/void VulkanExampleBase::pointerButtonCb(void *data,
|
|
|
|
|
wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button,
|
|
|
|
|
uint32_t state)
|
|
|
|
|
{
|
|
|
|
|
VulkanExampleBase *self = reinterpret_cast<VulkanExampleBase *>(data);
|
|
|
|
|
self->pointerButton(pointer, serial, time, button, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::pointerButton(struct wl_pointer *pointer,
|
|
|
|
|
uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
|
|
|
|
|
{
|
|
|
|
|
switch (button)
|
|
|
|
|
{
|
|
|
|
|
case BTN_LEFT:
|
|
|
|
|
mouseButtons.left = !!state;
|
|
|
|
|
break;
|
|
|
|
|
case BTN_MIDDLE:
|
|
|
|
|
mouseButtons.middle = !!state;
|
|
|
|
|
break;
|
|
|
|
|
case BTN_RIGHT:
|
|
|
|
|
mouseButtons.right = !!state;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/void VulkanExampleBase::pointerAxisCb(void *data,
|
|
|
|
|
wl_pointer *pointer, uint32_t time, uint32_t axis,
|
|
|
|
|
wl_fixed_t value)
|
|
|
|
|
{
|
|
|
|
|
VulkanExampleBase *self = reinterpret_cast<VulkanExampleBase *>(data);
|
|
|
|
|
self->pointerAxis(pointer, time, axis, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::pointerAxis(wl_pointer *pointer, uint32_t time,
|
|
|
|
|
uint32_t axis, wl_fixed_t value)
|
|
|
|
|
{
|
|
|
|
|
double d = wl_fixed_to_double(value);
|
|
|
|
|
switch (axis)
|
|
|
|
|
{
|
|
|
|
|
case REL_X:
|
|
|
|
|
zoom += d * 0.005f * zoomSpeed;
|
|
|
|
|
camera.translate(glm::vec3(0.0f, 0.0f, d * 0.005f * zoomSpeed));
|
|
|
|
|
viewUpdated = true;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/void VulkanExampleBase::keyboardKeymapCb(void *data,
|
|
|
|
|
struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/void VulkanExampleBase::keyboardEnterCb(void *data,
|
|
|
|
|
struct wl_keyboard *keyboard, uint32_t serial,
|
|
|
|
|
struct wl_surface *surface, struct wl_array *keys)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/void VulkanExampleBase::keyboardLeaveCb(void *data,
|
|
|
|
|
struct wl_keyboard *keyboard, uint32_t serial,
|
|
|
|
|
struct wl_surface *surface)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/void VulkanExampleBase::keyboardKeyCb(void *data,
|
|
|
|
|
struct wl_keyboard *keyboard, uint32_t serial, uint32_t time,
|
|
|
|
|
uint32_t key, uint32_t state)
|
|
|
|
|
{
|
|
|
|
|
VulkanExampleBase *self = reinterpret_cast<VulkanExampleBase *>(data);
|
|
|
|
|
self->keyboardKey(keyboard, serial, time, key, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::keyboardKey(struct wl_keyboard *keyboard,
|
|
|
|
|
uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
|
|
|
|
|
{
|
|
|
|
|
switch (key)
|
|
|
|
|
{
|
|
|
|
|
case KEY_W:
|
|
|
|
|
camera.keys.up = !!state;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_S:
|
|
|
|
|
camera.keys.down = !!state;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_A:
|
|
|
|
|
camera.keys.left = !!state;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_D:
|
|
|
|
|
camera.keys.right = !!state;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_P:
|
|
|
|
|
if (state)
|
|
|
|
|
paused = !paused;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_F1:
|
2017-10-30 18:03:48 +01:00
|
|
|
if (state && settings.overlay)
|
2017-11-01 13:40:44 +01:00
|
|
|
settings.overlay = !settings.overlay;
|
2017-02-02 08:54:56 +00:00
|
|
|
break;
|
|
|
|
|
case KEY_ESC:
|
|
|
|
|
quit = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state)
|
|
|
|
|
keyPressed(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/void VulkanExampleBase::keyboardModifiersCb(void *data,
|
|
|
|
|
struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed,
|
|
|
|
|
uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::seatCapabilities(wl_seat *seat, uint32_t caps)
|
|
|
|
|
{
|
|
|
|
|
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !pointer)
|
|
|
|
|
{
|
|
|
|
|
pointer = wl_seat_get_pointer(seat);
|
|
|
|
|
static const struct wl_pointer_listener pointer_listener =
|
|
|
|
|
{ pointerEnterCb, pointerLeaveCb, pointerMotionCb, pointerButtonCb,
|
|
|
|
|
pointerAxisCb, };
|
|
|
|
|
wl_pointer_add_listener(pointer, &pointer_listener, this);
|
|
|
|
|
}
|
|
|
|
|
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && pointer)
|
|
|
|
|
{
|
|
|
|
|
wl_pointer_destroy(pointer);
|
|
|
|
|
pointer = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !keyboard)
|
|
|
|
|
{
|
|
|
|
|
keyboard = wl_seat_get_keyboard(seat);
|
|
|
|
|
static const struct wl_keyboard_listener keyboard_listener =
|
|
|
|
|
{ keyboardKeymapCb, keyboardEnterCb, keyboardLeaveCb, keyboardKeyCb,
|
|
|
|
|
keyboardModifiersCb, };
|
|
|
|
|
wl_keyboard_add_listener(keyboard, &keyboard_listener, this);
|
|
|
|
|
}
|
|
|
|
|
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && keyboard)
|
|
|
|
|
{
|
|
|
|
|
wl_keyboard_destroy(keyboard);
|
|
|
|
|
keyboard = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::registryGlobal(wl_registry *registry, uint32_t name,
|
|
|
|
|
const char *interface, uint32_t version)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp(interface, "wl_compositor") == 0)
|
|
|
|
|
{
|
|
|
|
|
compositor = (wl_compositor *) wl_registry_bind(registry, name,
|
|
|
|
|
&wl_compositor_interface, 3);
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(interface, "wl_shell") == 0)
|
|
|
|
|
{
|
|
|
|
|
shell = (wl_shell *) wl_registry_bind(registry, name,
|
|
|
|
|
&wl_shell_interface, 1);
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(interface, "wl_seat") == 0)
|
|
|
|
|
{
|
|
|
|
|
seat = (wl_seat *) wl_registry_bind(registry, name, &wl_seat_interface,
|
|
|
|
|
1);
|
|
|
|
|
|
|
|
|
|
static const struct wl_seat_listener seat_listener =
|
|
|
|
|
{ seatCapabilitiesCb, };
|
|
|
|
|
wl_seat_add_listener(seat, &seat_listener, this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/void VulkanExampleBase::registryGlobalRemoveCb(void *data,
|
|
|
|
|
struct wl_registry *registry, uint32_t name)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::initWaylandConnection()
|
|
|
|
|
{
|
|
|
|
|
display = wl_display_connect(NULL);
|
|
|
|
|
if (!display)
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Could not connect to Wayland display!\n";
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
registry = wl_display_get_registry(display);
|
|
|
|
|
if (!registry)
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Could not get Wayland registry!\n";
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wl_registry_listener registry_listener =
|
|
|
|
|
{ registryGlobalCb, registryGlobalRemoveCb };
|
|
|
|
|
wl_registry_add_listener(registry, ®istry_listener, this);
|
|
|
|
|
wl_display_dispatch(display);
|
2017-02-14 18:52:02 +00:00
|
|
|
wl_display_roundtrip(display);
|
2017-02-02 08:54:56 +00:00
|
|
|
if (!compositor || !shell || !seat)
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Could not bind Wayland protocols!\n";
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void PingCb(void *data, struct wl_shell_surface *shell_surface,
|
|
|
|
|
uint32_t serial)
|
|
|
|
|
{
|
|
|
|
|
wl_shell_surface_pong(shell_surface, serial);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ConfigureCb(void *data, struct wl_shell_surface *shell_surface,
|
|
|
|
|
uint32_t edges, int32_t width, int32_t height)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void PopupDoneCb(void *data, struct wl_shell_surface *shell_surface)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wl_shell_surface *VulkanExampleBase::setupWindow()
|
|
|
|
|
{
|
|
|
|
|
surface = wl_compositor_create_surface(compositor);
|
|
|
|
|
shell_surface = wl_shell_get_shell_surface(shell, surface);
|
|
|
|
|
|
|
|
|
|
static const struct wl_shell_surface_listener shell_surface_listener =
|
|
|
|
|
{ PingCb, ConfigureCb, PopupDoneCb };
|
|
|
|
|
|
|
|
|
|
wl_shell_surface_add_listener(shell_surface, &shell_surface_listener, this);
|
|
|
|
|
wl_shell_surface_set_toplevel(shell_surface);
|
|
|
|
|
std::string windowTitle = getWindowTitle();
|
|
|
|
|
wl_shell_surface_set_title(shell_surface, windowTitle.c_str());
|
|
|
|
|
return shell_surface;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-13 10:24:25 +02:00
|
|
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
2017-01-23 10:49:27 +01:00
|
|
|
|
|
|
|
|
static inline xcb_intern_atom_reply_t* intern_atom_helper(xcb_connection_t *conn, bool only_if_exists, const char *str)
|
|
|
|
|
{
|
|
|
|
|
xcb_intern_atom_cookie_t cookie = xcb_intern_atom(conn, only_if_exists, strlen(str), str);
|
|
|
|
|
return xcb_intern_atom_reply(conn, cookie, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-03 16:41:57 +01:00
|
|
|
// Set up a window using XCB and request event types
|
2016-02-16 15:07:25 +01:00
|
|
|
xcb_window_t VulkanExampleBase::setupWindow()
|
|
|
|
|
{
|
|
|
|
|
uint32_t value_mask, value_list[32];
|
|
|
|
|
|
|
|
|
|
window = xcb_generate_id(connection);
|
|
|
|
|
|
|
|
|
|
value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
|
|
|
|
|
value_list[0] = screen->black_pixel;
|
2016-03-13 17:15:44 +01:00
|
|
|
value_list[1] =
|
2016-03-03 16:41:57 +01:00
|
|
|
XCB_EVENT_MASK_KEY_RELEASE |
|
2016-08-03 20:44:31 +02:00
|
|
|
XCB_EVENT_MASK_KEY_PRESS |
|
2016-02-16 15:07:25 +01:00
|
|
|
XCB_EVENT_MASK_EXPOSURE |
|
|
|
|
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
|
|
|
|
XCB_EVENT_MASK_POINTER_MOTION |
|
|
|
|
|
XCB_EVENT_MASK_BUTTON_PRESS |
|
|
|
|
|
XCB_EVENT_MASK_BUTTON_RELEASE;
|
|
|
|
|
|
2017-01-23 10:49:27 +01:00
|
|
|
if (settings.fullscreen)
|
|
|
|
|
{
|
|
|
|
|
width = destWidth = screen->width_in_pixels;
|
|
|
|
|
height = destHeight = screen->height_in_pixels;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-16 15:07:25 +01:00
|
|
|
xcb_create_window(connection,
|
|
|
|
|
XCB_COPY_FROM_PARENT,
|
|
|
|
|
window, screen->root,
|
|
|
|
|
0, 0, width, height, 0,
|
|
|
|
|
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
|
|
|
|
screen->root_visual,
|
|
|
|
|
value_mask, value_list);
|
|
|
|
|
|
|
|
|
|
/* Magic code that will send notification when window is destroyed */
|
2017-01-23 10:49:27 +01:00
|
|
|
xcb_intern_atom_reply_t* reply = intern_atom_helper(connection, true, "WM_PROTOCOLS");
|
|
|
|
|
atom_wm_delete_window = intern_atom_helper(connection, false, "WM_DELETE_WINDOW");
|
2016-02-16 15:07:25 +01:00
|
|
|
|
|
|
|
|
xcb_change_property(connection, XCB_PROP_MODE_REPLACE,
|
|
|
|
|
window, (*reply).atom, 4, 32, 1,
|
|
|
|
|
&(*atom_wm_delete_window).atom);
|
|
|
|
|
|
2016-03-13 17:15:44 +01:00
|
|
|
std::string windowTitle = getWindowTitle();
|
2016-02-16 15:07:25 +01:00
|
|
|
xcb_change_property(connection, XCB_PROP_MODE_REPLACE,
|
|
|
|
|
window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
|
2016-03-13 17:15:44 +01:00
|
|
|
title.size(), windowTitle.c_str());
|
2016-02-16 15:07:25 +01:00
|
|
|
|
|
|
|
|
free(reply);
|
|
|
|
|
|
2017-01-23 10:49:27 +01:00
|
|
|
if (settings.fullscreen)
|
|
|
|
|
{
|
|
|
|
|
xcb_intern_atom_reply_t *atom_wm_state = intern_atom_helper(connection, false, "_NET_WM_STATE");
|
|
|
|
|
xcb_intern_atom_reply_t *atom_wm_fullscreen = intern_atom_helper(connection, false, "_NET_WM_STATE_FULLSCREEN");
|
|
|
|
|
xcb_change_property(connection,
|
|
|
|
|
XCB_PROP_MODE_REPLACE,
|
|
|
|
|
window, atom_wm_state->atom,
|
|
|
|
|
XCB_ATOM_ATOM, 32, 1,
|
|
|
|
|
&(atom_wm_fullscreen->atom));
|
|
|
|
|
free(atom_wm_fullscreen);
|
|
|
|
|
free(atom_wm_state);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-16 15:07:25 +01:00
|
|
|
xcb_map_window(connection, window);
|
|
|
|
|
|
|
|
|
|
return(window);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize XCB connection
|
|
|
|
|
void VulkanExampleBase::initxcbConnection()
|
|
|
|
|
{
|
|
|
|
|
const xcb_setup_t *setup;
|
|
|
|
|
xcb_screen_iterator_t iter;
|
|
|
|
|
int scr;
|
|
|
|
|
|
|
|
|
|
connection = xcb_connect(NULL, &scr);
|
|
|
|
|
if (connection == NULL) {
|
|
|
|
|
printf("Could not find a compatible Vulkan ICD!\n");
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setup = xcb_get_setup(connection);
|
|
|
|
|
iter = xcb_setup_roots_iterator(setup);
|
|
|
|
|
while (scr-- > 0)
|
|
|
|
|
xcb_screen_next(&iter);
|
|
|
|
|
screen = iter.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::handleEvent(const xcb_generic_event_t *event)
|
|
|
|
|
{
|
|
|
|
|
switch (event->response_type & 0x7f)
|
|
|
|
|
{
|
|
|
|
|
case XCB_CLIENT_MESSAGE:
|
|
|
|
|
if ((*(xcb_client_message_event_t*)event).data.data32[0] ==
|
|
|
|
|
(*atom_wm_delete_window).atom) {
|
|
|
|
|
quit = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case XCB_MOTION_NOTIFY:
|
|
|
|
|
{
|
|
|
|
|
xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)event;
|
2017-11-02 13:40:27 +01:00
|
|
|
handleMouseMove((int32_t)motion->event_x, (int32_t)motion->event_y);
|
|
|
|
|
break;
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case XCB_BUTTON_PRESS:
|
|
|
|
|
{
|
|
|
|
|
xcb_button_press_event_t *press = (xcb_button_press_event_t *)event;
|
2016-03-30 22:48:58 +02:00
|
|
|
if (press->detail == XCB_BUTTON_INDEX_1)
|
|
|
|
|
mouseButtons.left = true;
|
2016-03-30 23:00:53 +02:00
|
|
|
if (press->detail == XCB_BUTTON_INDEX_2)
|
2016-03-30 22:48:58 +02:00
|
|
|
mouseButtons.middle = true;
|
|
|
|
|
if (press->detail == XCB_BUTTON_INDEX_3)
|
|
|
|
|
mouseButtons.right = true;
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case XCB_BUTTON_RELEASE:
|
|
|
|
|
{
|
|
|
|
|
xcb_button_press_event_t *press = (xcb_button_press_event_t *)event;
|
2016-03-30 22:48:58 +02:00
|
|
|
if (press->detail == XCB_BUTTON_INDEX_1)
|
2016-02-16 15:07:25 +01:00
|
|
|
mouseButtons.left = false;
|
2016-03-30 23:00:53 +02:00
|
|
|
if (press->detail == XCB_BUTTON_INDEX_2)
|
2016-03-30 22:48:58 +02:00
|
|
|
mouseButtons.middle = false;
|
|
|
|
|
if (press->detail == XCB_BUTTON_INDEX_3)
|
2016-02-16 15:07:25 +01:00
|
|
|
mouseButtons.right = false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-08-03 21:44:04 +02:00
|
|
|
case XCB_KEY_PRESS:
|
|
|
|
|
{
|
|
|
|
|
const xcb_key_release_event_t *keyEvent = (const xcb_key_release_event_t *)event;
|
|
|
|
|
switch (keyEvent->detail)
|
|
|
|
|
{
|
|
|
|
|
case KEY_W:
|
|
|
|
|
camera.keys.up = true;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_S:
|
|
|
|
|
camera.keys.down = true;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_A:
|
|
|
|
|
camera.keys.left = true;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_D:
|
|
|
|
|
camera.keys.right = true;
|
|
|
|
|
break;
|
2016-08-04 20:58:02 +02:00
|
|
|
case KEY_P:
|
|
|
|
|
paused = !paused;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_F1:
|
2017-11-01 13:40:44 +01:00
|
|
|
if (settings.overlay) {
|
|
|
|
|
settings.overlay = !settings.overlay;
|
2016-08-04 20:58:02 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2016-08-03 21:44:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-02-16 15:07:25 +01:00
|
|
|
case XCB_KEY_RELEASE:
|
|
|
|
|
{
|
2016-03-03 16:41:57 +01:00
|
|
|
const xcb_key_release_event_t *keyEvent = (const xcb_key_release_event_t *)event;
|
2016-08-03 20:44:31 +02:00
|
|
|
switch (keyEvent->detail)
|
|
|
|
|
{
|
2016-08-03 21:44:04 +02:00
|
|
|
case KEY_W:
|
|
|
|
|
camera.keys.up = false;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_S:
|
|
|
|
|
camera.keys.down = false;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_A:
|
|
|
|
|
camera.keys.left = false;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_D:
|
|
|
|
|
camera.keys.right = false;
|
|
|
|
|
break;
|
|
|
|
|
case KEY_ESCAPE:
|
2016-08-03 20:44:31 +02:00
|
|
|
quit = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-03-03 16:41:57 +01:00
|
|
|
keyPressed(keyEvent->detail);
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case XCB_DESTROY_NOTIFY:
|
|
|
|
|
quit = true;
|
|
|
|
|
break;
|
2016-04-11 19:44:03 +02:00
|
|
|
case XCB_CONFIGURE_NOTIFY:
|
|
|
|
|
{
|
|
|
|
|
const xcb_configure_notify_event_t *cfgEvent = (const xcb_configure_notify_event_t *)event;
|
|
|
|
|
if ((prepared) && ((cfgEvent->width != width) || (cfgEvent->height != height)))
|
|
|
|
|
{
|
|
|
|
|
destWidth = cfgEvent->width;
|
|
|
|
|
destHeight = cfgEvent->height;
|
|
|
|
|
if ((destWidth > 0) && (destHeight > 0))
|
|
|
|
|
{
|
|
|
|
|
windowResize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-02-16 15:07:25 +01:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-04-22 16:02:39 +02:00
|
|
|
void VulkanExampleBase::viewChanged() {}
|
2016-03-03 16:41:57 +01:00
|
|
|
|
2017-04-22 16:02:39 +02:00
|
|
|
void VulkanExampleBase::keyPressed(uint32_t) {}
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2017-10-05 21:22:10 +02:00
|
|
|
void VulkanExampleBase::mouseMoved(double x, double y, bool & handled) {}
|
|
|
|
|
|
2017-04-22 16:02:39 +02:00
|
|
|
void VulkanExampleBase::buildCommandBuffers() {}
|
2016-04-10 11:12:04 +02:00
|
|
|
|
2018-06-03 09:38:14 +02:00
|
|
|
void VulkanExampleBase::createSynchronizationPrimitives()
|
|
|
|
|
{
|
|
|
|
|
// Wait fences to sync command buffer access
|
|
|
|
|
VkFenceCreateInfo fenceCreateInfo = vks::initializers::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT);
|
|
|
|
|
waitFences.resize(drawCmdBuffers.size());
|
|
|
|
|
for (auto& fence : waitFences) {
|
|
|
|
|
VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-16 15:07:25 +01:00
|
|
|
void VulkanExampleBase::createCommandPool()
|
|
|
|
|
{
|
|
|
|
|
VkCommandPoolCreateInfo cmdPoolInfo = {};
|
|
|
|
|
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
|
|
|
cmdPoolInfo.queueFamilyIndex = swapChain.queueNodeIndex;
|
|
|
|
|
cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
2016-05-22 20:27:06 +02:00
|
|
|
VK_CHECK_RESULT(vkCreateCommandPool(device, &cmdPoolInfo, nullptr, &cmdPool));
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::setupDepthStencil()
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
2016-05-22 20:27:06 +02:00
|
|
|
VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &depthStencil.image));
|
2016-02-16 15:07:25 +01:00
|
|
|
vkGetImageMemoryRequirements(device, depthStencil.image, &memReqs);
|
|
|
|
|
mem_alloc.allocationSize = memReqs.size;
|
2016-07-23 20:42:03 +02:00
|
|
|
mem_alloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
2016-05-22 20:27:06 +02:00
|
|
|
VK_CHECK_RESULT(vkAllocateMemory(device, &mem_alloc, nullptr, &depthStencil.mem));
|
|
|
|
|
VK_CHECK_RESULT(vkBindImageMemory(device, depthStencil.image, depthStencil.mem, 0));
|
2016-02-16 15:07:25 +01:00
|
|
|
|
|
|
|
|
depthStencilView.image = depthStencil.image;
|
2016-05-22 20:27:06 +02:00
|
|
|
VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthStencil.view));
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::setupFrameBuffer()
|
|
|
|
|
{
|
|
|
|
|
VkImageView attachments[2];
|
|
|
|
|
|
|
|
|
|
// Depth/Stencil attachment is the same for all frame buffers
|
|
|
|
|
attachments[1] = depthStencil.view;
|
|
|
|
|
|
|
|
|
|
VkFramebufferCreateInfo frameBufferCreateInfo = {};
|
|
|
|
|
frameBufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
|
|
|
|
frameBufferCreateInfo.pNext = NULL;
|
|
|
|
|
frameBufferCreateInfo.renderPass = renderPass;
|
|
|
|
|
frameBufferCreateInfo.attachmentCount = 2;
|
|
|
|
|
frameBufferCreateInfo.pAttachments = attachments;
|
|
|
|
|
frameBufferCreateInfo.width = width;
|
|
|
|
|
frameBufferCreateInfo.height = height;
|
|
|
|
|
frameBufferCreateInfo.layers = 1;
|
|
|
|
|
|
|
|
|
|
// Create frame buffers for every swap chain image
|
|
|
|
|
frameBuffers.resize(swapChain.imageCount);
|
|
|
|
|
for (uint32_t i = 0; i < frameBuffers.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
attachments[0] = swapChain.buffers[i].view;
|
2016-05-22 20:27:06 +02:00
|
|
|
VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCreateInfo, nullptr, &frameBuffers[i]));
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::setupRenderPass()
|
|
|
|
|
{
|
2016-08-10 20:39:01 +02:00
|
|
|
std::array<VkAttachmentDescription, 2> attachments = {};
|
2016-04-30 10:45:39 +02:00
|
|
|
// Color attachment
|
2017-01-25 18:54:09 +01:00
|
|
|
attachments[0].format = swapChain.colorFormat;
|
2016-02-16 15:07:25 +01:00
|
|
|
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;
|
2016-08-10 20:39:01 +02:00
|
|
|
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
|
attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
2016-04-30 10:45:39 +02:00
|
|
|
// Depth attachment
|
2016-02-16 15:07:25 +01:00
|
|
|
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;
|
2017-08-16 21:00:17 +02:00
|
|
|
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
2016-02-16 15:07:25 +01:00
|
|
|
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
2016-08-10 20:39:01 +02:00
|
|
|
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
2016-02-16 15:07:25 +01:00
|
|
|
attachments[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;
|
|
|
|
|
depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
|
|
|
|
|
2016-08-10 20:39:01 +02:00
|
|
|
VkSubpassDescription subpassDescription = {};
|
|
|
|
|
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
|
|
|
|
subpassDescription.colorAttachmentCount = 1;
|
|
|
|
|
subpassDescription.pColorAttachments = &colorReference;
|
|
|
|
|
subpassDescription.pDepthStencilAttachment = &depthReference;
|
|
|
|
|
subpassDescription.inputAttachmentCount = 0;
|
|
|
|
|
subpassDescription.pInputAttachments = nullptr;
|
|
|
|
|
subpassDescription.preserveAttachmentCount = 0;
|
|
|
|
|
subpassDescription.pPreserveAttachments = nullptr;
|
|
|
|
|
subpassDescription.pResolveAttachments = nullptr;
|
|
|
|
|
|
|
|
|
|
// Subpass dependencies for layout transitions
|
|
|
|
|
std::array<VkSubpassDependency, 2> dependencies;
|
|
|
|
|
|
|
|
|
|
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
|
|
|
|
|
dependencies[0].dstSubpass = 0;
|
|
|
|
|
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
|
|
|
|
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
|
|
|
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
|
|
|
|
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
|
|
|
|
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
|
|
|
|
|
|
|
|
|
dependencies[1].srcSubpass = 0;
|
|
|
|
|
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
|
|
|
|
|
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
|
|
|
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
|
|
|
|
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
|
|
|
|
dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
|
|
|
|
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
2016-02-16 15:07:25 +01:00
|
|
|
|
|
|
|
|
VkRenderPassCreateInfo renderPassInfo = {};
|
|
|
|
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
2016-08-10 20:39:01 +02:00
|
|
|
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
|
|
|
|
|
renderPassInfo.pAttachments = attachments.data();
|
2016-02-16 15:07:25 +01:00
|
|
|
renderPassInfo.subpassCount = 1;
|
2016-08-10 20:39:01 +02:00
|
|
|
renderPassInfo.pSubpasses = &subpassDescription;
|
|
|
|
|
renderPassInfo.dependencyCount = static_cast<uint32_t>(dependencies.size());
|
|
|
|
|
renderPassInfo.pDependencies = dependencies.data();
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2016-05-22 20:27:06 +02:00
|
|
|
VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass));
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-03-08 21:29:38 +01:00
|
|
|
void VulkanExampleBase::getEnabledFeatures()
|
|
|
|
|
{
|
|
|
|
|
// Can be overriden in derived class
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-10 11:12:04 +02:00
|
|
|
void VulkanExampleBase::windowResize()
|
|
|
|
|
{
|
|
|
|
|
if (!prepared)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
prepared = false;
|
|
|
|
|
|
2017-02-04 15:58:46 +01:00
|
|
|
// Ensure all operations on the device have been finished before destroying resources
|
|
|
|
|
vkDeviceWaitIdle(device);
|
|
|
|
|
|
2016-04-10 11:12:04 +02:00
|
|
|
// Recreate swap chain
|
|
|
|
|
width = destWidth;
|
|
|
|
|
height = destHeight;
|
|
|
|
|
setupSwapChain();
|
|
|
|
|
|
|
|
|
|
// Recreate the frame buffers
|
|
|
|
|
vkDestroyImageView(device, depthStencil.view, nullptr);
|
|
|
|
|
vkDestroyImage(device, depthStencil.image, nullptr);
|
|
|
|
|
vkFreeMemory(device, depthStencil.mem, nullptr);
|
2017-11-01 15:19:28 +01:00
|
|
|
setupDepthStencil();
|
|
|
|
|
for (uint32_t i = 0; i < frameBuffers.size(); i++) {
|
2016-04-10 11:12:04 +02:00
|
|
|
vkDestroyFramebuffer(device, frameBuffers[i], nullptr);
|
|
|
|
|
}
|
|
|
|
|
setupFrameBuffer();
|
|
|
|
|
|
2018-08-29 20:49:13 +02:00
|
|
|
if ((width > 0.0f) && (height > 0.0f)) {
|
|
|
|
|
if (settings.overlay) {
|
|
|
|
|
UIOverlay->resize(width, height);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-10 11:12:04 +02:00
|
|
|
// Command buffers need to be recreated as they may store
|
|
|
|
|
// references to the recreated frame buffer
|
|
|
|
|
destroyCommandBuffers();
|
|
|
|
|
createCommandBuffers();
|
|
|
|
|
buildCommandBuffers();
|
|
|
|
|
|
|
|
|
|
vkDeviceWaitIdle(device);
|
|
|
|
|
|
2018-06-30 21:56:23 +02:00
|
|
|
if ((width > 0.0f) && (height > 0.0f)) {
|
|
|
|
|
camera.updateAspectRatio((float)width / (float)height);
|
2016-05-15 18:31:31 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-10 11:12:04 +02:00
|
|
|
// Notify derived class
|
|
|
|
|
windowResized();
|
|
|
|
|
viewChanged();
|
|
|
|
|
|
|
|
|
|
prepared = true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-02 13:40:27 +01:00
|
|
|
void VulkanExampleBase::handleMouseMove(int32_t x, int32_t y)
|
|
|
|
|
{
|
|
|
|
|
int32_t dx = (int32_t)mousePos.x - x;
|
|
|
|
|
int32_t dy = (int32_t)mousePos.y - y;
|
|
|
|
|
|
|
|
|
|
bool handled = false;
|
|
|
|
|
|
|
|
|
|
if (settings.overlay) {
|
|
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
|
|
|
handled = io.WantCaptureMouse;
|
|
|
|
|
}
|
|
|
|
|
mouseMoved((float)x, (float)y, handled);
|
|
|
|
|
|
|
|
|
|
if (handled) {
|
|
|
|
|
mousePos = glm::vec2((float)x, (float)y);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mouseButtons.left) {
|
|
|
|
|
rotation.x += dy * 1.25f * rotationSpeed;
|
|
|
|
|
rotation.y -= dx * 1.25f * rotationSpeed;
|
|
|
|
|
camera.rotate(glm::vec3(dy * camera.rotationSpeed, -dx * camera.rotationSpeed, 0.0f));
|
|
|
|
|
viewUpdated = true;
|
|
|
|
|
}
|
|
|
|
|
if (mouseButtons.right) {
|
|
|
|
|
zoom += dy * .005f * zoomSpeed;
|
|
|
|
|
camera.translate(glm::vec3(-0.0f, 0.0f, dy * .005f * zoomSpeed));
|
|
|
|
|
viewUpdated = true;
|
|
|
|
|
}
|
|
|
|
|
if (mouseButtons.middle) {
|
|
|
|
|
cameraPos.x -= dx * 0.01f;
|
|
|
|
|
cameraPos.y -= dy * 0.01f;
|
|
|
|
|
camera.translate(glm::vec3(-dx * 0.01f, -dy * 0.01f, 0.0f));
|
|
|
|
|
viewUpdated = true;
|
|
|
|
|
}
|
|
|
|
|
mousePos = glm::vec2((float)x, (float)y);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-10 11:12:04 +02:00
|
|
|
void VulkanExampleBase::windowResized()
|
|
|
|
|
{
|
2016-05-03 21:22:45 +02:00
|
|
|
// Can be overriden in derived class
|
2016-04-10 11:12:04 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-16 15:07:25 +01:00
|
|
|
void VulkanExampleBase::initSwapchain()
|
|
|
|
|
{
|
2016-03-20 14:55:46 +01:00
|
|
|
#if defined(_WIN32)
|
2016-02-23 21:55:37 +01:00
|
|
|
swapChain.initSurface(windowInstance, window);
|
2017-08-13 10:24:25 +02:00
|
|
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
2016-03-20 15:45:40 +01:00
|
|
|
swapChain.initSurface(androidApp->window);
|
2017-04-14 12:00:05 -04:00
|
|
|
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
|
2017-07-29 19:31:00 +02:00
|
|
|
swapChain.initSurface(view);
|
2016-11-04 13:32:58 -07:00
|
|
|
#elif defined(_DIRECT2DISPLAY)
|
|
|
|
|
swapChain.initSurface(width, height);
|
2017-02-02 08:54:56 +00:00
|
|
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
|
|
|
swapChain.initSurface(display, surface);
|
2017-08-13 10:24:25 +02:00
|
|
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
2016-02-23 21:55:37 +01:00
|
|
|
swapChain.initSurface(connection, window);
|
2016-02-16 15:07:25 +01:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VulkanExampleBase::setupSwapChain()
|
|
|
|
|
{
|
2017-01-22 13:38:57 +01:00
|
|
|
swapChain.create(&width, &height, settings.vsync);
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
2017-10-29 11:41:43 +01:00
|
|
|
|
2017-11-03 11:17:09 +01:00
|
|
|
void VulkanExampleBase::OnSetupUIOverlay(vks::UIOverlayCreateInfo &createInfo) {}
|
2017-10-30 12:36:44 +01:00
|
|
|
void VulkanExampleBase::OnUpdateUIOverlay(vks::UIOverlay *overlay) {}
|