Browse Source

Commit changes

master
Alexander Memer 1 year ago
parent
commit
a0ffe51712

+ 4
- 1
.gitignore View File

@@ -258,4 +258,7 @@ paket-files/

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
*.pyc

build/
bin/

+ 46
- 0
CMakeLists.txt View File

@@ -0,0 +1,46 @@
cmake_minimum_required(VERSION 3.7.1)

set(DEFAULT_BUILD_TYPE "Debug")

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
endif()

set(LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib")
set(INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")

project(VulkanEngine)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

file(GLOB INCLUDES "${INCLUDE_DIR}/*.hpp")
file(GLOB SOURCES "${SOURCE_DIR}/*.cpp")

if(NOT LIB_VK_LIBRARY)
message(WARNING "Vulkan library not found please specify it with -DLIB_VK_LIBRARY='Path to your vulkan lib' or use the cmake-gui to se set it")
set(LIB_VK_LIBRARY "" CACHE FILEPATH "Path to your Vulkan library file")
set(ERROR "YES")
endif()
if(NOT LIB_VK_INCLUDE_DIR)
message(WARNING "Vulkan include directory not found please specify it with -DLIB_VK_INCLUDE_DIR='Path to your vulkan include dirrectory' or use the cmake-gui to se set it")
set(LIB_VK_INCLUDE_DIR "" CACHE PATH "Path to your Vulkan include directory")
set(ERROR "YES")
endif()

set(CMAKE_SUPPRESS_REGENERATION true)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin)

if(ERROR)
message(FATAL_ERROR "Error occured check output")
endif()

include_directories(${INCLUDE_DIR} ${LIB_VK_INCLUDE_DIR})

add_executable(VulkanEngine ${SOURCES} ${INCLUDES})

target_link_libraries(VulkanEngine ${LIB_VK_LIBRARY})

set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT VulkanEngine)
set_target_properties(VulkanEngine PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/")

+ 25
- 0
include/Clock.hpp View File

@@ -0,0 +1,25 @@
#pragma once
#include "PCH.hpp"
#include "Time.hpp"

class Clock
{
public:

U64 now()
{
auto t = std::chrono::time_point_cast<std::chrono::microseconds>(clock.now());
auto t2 = t.time_since_epoch();
return t2.count();
}

Time time()
{
Time t;
t.setMicroSeconds(now());
return t;
}

private:
std::chrono::high_resolution_clock clock;
};

+ 49
- 0
include/Engine.hpp View File

@@ -0,0 +1,49 @@
#pragma once

#include "PCH.hpp"
#include "Window.hpp"
#include "Renderer.hpp"
#include "VulkanWrapper.hpp"
#include "Time.hpp"
#include "Clock.hpp"

class Window;
class Renderer;

class Engine
{
public:
Engine() {}
~Engine() {}

static void start();
static void createVulkanInstance();
static void queryVulkanPhysicalDeviceDetails();
static void createWindow();
static void quit();

static VkPhysicalDevice getPhysicalDevice() { return vkPhysicalDevice; }
static PhysicalDeviceDetails& getPhysicalDeviceDetails() { return physicalDevicesDetails[physicalDeviceIndex]; }

#ifdef ENABLE_VULKAN_VALIDATION
static VkDebugReportCallbackEXT debugCallbackInfo;
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallbackFunc(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char* layerPrefix, const char* msg, void* userData);
#endif

#ifdef _WIN32
static HINSTANCE win32Instance;
#endif
static Clock clock;
static Window *window;
static Renderer *renderer;


static VkInstance vkInstance;
static VkPhysicalDevice vkPhysicalDevice;
static std::vector<PhysicalDeviceDetails> physicalDevicesDetails;
static int physicalDeviceIndex;
static bool isRunning;
static Time engineStartTime;
};


+ 66
- 0
include/Event.hpp View File

@@ -0,0 +1,66 @@
#pragma once
#include "PCH.hpp"
#include "Keyboard.hpp"

struct Event
{
enum Type { MouseMove, MouseDown, MouseUp, MouseWheel, KeyDown, KeyUp, WindowResized, WindowMoved };
Type type;

Event() {}
Event(Type pType) : type(pType) {}

union {
struct key_struct {
Key key;
bool shift;
bool alt;
bool sys;
bool ctrl;
bool caps;
};
key_struct keyEvent;
};

void constructKey(Key pKey, bool pShift, bool pAlt, bool pSys, bool pCtrl, bool pCaps)
{
keyEvent.key = pKey; keyEvent.shift = pShift; keyEvent.alt = pAlt; keyEvent.sys = pSys; keyEvent.ctrl = pCtrl; keyEvent.caps = pCaps;
}
};

class EventQ
{
private:
std::queue<Event> events;

public:
bool pollEvent(Event& pEvent)
{
if (events.size() > 0)
{
pEvent = events.front();
events.pop();
return true;
}
else
{
return false;
}
}

void pushEvent(Event& pEvent)
{
events.push(pEvent);
}
};

class KeyEvent : private Event
{
public:
Key getKey() { return keyEvent.key; }
bool getShift() { return keyEvent.shift; }
bool getAlt() { return keyEvent.alt; }
bool getSys() { return keyEvent.sys; }
bool getCtrl() { return keyEvent.ctrl; }
bool getCaps() { return keyEvent.caps; }
};

+ 99
- 0
include/Keyboard.hpp View File

@@ -0,0 +1,99 @@
#pragma once
#include "PCH.hpp"

typedef S32 KeyCode;

class Key
{
public:
Key(KeyCode pCode) : code(pCode) {}
Key() : code(KC_NULL) {}
enum
{
KC_NULL = 0,

KC_0 = 0x30,
KC_1,
KC_2,
KC_3,
KC_4,
KC_5,
KC_6,
KC_7,
KC_8,

KC_A = 0x41,
KC_B,
KC_C,
KC_D,
KC_E,
KC_F,
KC_G,
KC_H,
KC_I,
KC_J,
KC_K,
KC_L,
KC_M,
KC_N,
KC_O,
KC_P,
KC_Q,
KC_R,
KC_S,
KC_T,
KC_U,
KC_V,
KC_W,
KC_X,
KC_Y,
KC_Z,

KC_NUMPAD0 = 0x60,
KC_NUMPAD1,
KC_NUMPAD2,
KC_NUMPAD3,
KC_NUMPAD4,
KC_NUMPAD5,
KC_NUMPAD6,
KC_NUMPAD7,
KC_NUMPAD8,
KC_NUMPAD9,

KC_BACKSPACE = VK_BACK,
KC_TAB = VK_TAB,
KC_DELETE = VK_DELETE,
KC_ENTER = VK_RETURN,
KC_LEFT = VK_LEFT,
KC_RIGHT = VK_RIGHT,
KC_UP = VK_UP,
KC_DOWN = VK_DOWN,

KC_LEFT_SUPER = VK_LWIN,
KC_RIGHT_SUPER = VK_RWIN,
KC_RETURN = VK_RETURN,
KC_LEFT_SHIFT = VK_LSHIFT,
KC_RIGHT_SHIFT = VK_RSHIFT,
KC_LEFT_CTRL = VK_LCONTROL,
KC_RIGHT_CTRL = VK_RCONTROL,
KC_LEFT_ALT = VK_LMENU,
KC_RIGHT_ALT = VK_RMENU,
KC_CAPS = VK_CAPITAL,
KC_ESCAPE = VK_ESCAPE
};
KeyCode code;
};

class Keyboard
{
public:
Keyboard() {}
~Keyboard() {}

static bool isKeyPressed(Key key)
{
return keyState[key.code] != 0;
}

static U8 keyState[256];
};

BIN
include/PCH.hpp View File


+ 52
- 0
include/Renderer.hpp View File

@@ -0,0 +1,52 @@
#pragma once

#include "PCH.hpp"
#include "Engine.hpp"

class Renderer
{
public:
Renderer() {}
~Renderer() {}

VkDevice vkLogicalDevice;
VkQueue vkGraphicsQueue;
VkQueue vkPresentQueue;
VkSwapchainKHR vkSwapChain;
VkPipeline vkPipeline;
VkPipelineLayout vkPipelineLayout;
VkRenderPass vkRenderPass;
VkCommandPool vkCommandPool;
std::vector<VkCommandBuffer> vkCommandBuffers;
std::vector<VkFramebuffer> vkFramebuffers;
std::vector<VkImage> vkSwapChainImages;
std::vector<VkImageView> vkSwapChainImageViews;
VkFormat swapChainImageFormat;
VkExtent2D swapChainExtent;

VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats);
VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& modes);
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);

VkSemaphore imageAvailableSemaphore;
VkSemaphore renderFinishedSemaphore;

void init();
void render();
void cleanup();

void initVulkanLogicalDevice();
void initVulkanSwapChain();
void initVulkanImageViews();
void initVulkanRenderPass();
void initVulkanGraphicsPipeline();
void initVulkanFramebuffers();
void initVulkanCommandPool();
void initVulkanCommandBuffers();
void initVulkanSemaphores();
VkShaderModule createShaderModule(const std::vector<char>& code);

void cleanupSwapChain();
void recreateVulkanSwapChain();
};


+ 74
- 0
include/Time.hpp View File

@@ -0,0 +1,74 @@
#pragma once
#include "Types.hpp"

class Time
{
public:
Time() : seconds(0), milliSeconds(0), microSeconds(0) {};
Time(double pSeconds) { setSeconds(pSeconds); }
Time(Time& pTime) { setMicroSeconds(pTime.getMicroSeconds()); }
Time(Time&& pTime) { setMicroSeconds(pTime.getMicroSeconds()); }
~Time() {};

Time& setMicroSeconds(S64 ms) { microSeconds = ms; milliSeconds = double(ms) * 0.001; seconds = double(ms) * 0.000001; return *this; }
Time& setMilliSeconds(double ms) { milliSeconds = ms; microSeconds = ms * 1000; seconds = ms * 0.001; return *this; }
Time& setSeconds(double s) { seconds = s; microSeconds = s * 1000000; milliSeconds = s * 1000; return *this; }

S64 getMicroSeconds() { return microSeconds; }
double getMilliSeconds() { return milliSeconds; }
float getMilliSecondsf() { return float(milliSeconds); }
double getSeconds() { return seconds; }
float getSecondsf() { return float(seconds); }

S64 removeMicroSeconds(S64 ms) { setMicroSeconds(microSeconds - ms); return microSeconds; }
double removeMilliSeconds(double ms) { setMilliSeconds(milliSeconds - ms); return milliSeconds; }
double removeSeconds(double s) { setSeconds(seconds - s); return seconds; }

S64 addMicroSeconds(S64 ms) { setMicroSeconds(microSeconds + ms); return microSeconds; }
double addMilliSeconds(double ms) { setMilliSeconds(milliSeconds + ms); return milliSeconds; }
double addSeconds(double s) { setSeconds(seconds + s); return seconds; }

void subtract(Time& rhs)
{
microSeconds -= rhs.getMicroSeconds();
milliSeconds -= rhs.getMilliSeconds();
seconds -= rhs.getSeconds();
}

void add(Time& rhs)
{
microSeconds += rhs.getMicroSeconds();
milliSeconds += rhs.getMilliSeconds();
seconds += rhs.getSeconds();
}

Time operator-(Time& rhs)
{
Time ret;
ret.setMicroSeconds(microSeconds - rhs.getMicroSeconds());
return ret;
}

Time operator+(Time& rhs)
{
Time ret;
ret.setMicroSeconds(microSeconds + rhs.getMicroSeconds());
return ret;
}

void operator=(Time& rhs)
{
setMicroSeconds(rhs.getMicroSeconds());
}

void operator=(Time rhs)
{
setMicroSeconds(rhs.getMicroSeconds());
}

private:

S64 microSeconds;
double milliSeconds;
double seconds;
};

+ 13
- 0
include/Types.hpp View File

@@ -0,0 +1,13 @@
#pragma once

typedef unsigned char U8;
typedef signed char S8;

typedef unsigned short U16;
typedef signed short S16;

typedef unsigned int U32;
typedef signed int S32;

typedef unsigned long long U64;
typedef signed long long S64;

+ 27
- 0
include/VulkanWrapper.hpp View File

@@ -0,0 +1,27 @@
#pragma once

#include "PCH.hpp"

struct PhysicalDeviceDetails
{
PhysicalDeviceDetails(VkPhysicalDevice device) : suitabilityScore(0), vkPhysicalDevice(device), graphicsQueueFamily(-1), presentQueueFamily(-1), computeQueueFamily(-1), transferQueueFamily(-1) {}
S32 suitabilityScore;
VkPhysicalDevice vkPhysicalDevice;
VkPhysicalDeviceProperties deviceProperties;
VkPhysicalDeviceFeatures deviceFeatures;

void queryDetails();
std::vector<VkQueueFamilyProperties> queueFamilies;
S32 graphicsQueueFamily;
S32 computeQueueFamily;
S32 presentQueueFamily;
S32 transferQueueFamily;

struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
};

SwapChainSupportDetails swapChainDetails;
};

+ 54
- 0
include/Window.hpp View File

@@ -0,0 +1,54 @@
#pragma once

#include "PCH.hpp"
#include "Event.hpp"

struct WindowCreateInfo
{
WindowCreateInfo() : positionX(0), positionY(0), borderless(0) {}

#ifdef _WIN32
HINSTANCE win32Instance;
#endif

int width;
int height;

const char *title;
int positionX;
int positionY;

bool borderless;

};

class Window
{
public:
Window() {};
~Window() {};

void create(WindowCreateInfo *c);
void destroy();

VkSurfaceKHR vkSurface;

U32 resX;
U32 resY;

std::string windowName;

EventQ eventQ;

#ifdef _WIN32
HINSTANCE win32Instance;
WNDCLASSEX win32WindowClass;
HWND win32WindowHandler;

#endif

bool processMessages();
};


vulkanengine/targetver.h → include/targetver.hpp View File


BIN
shaders/frag.spv View File


+ 10
- 0
shaders/shader.frag View File

@@ -0,0 +1,10 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable

layout(location = 0) in vec3 fragColor;

layout(location = 0) out vec4 outColor;

void main() {
outColor = vec4(fragColor, 1.0);
}

+ 25
- 0
shaders/shader.vert View File

@@ -0,0 +1,25 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable

out gl_PerVertex {
vec4 gl_Position;
};

layout(location = 0) out vec3 fragColor;

vec2 positions[3] = vec2[](
vec2(0.0, -0.5),
vec2(0.5, 0.5),
vec2(-0.5, 0.5)
);

vec3 colors[3] = vec3[](
vec3(1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 0.0, 1.0)
);

void main() {
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
fragColor = colors[gl_VertexIndex];
}

BIN
shaders/vert.spv View File


+ 223
- 0
src/Engine.cpp View File

@@ -0,0 +1,223 @@
#include "PCH.hpp"
#include "Engine.hpp"
#include "Window.hpp"
#include "Renderer.hpp"

void Engine::start()
{
LOG_INFO("Starting engine");
engineStartTime = clock.time();
#ifdef _WIN32

win32Instance = GetModuleHandle(NULL);

#endif
createVulkanInstance();
createWindow();
queryVulkanPhysicalDeviceDetails();

renderer = new Renderer();
renderer->init();

Time initTime = clock.time() - engineStartTime;
LOG_INFO("Initialisation time: " << initTime.getSecondsf() << " seconds");

Time frameTime;
double fpsDisplay = 0.f;
int frames = 0;

while (isRunning)
{
frameTime = clock.time();
while (window->processMessages()) {}

Event ev;
while (window->eventQ.pollEvent(ev)) {
switch (ev.type) {
case Event::KeyDown: {
if (ev.keyEvent.key.code == Key::KC_ESCAPE)
isRunning = false;
std::cout << "Key down: " << char(ev.keyEvent.key.code) << std::endl;
break;
}
case Event::KeyUp: {
std::cout << "Key up: " << char(ev.keyEvent.key.code) << std::endl;
break;
}
}
}

renderer->render();
frameTime = clock.time() - frameTime;

++frames;
fpsDisplay += frameTime.getSeconds();
if (fpsDisplay > 1.f)
{
//printf("%f\n", double(frames) / fpsDisplay);
fpsDisplay = 0.f;
frames = 0;
}
}

quit();
}

void Engine::createWindow()
{
LOG_INFO("Creating window");
WindowCreateInfo c;

#ifdef _WIN32
c.win32Instance = win32Instance;
#endif

c.title = "Vulkan Engine";

c.width = 800;
c.height = 600;

window = new Window();
window->create(&c);
}

void Engine::createVulkanInstance()
{
LOG_INFO("Creating Vulkan instance");
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pNext = nullptr;
appInfo.pApplicationName = "Keimo";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "No engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;

std::vector<const char *> enabledExtensions;
enabledExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
enabledExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#ifdef ENABLE_VULKAN_VALIDATION
enabledExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
#endif

VkInstanceCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.pApplicationInfo = &appInfo;
#ifdef ENABLE_VULKAN_VALIDATION
info.enabledLayerCount = 1;
auto layerName = "VK_LAYER_LUNARG_standard_validation";
info.ppEnabledLayerNames = &layerName;
#else
info.enabledLayerCount = 0;
info.ppEnabledLayerNames = nullptr;
#endif

info.enabledExtensionCount = (uint32_t)enabledExtensions.size();
info.ppEnabledExtensionNames = enabledExtensions.data();

if (vkCreateInstance(&info, nullptr, &vkInstance) != VK_SUCCESS)
{
LOG_FATAL("Failed to create Vulkan instance");
}
else
{
LOG_INFO("Vulkan instance created successfully");
}

#ifdef ENABLE_VULKAN_VALIDATION
VkDebugReportCallbackCreateInfoEXT createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
createInfo.pfnCallback = debugCallbackFunc;
auto createDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(vkInstance, "vkCreateDebugReportCallbackEXT");
if (createDebugReportCallbackEXT(vkInstance, &createInfo, nullptr, &debugCallbackInfo) != VK_SUCCESS) {
LOG_WARN("Failed to create debug callback");
}
else
{
LOG_INFO("Created debug callback");
}
#endif
}

void Engine::queryVulkanPhysicalDeviceDetails()
{
LOG_INFO("Picking Vulkan device");
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, nullptr);
if (physicalDeviceCount == 0) {
throw std::runtime_error("No devices found with Vulkan support!");
}

std::vector<VkPhysicalDevice> devices(physicalDeviceCount);
vkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, devices.data());

std::multimap<int, VkPhysicalDevice> rankedDevices;

for (const auto& device : devices)
{
physicalDevicesDetails.push_back(PhysicalDeviceDetails(device));

auto& qDevice = physicalDevicesDetails.back();

qDevice.queryDetails();

S32 highestSuitabilityScore = 0;
int i = 0;
for (auto &device : physicalDevicesDetails)
{
if (device.suitabilityScore > highestSuitabilityScore)
{
highestSuitabilityScore = device.suitabilityScore;
vkPhysicalDevice = device.vkPhysicalDevice;
physicalDeviceIndex = i;
}
++i;
}
}
if (vkPhysicalDevice == VK_NULL_HANDLE)
{
LOG_FATAL("Failed to find suitable GPU");
}
}

void Engine::quit()
{
LOG_INFO("Exiting");

renderer->cleanup();
window->destroy();
#ifdef ENABLE_VULKAN_VALIDATION
PFN_vkDestroyDebugReportCallbackEXT(vkGetInstanceProcAddr(vkInstance, "vkDestroyDebugReportCallbackEXT"))(vkInstance, debugCallbackInfo, 0);
#endif
vkDestroyInstance(vkInstance, nullptr);
}

#ifdef ENABLE_VULKAN_VALIDATION
VKAPI_ATTR VkBool32 VKAPI_CALL Engine::debugCallbackFunc(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char* layerPrefix, const char* msg, void* userData)
{
LOG_WARN(msg);
return VK_FALSE;
}
VkDebugReportCallbackEXT Engine::debugCallbackInfo;
#endif

#ifdef _WIN32
HINSTANCE Engine::win32Instance;
#endif
Clock Engine::clock;
Window *Engine::window;
Renderer *Engine::renderer;
VkInstance Engine::vkInstance;
VkPhysicalDevice Engine::vkPhysicalDevice = VK_NULL_HANDLE;

std::vector<PhysicalDeviceDetails> Engine::physicalDevicesDetails;
int Engine::physicalDeviceIndex;

bool Engine::isRunning = true;
Time Engine::engineStartTime;

+ 0
- 0
src/Event.cpp View File


+ 4
- 0
src/Keyboard.cpp View File

@@ -0,0 +1,4 @@
#include "PCH.hpp"
#include "Keyboard.hpp"

U8 Keyboard::keyState[256];

BIN
vulkanengine/stdafx.cpp → src/PCH.cpp View File


+ 621
- 0
src/Renderer.cpp View File

@@ -0,0 +1,621 @@
#include "PCH.hpp"
#include "Renderer.hpp"

void Renderer::init()
{
initVulkanLogicalDevice();
initVulkanSwapChain();
initVulkanImageViews();
initVulkanRenderPass();
initVulkanGraphicsPipeline();
initVulkanFramebuffers();
initVulkanCommandPool();
initVulkanCommandBuffers();
initVulkanSemaphores();
}

void Renderer::render() {

uint32_t imageIndex;
VkResult result = vkAcquireNextImageKHR(vkLogicalDevice, vkSwapChain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);

if (result != VK_SUCCESS)
{
cleanupSwapChain();
recreateVulkanSwapChain();
return;
}

VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;

VkSemaphore waitSemaphores[] = { imageAvailableSemaphore };
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;

submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &vkCommandBuffers[imageIndex];

VkSemaphore signalSemaphores[] = { renderFinishedSemaphore };
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;

if (vkQueueSubmit(vkGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
LOG_FATAL("Failed to submit Vulkan draw command buffer");
}

VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;

presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;

VkSwapchainKHR swapChains[] = { vkSwapChain };
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;

presentInfo.pImageIndices = &imageIndex;

vkQueuePresentKHR(vkPresentQueue, &presentInfo);

vkQueueWaitIdle(vkPresentQueue);

}

void Renderer::initVulkanLogicalDevice()
{
LOG_INFO("Creating logical device");

VkDeviceQueueCreateInfo qci;
qci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
qci.pNext = 0;
qci.flags = 0;
qci.queueFamilyIndex = 0;
qci.queueCount = 1;
float priority = 1.f;
qci.pQueuePriorities = &priority;

VkPhysicalDeviceFeatures features = {};

VkDeviceCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.queueCreateInfoCount = 1;
info.pQueueCreateInfos = &qci;

#ifdef ENABLE_VULKAN_VALIDATION
info.enabledLayerCount = 1;
auto layerName = "VK_LAYER_LUNARG_standard_validation";
info.ppEnabledLayerNames = &layerName;
#else
info.enabledLayerCount = 0;
info.ppEnabledLayerNames = nullptr;
#endif

info.enabledExtensionCount = 0;
info.ppEnabledExtensionNames = 0;
info.pEnabledFeatures = &features;

if (vkCreateDevice(Engine::vkPhysicalDevice, &info, nullptr, &vkLogicalDevice) != VK_SUCCESS)
{
LOG_FATAL("Failed to create logical device");
}
else
{
LOG_INFO("Logical device created successfully");
}

vkGetDeviceQueue(vkLogicalDevice, 0, 0, &vkGraphicsQueue);
vkGetDeviceQueue(vkLogicalDevice, 0, 0, &vkPresentQueue); // Ìîæåò íå ðàáîòàòü íà AMD
}

VkSurfaceFormatKHR Renderer::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats)
{
if (formats.size() == 1 && formats[0].format == VK_FORMAT_UNDEFINED)
{
return { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
}

for (const auto& current : formats)
{
if (current.format == VK_FORMAT_B8G8R8A8_UNORM && current.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
{
return current;
}
}

return formats[0];
}

VkPresentModeKHR Renderer::chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& modes)
{
for (const auto& mode : modes)
{
if (mode == VK_PRESENT_MODE_MAILBOX_KHR)
{
return mode;
}
}

return VK_PRESENT_MODE_FIFO_KHR;
}

VkExtent2D Renderer::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
{
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
{
return capabilities.currentExtent;
}
else
{
VkExtent2D actualExtent = { static_cast<uint32_t>(Engine::window->resX), static_cast<uint32_t>(Engine::window->resY) };
actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
return actualExtent;
}
}

void Renderer::initVulkanSwapChain()
{
LOG_INFO("Creating swapchain");

PhysicalDeviceDetails& details = Engine::getPhysicalDeviceDetails();

vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Engine::vkPhysicalDevice, Engine::window->vkSurface, &details.swapChainDetails.capabilities);

U32 formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(Engine::vkPhysicalDevice, Engine::window->vkSurface, &formatCount, nullptr);

if (formatCount != 0)
{
details.swapChainDetails.formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(Engine::vkPhysicalDevice, Engine::window->vkSurface, &formatCount, details.swapChainDetails.formats.data());
}
else
{
LOG_FATAL("Device not suitable (swap chain format count is 0)");
}

U32 presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(Engine::vkPhysicalDevice, Engine::window->vkSurface, &presentModeCount, nullptr);

if (presentModeCount != 0)
{
details.swapChainDetails.presentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(Engine::vkPhysicalDevice, Engine::window->vkSurface, &presentModeCount, details.swapChainDetails.presentModes.data());
}
else
{
LOG_FATAL("Device not suitable (swap chain present modes count is 0)");
}

VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(details.swapChainDetails.formats);
VkPresentModeKHR presentMode = chooseSwapPresentMode(details.swapChainDetails.presentModes);
VkExtent2D extent = chooseSwapExtent(details.swapChainDetails.capabilities);

VkSwapchainCreateInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
info.surface = Engine::window->vkSurface;

uint32_t imageCount = details.swapChainDetails.capabilities.minImageCount + 1;
if (details.swapChainDetails.capabilities.maxImageCount > 0 && imageCount > details.swapChainDetails.capabilities.maxImageCount) {
imageCount = details.swapChainDetails.capabilities.maxImageCount;
}

info.minImageCount = imageCount;
info.imageFormat = surfaceFormat.format;
info.imageColorSpace = surfaceFormat.colorSpace;
info.imageExtent = extent;
info.imageArrayLayers = 1;
info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;

info.preTransform = details.swapChainDetails.capabilities.currentTransform;
info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
info.presentMode = presentMode;
info.clipped = VK_TRUE;
info.oldSwapchain = VK_NULL_HANDLE;

if (vkCreateSwapchainKHR(vkLogicalDevice, &info, nullptr, &vkSwapChain) != VK_SUCCESS)
{
LOG_FATAL("Failed to create swapchain")
}
else
{
LOG_INFO("Swapchain created successfully");
}

vkGetSwapchainImagesKHR(vkLogicalDevice, vkSwapChain, &imageCount, nullptr);
vkSwapChainImages.resize(imageCount);
vkGetSwapchainImagesKHR(vkLogicalDevice, vkSwapChain, &imageCount, vkSwapChainImages.data());

swapChainImageFormat = surfaceFormat.format;
swapChainExtent = extent;
}

void Renderer::initVulkanImageViews()
{
LOG_INFO("Creating image views");
vkSwapChainImageViews.resize(vkSwapChainImages.size());

for (uint32_t i = 0; i < vkSwapChainImages.size(); i++) {

VkImageViewCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
info.image = vkSwapChainImages[i];
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
info.format = swapChainImageFormat;
info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.baseMipLevel = 0;
info.subresourceRange.levelCount = 1;
info.subresourceRange.baseArrayLayer = 0;
info.subresourceRange.layerCount = 1;

if (vkCreateImageView(vkLogicalDevice, &info, VK_NULL_HANDLE, &vkSwapChainImageViews[i]) != VK_SUCCESS) {
throw std::runtime_error("Failed to create image views!");
}
}

LOG_INFO("Image views created successfully");
}

void Renderer::initVulkanRenderPass()
{
LOG_INFO("Creating render pass");
VkAttachmentDescription colorAttachment = {};
colorAttachment.format = swapChainImageFormat;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;

VkAttachmentReference colorAttachmentRef = {};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;

VkRenderPassCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
info.attachmentCount = 1;
info.pAttachments = &colorAttachment;
info.subpassCount = 1;
info.pSubpasses = &subpass;

if (vkCreateRenderPass(vkLogicalDevice, &info, nullptr, &vkRenderPass) != VK_SUCCESS)
{
LOG_FATAL("Failed to create render pass");
}
else
{
LOG_INFO("Render pass created successfully");
}
}

static std::vector<char> readFile(const std::string& filename)
{
std::ifstream file(filename, std::ios::ate | std::ios::binary);

if (!file.is_open()) {
throw std::runtime_error("Failed to open file!");
}

size_t fileSize = (size_t)file.tellg();
std::vector<char> buffer(fileSize);

file.seekg(0);
file.read(buffer.data(), fileSize);

file.close();

return buffer;
}

void Renderer::initVulkanGraphicsPipeline()
{
LOG_INFO("Creating Vulkan graphics pipeline");

auto vertShaderCode = readFile("shaders/vert.spv");
auto fragShaderCode = readFile("shaders/frag.spv");

VkShaderModule vertShaderModule;
VkShaderModule fragShaderModule;

vertShaderModule = createShaderModule(vertShaderCode);
fragShaderModule = createShaderModule(fragShaderCode);

VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertShaderStageInfo.module = vertShaderModule;
vertShaderStageInfo.pName = "main";

VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragShaderStageInfo.module = fragShaderModule;
fragShaderStageInfo.pName = "main";

VkPipelineShaderStageCreateInfo shaderStagesArray[] = { vertShaderStageInfo, fragShaderStageInfo };

VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputInfo.vertexBindingDescriptionCount = 0;
vertexInputInfo.vertexAttributeDescriptionCount = 0;

VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo = {};
inputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
inputAssemblyInfo.primitiveRestartEnable = VK_FALSE;

VkViewport viewport = {};
viewport.x = 0.f;
viewport.y = 0.f;
viewport.width = (float)swapChainExtent.width;
viewport.height = (float)swapChainExtent.height;
viewport.minDepth = 0.f;
viewport.maxDepth = 1.f;

VkRect2D scissor = {};
scissor.offset = { 0, 0 };
scissor.extent = swapChainExtent;

VkPipelineViewportStateCreateInfo viewportStateInfo = {};
viewportStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportStateInfo.viewportCount = 1;
viewportStateInfo.pViewports = &viewport;
viewportStateInfo.scissorCount = 1;
viewportStateInfo.pScissors = &scissor;

VkPipelineRasterizationStateCreateInfo rasterizer = {};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.f;
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
rasterizer.depthBiasEnable = VK_FALSE;

VkPipelineMultisampleStateCreateInfo multisampling = {};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;

VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
colorBlendAttachment.blendEnable = VK_FALSE;
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;

VkPipelineColorBlendStateCreateInfo colorBlending = {};
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.logicOpEnable = VK_FALSE;
colorBlending.logicOp = VK_LOGIC_OP_COPY;
colorBlending.attachmentCount = 1;
colorBlending.pAttachments = &colorBlendAttachment;
colorBlending.blendConstants[0] = 0.0f;
colorBlending.blendConstants[1] = 0.0f;
colorBlending.blendConstants[2] = 0.0f;
colorBlending.blendConstants[3] = 0.0f;


VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 0;
pipelineLayoutInfo.pushConstantRangeCount = 0;

if (vkCreatePipelineLayout(vkLogicalDevice, &pipelineLayoutInfo, nullptr, &vkPipelineLayout) != VK_SUCCESS)
{
LOG_FATAL("Failed to create pipeline layout");
}
else
{
LOG_INFO("Pipeline layout created successfully");
}

VkGraphicsPipelineCreateInfo pipelineInfo = {};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = shaderStagesArray;
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &inputAssemblyInfo;
pipelineInfo.pViewportState = &viewportStateInfo;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.layout = vkPipelineLayout;

pipelineInfo.renderPass = vkRenderPass;
pipelineInfo.subpass = 0;

if (vkCreateGraphicsPipelines(vkLogicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &vkPipeline) != VK_SUCCESS)
{
LOG_FATAL("Failed to create graphics pipeline");
}
else
{
LOG_INFO("Graphics pipeline created successfully");
}

vkDestroyShaderModule(vkLogicalDevice, vertShaderModule, VK_NULL_HANDLE);
vkDestroyShaderModule(vkLogicalDevice, fragShaderModule, VK_NULL_HANDLE);

}

void Renderer::initVulkanFramebuffers()
{
LOG_INFO("Creating framebuffers");
vkFramebuffers.resize(vkSwapChainImageViews.size());

for (size_t i = 0; i < vkSwapChainImageViews.size(); i++) {

VkImageView attachments[] = { vkSwapChainImageViews[i] };

VkFramebufferCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.renderPass = vkRenderPass;
info.attachmentCount = 1;
info.pAttachments = attachments;
info.width = swapChainExtent.width;
info.height = swapChainExtent.height;
info.layers = 1;

if (vkCreateFramebuffer(vkLogicalDevice, &info, nullptr, &vkFramebuffers[i]) != VK_SUCCESS)
{
LOG_FATAL("Failed to create framebuffer");
}

}

LOG_INFO("Framebuffers created successfully");
}

void Renderer::initVulkanCommandPool()
{
LOG_INFO("Creating command pool");
VkCommandPoolCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
info.queueFamilyIndex = 0;

if (vkCreateCommandPool(vkLogicalDevice, &info, nullptr, &vkCommandPool) != VK_SUCCESS)
{
LOG_FATAL("Failed to create command pool");
}
else {
LOG_INFO("Command pool created successfully");
}
}

void Renderer::initVulkanCommandBuffers()
{
LOG_INFO("Creating Vulkan command buffers");

vkCommandBuffers.resize(vkFramebuffers.size());

VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = vkCommandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = (uint32_t)vkCommandBuffers.size();

if (vkAllocateCommandBuffers(vkLogicalDevice, &allocInfo, vkCommandBuffers.data()) != VK_SUCCESS) {
LOG_FATAL("Failed to allocate Vulkan command buffers");
}

for (size_t i = 0; i < vkCommandBuffers.size(); i++) {
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;

vkBeginCommandBuffer(vkCommandBuffers[i], &beginInfo);

VkRenderPassBeginInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = vkRenderPass;
renderPassInfo.framebuffer = vkFramebuffers[i];
renderPassInfo.renderArea.offset = { 0, 0 };
renderPassInfo.renderArea.extent = swapChainExtent;

VkClearValue clearColor = { 0.0f, 0.0f, 0.0f, 1.0f };
renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &clearColor;

vkCmdBeginRenderPass(vkCommandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);

vkCmdBindPipeline(vkCommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipeline);

vkCmdDraw(vkCommandBuffers[i], 3, 1, 0, 0);

vkCmdEndRenderPass(vkCommandBuffers[i]);

if (vkEndCommandBuffer(vkCommandBuffers[i]) != VK_SUCCESS) {
LOG_FATAL("Failed to record Vulkan command buffer");
}
}

}

void Renderer::initVulkanSemaphores()
{
VkSemaphoreCreateInfo semaphoreInfo = {};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;

if (vkCreateSemaphore(vkLogicalDevice, &semaphoreInfo, nullptr, &imageAvailableSemaphore) != VK_SUCCESS
||
vkCreateSemaphore(vkLogicalDevice, &semaphoreInfo, nullptr, &renderFinishedSemaphore) != VK_SUCCESS) {
LOG_FATAL("Failed to create semaphores");
}
else {
LOG_INFO("Semaphores created successfully");
}

}

VkShaderModule Renderer::createShaderModule(const std::vector<char>& code) {

VkShaderModuleCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size();
createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());

VkShaderModule shaderModule;
if (vkCreateShaderModule(vkLogicalDevice, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
LOG_FATAL("Failed to create shader module");

}

return shaderModule;

}

void Renderer::cleanup()
{
cleanupSwapChain();
vkDestroySemaphore(vkLogicalDevice, renderFinishedSemaphore, 0);
vkDestroySemaphore(vkLogicalDevice, imageAvailableSemaphore, 0);
vkDestroyCommandPool(vkLogicalDevice, vkCommandPool, 0);
vkDestroyDevice(vkLogicalDevice, 0);
}

void Renderer::cleanupSwapChain()
{
for (auto framebuffer : vkFramebuffers)
{
vkDestroyFramebuffer(vkLogicalDevice, framebuffer, nullptr);
vkDestroyPipelineLayout(vkLogicalDevice, vkPipelineLayout, nullptr);
vkDestroyPipeline(vkLogicalDevice, vkPipeline, nullptr);
vkFreeCommandBuffers(vkLogicalDevice, vkCommandPool, U32(vkCommandBuffers.size()), vkCommandBuffers.data());
vkDestroyRenderPass(vkLogicalDevice, vkRenderPass, nullptr);

for (auto imageView : vkSwapChainImageViews) {
vkDestroyImageView(vkLogicalDevice, imageView, nullptr);

}
}

vkDestroySwapchainKHR(vkLogicalDevice, vkSwapChain, nullptr);
}

void Renderer::recreateVulkanSwapChain()
{
vkDeviceWaitIdle(vkLogicalDevice);
initVulkanSwapChain();
initVulkanImageViews();
initVulkanRenderPass();
initVulkanGraphicsPipeline();
initVulkanFramebuffers();
initVulkanCommandBuffers();
}

+ 89
- 0
src/VulkanWrapper.cpp View File

@@ -0,0 +1,89 @@
#include "PCH.hpp"
#include "VulkanWrapper.hpp"
#include "Engine.hpp"
#include "Window.hpp"

void PhysicalDeviceDetails::queryDetails()
{
{
vkGetPhysicalDeviceProperties(vkPhysicalDevice, &deviceProperties);
vkGetPhysicalDeviceFeatures(vkPhysicalDevice, &deviceFeatures);

switch (deviceProperties.deviceType)
{
case (VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU):
suitabilityScore += 1000;
break;
case (VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU):
suitabilityScore += 500;
break;
case (VK_PHYSICAL_DEVICE_TYPE_CPU):
suitabilityScore += 100;
break;
default:
suitabilityScore -= 100000;
break;
}
}

{
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, &queueFamilyCount, nullptr);
queueFamilies.resize(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, &queueFamilyCount, queueFamilies.data());
}

{
int i = 0;
for (const auto& queueFamily : queueFamilies)
{
VkBool32 surfaceSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(vkPhysicalDevice, i, Engine::window->vkSurface, &surfaceSupport);

if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT && graphicsQueueFamily == -1)
graphicsQueueFamily = i;

if (graphicsQueueFamily == i && surfaceSupport && presentQueueFamily == -1)
presentQueueFamily = i;

if (queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT && computeQueueFamily == -1)
computeQueueFamily = i;

if (queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT)
transferQueueFamily = i;

suitabilityScore += queueFamily.queueCount;

++i;
}

if (graphicsQueueFamily == -1 || presentQueueFamily == -1 || computeQueueFamily == -1 || transferQueueFamily == -1)
suitabilityScore -= 100000;
}

vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vkPhysicalDevice, Engine::window->vkSurface, &swapChainDetails.capabilities);

{
uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(vkPhysicalDevice, Engine::window->vkSurface, &formatCount, nullptr);

if (formatCount != 0) {
swapChainDetails.formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(vkPhysicalDevice, Engine::window->vkSurface, &formatCount, swapChainDetails.formats.data());
}
else
suitabilityScore -= 100000;
}

{
uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(vkPhysicalDevice, Engine::window->vkSurface, &presentModeCount, nullptr);

if (presentModeCount != 0) {
swapChainDetails.presentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(vkPhysicalDevice, Engine::window->vkSurface, &presentModeCount, swapChainDetails.presentModes.data());
}
else
suitabilityScore -= 100000;
}
}

+ 133
- 0
src/Window.cpp View File

@@ -0,0 +1,133 @@
#include "PCH.hpp"
#include "Engine.hpp"
#include "Window.hpp"
#include "Keyboard.hpp"

#ifdef _WIN32
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
#endif

void Window::create(WindowCreateInfo *c)
{
#ifdef _WIN32
memset(&win32WindowClass, 0, sizeof(WNDCLASSEX));
win32WindowClass.cbSize = sizeof(WNDCLASSEX);
win32WindowClass.lpfnWndProc = WndProc;
win32WindowClass.lpszClassName = LPCSTR(c->title);
win32WindowClass.hInstance = c->win32Instance;
win32WindowClass.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
win32WindowClass.style = CS_OWNDC;
win32WindowClass.cbClsExtra = 0;
win32WindowClass.cbWndExtra = 0;

if (!RegisterClassEx(&win32WindowClass))
{
LOG_FATAL("Failed to register Window class");
}

windowName = c->title;

DWORD windowStyle;

if (c->borderless)
{
windowStyle = WS_POPUP;
}
else
{
windowStyle = (WS_OVERLAPPED | WS_SYSMENU);
}

win32WindowHandler = CreateWindowEx(0, win32WindowClass.lpszClassName, win32WindowClass.lpszClassName, windowStyle,
c->positionX, c->positionY, c->width, c->height, 0, 0, c->win32Instance, 0);

if (!win32WindowHandler)
LOG_FATAL("Could not create win32 window");

ShowWindow(win32WindowHandler, 1);

VkWin32SurfaceCreateInfoKHR sci;
sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
sci.pNext = 0;
sci.flags = 0;
sci.hinstance = Engine::win32Instance;
sci.hwnd = win32WindowHandler;
vkCreateWin32SurfaceKHR(Engine::vkInstance, &sci, 0, &vkSurface);

#endif
}

bool Window::processMessages()
{
#ifdef _WIN32
MSG msg;
if (PeekMessage(&msg, win32WindowHandler, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
return true;
}
return false;
#endif
}

void Window::destroy()
{
vkDestroySurfaceKHR(Engine::vkInstance, vkSurface, nullptr);

#ifdef _WIN32
UnregisterClass((LPCSTR)windowName.c_str(), Engine::win32Instance);
#endif
}

#ifdef _WIN32

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_KEYDOWN:
{
Keyboard::keyState[wParam] = 1;
auto check = [](U8 pKey) -> bool { return Keyboard::isKeyPressed(pKey); };
Event newEvent(Event::KeyDown);
newEvent.constructKey(wParam,
check(Key::KC_RIGHT_SHIFT) || check(Key::KC_LEFT_SHIFT),
check(Key::KC_LEFT_ALT) || check(Key::KC_RIGHT_ALT),
check(Key::KC_RIGHT_SUPER) || check(Key::KC_LEFT_SUPER),
check(Key::KC_CAPS),
check(Key::KC_RIGHT_CTRL) || check(Key::KC_LEFT_CTRL));
Engine::window->eventQ.pushEvent(newEvent);
break;
}
case WM_KEYUP:
{
Keyboard::keyState[wParam] = 0;
auto check = [](U8 pKey) -> bool { return Keyboard::isKeyPressed(pKey); };
Event newEvent(Event::KeyUp);
newEvent.constructKey(wParam,
check(Key::KC_RIGHT_SHIFT) || check(Key::KC_LEFT_SHIFT),
check(Key::KC_LEFT_ALT) || check(Key::KC_RIGHT_ALT),
check(Key::KC_RIGHT_SUPER) || check(Key::KC_LEFT_SUPER),
check(Key::KC_CAPS),
check(Key::KC_RIGHT_CTRL) || check(Key::KC_LEFT_CTRL));
Engine::window->eventQ.pushEvent(newEvent);
break;
}
case WM_CLOSE:
{
DestroyWindow(hWnd);
PostQuitMessage(0);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
Engine::isRunning = false;
break;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);;
}

#endif

+ 8
- 0
src/main.cpp View File

@@ -0,0 +1,8 @@
#include "PCH.hpp"
#include "Engine.hpp"

int main(int argc, char **argv)
{
LOG_INFO("Engine started");
Engine::start();
}

BIN
vulkanengine/vulkanengine.cpp → src/vulkanengine.cpp View File


+ 0
- 31
vulkanengine.sln View File

@@ -1,31 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27428.2043
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vulkanengine", "vulkanengine\vulkanengine.vcxproj", "{0D8BA046-D261-4FB3-BE20-BBDA0C3BEB7C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0D8BA046-D261-4FB3-BE20-BBDA0C3BEB7C}.Debug|x64.ActiveCfg = Debug|x64
{0D8BA046-D261-4FB3-BE20-BBDA0C3BEB7C}.Debug|x64.Build.0 = Debug|x64
{0D8BA046-D261-4FB3-BE20-BBDA0C3BEB7C}.Debug|x86.ActiveCfg = Debug|Win32
{0D8BA046-D261-4FB3-BE20-BBDA0C3BEB7C}.Debug|x86.Build.0 = Debug|Win32
{0D8BA046-D261-4FB3-BE20-BBDA0C3BEB7C}.Release|x64.ActiveCfg = Release|x64
{0D8BA046-D261-4FB3-BE20-BBDA0C3BEB7C}.Release|x64.Build.0 = Release|x64
{0D8BA046-D261-4FB3-BE20-BBDA0C3BEB7C}.Release|x86.ActiveCfg = Release|Win32
{0D8BA046-D261-4FB3-BE20-BBDA0C3BEB7C}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {295A50BA-8CD0-4690-8959-E3C580852088}
EndGlobalSection
EndGlobal

BIN
vulkanengine/dllmain.cpp View File


BIN
vulkanengine/stdafx.h View File


+ 0
- 166
vulkanengine/vulkanengine.vcxproj View File

@@ -1,166 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{0D8BA046-D261-4FB3-BE20-BBDA0C3BEB7C}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>vulkanengine</RootNamespace>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;VULKANENGINE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;VULKANENGINE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;VULKANENGINE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;VULKANENGINE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="vulkanengine.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

+ 0
- 36
vulkanengine/vulkanengine.vcxproj.filters View File

@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vulkanengine.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

Loading…
Cancel
Save