├── screenshot.png ├── shared.h ├── README.md ├── shader.comp ├── shader.frag ├── commands.h ├── shader.vert ├── system.h ├── makefile ├── main.cpp ├── controller.h ├── compute.h ├── compositor.h ├── system.cpp ├── renderer.h ├── commands.cpp ├── LICENSE ├── compositor.cpp ├── controller.cpp ├── compute.cpp └── renderer.cpp /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nigeljw3/vulkanengine/HEAD/screenshot.png -------------------------------------------------------------------------------- /shared.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef SHARED_H 19 | #define SHARED_H 20 | 21 | #include 22 | 23 | namespace vfsme { 24 | 25 | const uint32_t InvalidIndex = 0xffffffff; 26 | 27 | }; 28 | 29 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VFSME - Vulkan Free Surface Modeling Engine 2 | 3 | A simple framework and demo application for free surface modeling using compute and rendering with the Vulkan API. 4 | 5 | ![Screenshot](/screenshot.png) 6 | 7 | Todo List: 8 | - [ ] Integrate existing Boussinesq equation framework for depth integration: See research at [Nigel J W](http://nigeljw.com) 9 | - [ ] Add other free surface modeling like cloth 10 | - [ ] Use lighter weight synchronization primitives between compute/transfer/render queues 11 | - [ ] Fix specular lighting in fragment shader 12 | 13 | Dependencies: 14 | 15 | [LunarG Vulkan SDK] (https://vulkan.lunarg.com) 16 | 17 | [GLFW] (http://www.glfw.org) 18 | 19 | [GLM] (http://glm.g-truc.net) 20 | 21 | Great references for the Vulkan API: 22 | 23 | [Khronos Vulkan API] (https://www.khronos.org/vulkan) 24 | 25 | [Vulkan Tutorial](https://vulkan-tutorial.com) 26 | 27 | [Sascha Willems Vulkan Examples] (https://github.com/SaschaWillems/Vulkan) 28 | -------------------------------------------------------------------------------- /shader.comp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #version 450 19 | 20 | #extension GL_ARB_separate_shader_objects : enable 21 | #extension GL_ARB_shading_language_420pack : enable 22 | 23 | layout (binding = 0) uniform UBO 24 | { 25 | float time; 26 | float dx; 27 | float k; 28 | float omega; 29 | float amplitude; 30 | } ubo; 31 | 32 | layout(std430, binding = 1) buffer Height 33 | { 34 | float height[]; 35 | }; 36 | 37 | layout(std140, binding = 2) buffer Normal 38 | { 39 | vec4 normal[]; 40 | }; 41 | 42 | layout (local_size_x = 32, local_size_y = 32) in; 43 | 44 | void main() 45 | { 46 | // Current SSBO index 47 | uint index = gl_LocalInvocationIndex; 48 | 49 | float kx = ubo.k * gl_LocalInvocationID.x * ubo.dx; 50 | 51 | height[index] = ubo.amplitude*sin(kx - ubo.omega*ubo.time); 52 | 53 | normal[index].x = -ubo.amplitude*cos(kx - ubo.omega*ubo.time); 54 | normal[index].y = 1.0; 55 | normal[index].z = 0.0; 56 | normal[index].w = 1.0; 57 | } -------------------------------------------------------------------------------- /shader.frag: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #version 450 19 | #extension GL_ARB_separate_shader_objects : enable 20 | 21 | layout(location = 0) in vec3 inColor; 22 | layout(location = 1) in vec3 inNormal; 23 | layout(location = 2) in vec3 inEyePos; 24 | layout(location = 3) in vec3 inLightVec; 25 | layout(location = 4) in vec4 inAmbientLight; 26 | layout(location = 5) in vec4 inDiffuseLight; 27 | layout(location = 6) in vec4 inSpecularLight; 28 | layout(location = 7) in float inSpecularConst; 29 | 30 | layout(location = 0) out vec4 outColor; 31 | 32 | void main() { 33 | vec4 diffuseLight = inDiffuseLight * max(dot(inNormal, inLightVec), 0.0); 34 | vec3 eyeVec = normalize(-inEyePos); 35 | vec3 reflectedLight = normalize(reflect(-inLightVec, inNormal)); 36 | float specularIntensity = pow(max(dot(reflectedLight, eyeVec), 0.0), 0.8); 37 | vec4 specularLight = inSpecularLight * specularIntensity * inSpecularConst; 38 | 39 | outColor = (inAmbientLight + diffuseLight) * vec4(inColor, 1.0) + specularLight; 40 | } -------------------------------------------------------------------------------- /commands.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef commands_h 19 | #define commands_h 20 | 21 | #include 22 | 23 | namespace vfsme 24 | { 25 | 26 | class Commands 27 | { 28 | public: 29 | explicit Commands(const VkPhysicalDeviceMemoryProperties& memProperties); 30 | ~Commands() = default; 31 | 32 | ///@note Only define copy and move constructors and assignment operators if they are actually required 33 | Commands(const Commands&) = delete; 34 | Commands(Commands&&) = delete; 35 | Commands& operator=(const Commands&) = delete; 36 | Commands& operator=(Commands &&) = delete; 37 | 38 | protected: 39 | void SetupImage(VkDevice& device, VkImage& image, const VkExtent3D& extent, const VkFormat& format, VkDeviceMemory& memory, VkMemoryPropertyFlags properties, VkBufferUsageFlags usage); 40 | void SetupBuffer(VkDevice& device, VkBuffer& buffer, VkDeviceMemory& memory, VkDeviceSize size, VkMemoryPropertyFlags properties, VkBufferUsageFlags usage); 41 | uint32_t GetMemoryTypeIndex(VkDevice& device, const VkMemoryRequirements& memReqs, const VkPhysicalDeviceMemoryProperties& props, VkMemoryPropertyFlags propFlags, uint32_t& allocSize) const; 42 | 43 | const VkPhysicalDeviceMemoryProperties& memProperties; 44 | }; 45 | 46 | }; 47 | 48 | #endif -------------------------------------------------------------------------------- /shader.vert: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #version 450 19 | #extension GL_ARB_separate_shader_objects : enable 20 | 21 | layout(location = 0) in vec3 inPosition; 22 | layout(location = 1) in vec3 inColor; 23 | layout(location = 3) in vec4 inNormal; 24 | layout(location = 2) in float inHeight; 25 | 26 | layout(binding = 0) uniform UBO { 27 | mat4 model; 28 | mat4 view; 29 | mat4 proj; 30 | vec3 lightPos; 31 | } ubo; 32 | 33 | layout(location = 0) out vec3 outColor; 34 | layout(location = 1) out vec3 outNormal; 35 | layout(location = 2) out vec3 outEyePos; 36 | layout(location = 3) out vec3 outLightVec; 37 | layout(location = 4) out vec4 outAmbientLight; 38 | layout(location = 5) out vec4 outDiffuseLight; 39 | layout(location = 6) out vec4 outSpecularLight; 40 | layout(location = 7) out float outSpecularConst; 41 | 42 | void main() { 43 | outColor = inColor; 44 | outAmbientLight = vec4(0.3, 0.3, 0.3, 1.0); 45 | outDiffuseLight = vec4(0.7, 0.7, 0.7, 1.0); 46 | outSpecularConst = 0.25; 47 | outSpecularLight = vec4(0.5, 0.5, 0.5, 1.0); 48 | outNormal = normalize(inNormal.xyz); 49 | 50 | mat4 modelView = ubo.view * ubo.model; 51 | vec4 pos = modelView * vec4(inPosition.x, inHeight, inPosition.z, 1.0); 52 | 53 | outEyePos = vec3(modelView * pos); 54 | 55 | vec4 lightPos = vec4(ubo.lightPos, 1.0) * modelView; 56 | 57 | outLightVec = normalize(ubo.lightPos.xyz - outEyePos); 58 | 59 | gl_Position = ubo.proj * pos; 60 | } -------------------------------------------------------------------------------- /system.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef system_h 19 | #define system_h 20 | 21 | #include 22 | #define GLFW_EXPOSE_NATIVE_WIN32 23 | #include 24 | #include 25 | 26 | #include "compositor.h" 27 | 28 | namespace vfsme 29 | { 30 | 31 | class System 32 | { 33 | public: 34 | ///@note Singleton pattern implementation for the system class 35 | /// as there will only ever be a single system on any platform 36 | /// This is assured to be reentrant as of c++11 since concuurent 37 | /// execution will wait for initialization 38 | static System& GetSingletonInstance() 39 | { 40 | static System instance; 41 | return instance; 42 | } 43 | 44 | ///@note Remove copy and move contructors and assignment operators 45 | /// since they should never be used with the single pattern 46 | System(const System&) = delete; 47 | System(System&&) = delete; 48 | System& operator=(const System&) = delete; 49 | System& operator=(System &&) = delete; 50 | 51 | void Init(uint32_t width, uint32_t height); 52 | void Destroy(); 53 | 54 | void CreateSurface(VkInstance& instance, VkSurfaceKHR* surface); 55 | void Loop(Compositor& composer, VkDevice& device); 56 | void DestroySurface(VkInstance& instance, VkSurfaceKHR& surface); 57 | bool CheckExtensionsSupport(uint32_t extensionCount, const VkExtensionProperties* extensions) const; 58 | 59 | private: 60 | System() = default; 61 | ~System() = default; 62 | 63 | GLFWwindow* window; 64 | unsigned int glfwExtensionCount = 0; 65 | const char** glfwExtensions; 66 | }; 67 | 68 | }; 69 | 70 | #endif -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016 Nigel Williams 2 | # 3 | # Vulkan Free Surface Modeling Engine (VFSME) is free software: 4 | # you can redistribute it and/or modify it under the terms of the 5 | # GNU Lesser General Public License as published by 6 | # the Free Software Foundation, version 3. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this program. If not, see . 15 | 16 | VULKAN_PATH = /c/Dev/VulkanSDK/1.0.30.0 17 | GLFW_PATH = /c/Dev/glfw/glfw-3.2.1.bin.WIN32 18 | GLM_PATH = /C/Dev/glm 19 | 20 | CFLAGS = -std=c++14 -Wall -g 21 | INCLUDE = -I$(VULKAN_PATH)/include -I$(GLFW_PATH)/include -I$(GLM_PATH) 22 | LDFLAGS = -L$(VULKAN_PATH)/Bin32 -L$(GLFW_PATH)/lib-mingw 23 | LDLIBS = -lvulkan-1 -lglfw3 -lgdi32 24 | DEFINES = -DVK_USE_PLATFORM_WIN32_KHR 25 | OBJS = commands.o renderer.o system.o controller.o compositor.o compute.o 26 | 27 | .PHONY: clean shaders test 28 | 29 | vulkan: main.cpp $(OBJS) shaders 30 | g++ $(CFLAGS) $(DEFINES) $(INCLUDE) $(LDFLAGS) -o vulkan main.cpp $(OBJS) $(LDLIBS) 31 | 32 | system.o: system.h system.cpp 33 | g++ $(CFLAGS) $(DEFINES) $(INCLUDE) -c system.cpp -o $@ 34 | 35 | commands.o: commands.h commands.cpp shared.h 36 | g++ $(CFLAGS) $(DEFINES) $(INCLUDE) -c commands.cpp -o $@ 37 | 38 | renderer.o: renderer.h renderer.cpp commands.h 39 | g++ $(CFLAGS) $(DEFINES) $(INCLUDE) -c renderer.cpp -o $@ 40 | 41 | compute.o: compute.h compute.cpp commands.h 42 | g++ $(CFLAGS) $(DEFINES) $(INCLUDE) -c compute.cpp -o $@ 43 | 44 | controller.o: controller.h controller.cpp shared.h 45 | g++ $(CFLAGS) $(DEFINES) $(INCLUDE) -c controller.cpp -o $@ 46 | 47 | compositor.o: compositor.h compositor.cpp renderer.h compute.h 48 | g++ $(CFLAGS) $(DEFINES) $(INCLUDE) -c compositor.cpp -o $@ 49 | 50 | test: vulkan 51 | LD_LIBRARY_PATH=$(VULKAN_PATH)/lib VK_LAYER_PATH=$(VULKAN_PATH)/etc/explicit_layer.d ./vulkan 52 | 53 | shaders: 54 | $(VULKAN_PATH)/Bin32/glslangValidator.exe -V shader.vert 55 | $(VULKAN_PATH)/Bin32/glslangValidator.exe -V shader.frag 56 | $(VULKAN_PATH)/Bin32/glslangValidator.exe -V shader.comp 57 | 58 | clean: 59 | rm *.exe *.o *.spv -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | 20 | #include "renderer.h" 21 | #include "system.h" 22 | #include "controller.h" 23 | #include "compositor.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | int main() 34 | { 35 | ///@todo Make window size configurable from command line arguments 36 | 37 | ///@note Static window size for now 38 | /// If dynamic window resizing is added, then swap chain reconstruction is necessary 39 | const uint32_t width = 1920; 40 | const uint32_t height = 1080; 41 | 42 | try 43 | { 44 | vfsme::System& window = vfsme::System::GetSingletonInstance(); 45 | 46 | window.Init(width, height); 47 | 48 | vfsme::Controller devCtrl; 49 | 50 | devCtrl.Init(); 51 | devCtrl.SetupQueue(); 52 | 53 | VkSurfaceKHR surface; 54 | 55 | window.CreateSurface(devCtrl.GetInstance(), &surface); 56 | 57 | devCtrl.SetupDevice(surface); 58 | devCtrl.Configure(surface); 59 | 60 | vfsme::Compositor composer(devCtrl.GetMemoryProperties()); 61 | 62 | bool supported = devCtrl.PresentModeSupported(surface, composer.GetPresentMode()) && 63 | devCtrl.SurfaceFormatSupported(surface, composer.GetSurfaceFormat()); 64 | 65 | if (supported) 66 | { 67 | composer.Init(devCtrl.GetDevice(), 68 | surface, width, height, 69 | devCtrl.GetQueueFamilyId(), 70 | devCtrl.GetGraphicsQueueIndex(), 71 | devCtrl.GetPresentQueueIndex(), 72 | devCtrl.GetComputeQueueIndex()); 73 | 74 | window.Loop(composer, devCtrl.GetDevice()); 75 | } 76 | 77 | composer.Destroy(devCtrl.GetDevice()); 78 | 79 | window.DestroySurface(devCtrl.GetInstance(), surface); 80 | 81 | devCtrl.Destroy(); 82 | 83 | window.Destroy(); 84 | 85 | } 86 | catch (const std::runtime_error& e) 87 | { 88 | std::cerr << e.what() << std::endl; 89 | return EXIT_FAILURE; 90 | } 91 | 92 | return 0; 93 | } -------------------------------------------------------------------------------- /controller.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef controller_h 19 | #define controller_h 20 | 21 | #include 22 | 23 | #include "shared.h" 24 | 25 | namespace vfsme 26 | { 27 | 28 | class Controller 29 | { 30 | public: 31 | Controller(); 32 | ~Controller(); 33 | 34 | ///@note Only define copy and move contructors and assignment operators if they are actually required 35 | Controller(const Controller&) = delete; 36 | Controller(Controller&&) = delete; 37 | Controller& operator=(const Controller&) = delete; 38 | Controller& operator=(Controller &&) = delete; 39 | 40 | void Init(); 41 | void SetupQueue(); 42 | void SetupDevice(const VkSurfaceKHR& surface); 43 | void Destroy(); 44 | 45 | inline VkPhysicalDevice& GetPhysicalDevice() { return physicalDevice; } 46 | inline VkDevice& GetDevice() { return device; } 47 | inline VkInstance& GetInstance() { return instance; } 48 | 49 | void Configure(const VkSurfaceKHR& surface); 50 | bool PresentModeSupported(const VkSurfaceKHR& surface, VkPresentModeKHR presentMode); 51 | bool SurfaceFormatSupported(const VkSurfaceKHR& surface, VkFormat surfaceFormat) const; 52 | 53 | const VkPhysicalDeviceMemoryProperties& GetMemoryProperties() const { return memProperties; } 54 | 55 | //inline VkSurfaceCapabilitiesKHR* GetCapabilities() { return &capabilities; } 56 | inline uint32_t GetQueueFamilyId() const { return queueFamilyId; } 57 | inline uint32_t GetGraphicsQueueIndex() const { return graphicsQueueIndex; } 58 | inline uint32_t GetPresentQueueIndex() const { return presentQueueIndex; } 59 | inline uint32_t GetComputeQueueIndex() const { return computeQueueIndex; } 60 | 61 | void CheckFormatPropertyType(VkFormat format, VkFormatFeatureFlagBits flags) const; 62 | 63 | private: 64 | void PrintCapabilities() const; 65 | 66 | VkDevice device; 67 | VkPhysicalDevice physicalDevice; 68 | VkPhysicalDeviceFeatures deviceFeatures; 69 | VkInstance instance; 70 | VkDebugReportCallbackEXT callback; 71 | VkSurfaceCapabilitiesKHR capabilities; 72 | VkPhysicalDeviceMemoryProperties memProperties; 73 | float* queuePriorities; 74 | 75 | const uint32_t queueCount = 3; 76 | uint32_t queueFamilyId = InvalidIndex; 77 | const uint32_t graphicsQueueIndex = 0; 78 | const uint32_t presentQueueIndex = 1; 79 | const uint32_t computeQueueIndex = 2; 80 | }; 81 | 82 | }; 83 | 84 | #endif -------------------------------------------------------------------------------- /compute.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef compute_h 19 | #define compute_h 20 | 21 | #include "commands.h" 22 | 23 | #include 24 | #include 25 | 26 | namespace vfsme 27 | { 28 | 29 | class Compute : Commands 30 | { 31 | public: 32 | Compute(const VkExtent3D& extent, const VkPhysicalDeviceMemoryProperties& props); 33 | ~Compute() = default; 34 | 35 | ///@note Only define copy and move constructors and assignment operators if they are actually required 36 | Compute(const Compute&) = delete; 37 | Compute(Compute&&) = delete; 38 | Compute& operator=(const Compute&) = delete; 39 | Compute& operator=(Compute &&) = delete; 40 | 41 | void Init(VkDevice& device); 42 | void Destroy(VkDevice& device); 43 | void SetupQueue(VkDevice& device, uint32_t queueFamilyId); 44 | VkCommandBuffer* SetupCommandBuffer(VkDevice& device, uint32_t queueFamilyId); 45 | 46 | inline VkBuffer& GetStorageBuffer() { return storageBuffer; } 47 | inline VkBuffer& GetNormalBuffer() { return normalBuffer; } 48 | 49 | void PrintResults(VkDevice& device); 50 | void UpdateWave(VkDevice& device); 51 | 52 | private: 53 | struct Wave 54 | { 55 | float lambda; 56 | float k; 57 | float omega; 58 | float dx; 59 | float amplitude; 60 | } wave = {}; 61 | 62 | const uint32_t numWaveComponents = 5; 63 | 64 | VkShaderModule shaderModule; 65 | VkPipeline pipeline; 66 | VkPipelineLayout pipelineLayout; 67 | 68 | VkCommandBuffer commandBuffer; 69 | VkBufferMemoryBarrier memoryBarriers[2] = { {}, {} }; 70 | 71 | //VkImage image; 72 | VkBuffer uniformBuffer; 73 | VkBuffer storageBuffer; 74 | VkBuffer normalBuffer; 75 | 76 | VkDeviceMemory uniformBufferMemory; 77 | VkDeviceMemory storageBufferMemory; 78 | VkDeviceMemory normalBufferMemory; 79 | //VkDeviceMemory imageMemory; 80 | 81 | VkCommandPool commandPool; 82 | 83 | const VkExtent3D& extent; 84 | 85 | VkDescriptorSet descriptorSet; 86 | VkDescriptorSetLayout descriptorSetLayout = {}; 87 | VkDescriptorPool descriptorPool = {}; 88 | 89 | uint32_t uniformBufferSize; 90 | uint32_t storageBufferSize; 91 | uint32_t normalBufferSize; 92 | 93 | ///@todo Use the fence 94 | VkFence fence; 95 | 96 | std::chrono::time_point startTime; 97 | }; 98 | 99 | }; 100 | 101 | #endif -------------------------------------------------------------------------------- /compositor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef compositor_h 19 | #define compositor_h 20 | 21 | #include 22 | 23 | #include "renderer.h" 24 | #include "compute.h" 25 | 26 | namespace vfsme 27 | { 28 | 29 | class Compositor 30 | { 31 | public: 32 | explicit Compositor(const VkPhysicalDeviceMemoryProperties& memProperties); 33 | ~Compositor(); 34 | 35 | ///@note Only define copy and move constructors and assignment operators if they are actually required 36 | Compositor(const Compositor&) = delete; 37 | Compositor(Compositor&&) = delete; 38 | Compositor& operator=(const Compositor&) = delete; 39 | Compositor& operator=(Compositor &&) = delete; 40 | 41 | void Init(VkDevice& device, 42 | const VkSurfaceKHR& surface, 43 | uint32_t width, 44 | uint32_t height, 45 | uint32_t queueFamilyId, 46 | uint32_t graphicsQueueIndex, 47 | uint32_t presentQueueIndex, 48 | uint32_t computeQueueIndex); 49 | 50 | void Loop(); 51 | void Destroy(VkDevice& device); 52 | 53 | inline VkFormat GetSurfaceFormat() const { return surfaceFormat; } 54 | inline VkPresentModeKHR GetPresentMode() const { return presentMode; } 55 | 56 | void Draw(VkDevice& device); 57 | 58 | private: 59 | void PrintCapabilities(); 60 | 61 | uint32_t imageCount; 62 | uint32_t drawIndex; 63 | 64 | Renderer* graphicsEngine; 65 | Compute* computer; 66 | 67 | VkSurfaceCapabilitiesKHR capabilities; 68 | VkImage* images; 69 | VkSemaphore waitSemaphore; 70 | VkSemaphore signalSemaphore; 71 | VkSwapchainKHR swapChain; 72 | VkImageView* imageViews; 73 | 74 | const VkPhysicalDeviceMemoryProperties& memProperties; 75 | 76 | VkQueue presentQueue; 77 | VkQueue graphicsQueue; 78 | VkQueue computeQueue; 79 | 80 | VkCommandBuffer* drawCommandBuffer; 81 | VkCommandBuffer* transferCommandBuffer; 82 | VkCommandBuffer* computeCommandBuffer; 83 | 84 | const VkFormat surfaceFormat = VK_FORMAT_B8G8R8A8_UNORM; 85 | const VkPresentModeKHR presentMode = VK_PRESENT_MODE_MAILBOX_KHR; 86 | 87 | VkImage textureImage; 88 | VkImageMemoryBarrier barrier; 89 | 90 | ///@note Grid dimensions are currently restricted by the max X and Y workgroup sizes of the device (32x32 on my hardware) 91 | /// Needs to be changed to dynamic sizing in a future patchset by either spreading computation to the third workgroup 92 | /// dimension or across multiple workgroups, or, at the very least, set dynamically to the physical device limits. 93 | const VkExtent3D grid { 32, 32, 1 }; 94 | }; 95 | 96 | }; 97 | 98 | #endif -------------------------------------------------------------------------------- /system.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "system.h" 19 | 20 | #include 21 | 22 | namespace vfsme 23 | { 24 | 25 | void System::Init(uint32_t width, uint32_t height) 26 | { 27 | glfwInit(); 28 | glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); 29 | glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); 30 | window = glfwCreateWindow(width, height, "Vulkan window", nullptr, nullptr); 31 | 32 | glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); 33 | } 34 | 35 | void System::Destroy() 36 | { 37 | glfwDestroyWindow(window); 38 | glfwTerminate(); 39 | } 40 | 41 | void System::Loop(Compositor& composer, VkDevice& device) 42 | { 43 | while(!glfwWindowShouldClose(window)) 44 | { 45 | glfwPollEvents(); 46 | 47 | composer.Draw(device); 48 | } 49 | } 50 | 51 | void System::CreateSurface(VkInstance& instance, VkSurfaceKHR* surface) 52 | { 53 | VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {}; 54 | surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; 55 | surfaceCreateInfo.hwnd = glfwGetWin32Window(window); 56 | surfaceCreateInfo.hinstance = GetModuleHandle(nullptr); 57 | 58 | auto CreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"); 59 | 60 | VkResult result = CreateWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, surface); 61 | //glfwCreateWindowSurface(instance, window, nullptr, &surface) 62 | 63 | if (result != VK_SUCCESS) 64 | { 65 | throw std::runtime_error("failed to create surface");; 66 | } 67 | } 68 | 69 | void System::DestroySurface(VkInstance& instance, VkSurfaceKHR& surface) 70 | { 71 | auto DestroySurfaceKHR = (PFN_vkDestroySurfaceKHR) vkGetInstanceProcAddr(instance, "vkDestroySurfaceKHR"); 72 | DestroySurfaceKHR(instance, surface, nullptr); 73 | } 74 | 75 | bool System::CheckExtensionsSupport(uint32_t extensionCount, const VkExtensionProperties* extensions) const 76 | { 77 | bool fullySupported = true; 78 | 79 | for(unsigned int i = 0; i < glfwExtensionCount; ++i) 80 | { 81 | std::cout << glfwExtensions[i] << std::endl; 82 | 83 | bool extensionSupported = false; 84 | 85 | for(unsigned int j = 0; j < extensionCount; ++j) 86 | { 87 | if (strcmp(glfwExtensions[i], extensions[j].extensionName) == 0) 88 | { 89 | extensionSupported = true; 90 | break; 91 | } 92 | } 93 | 94 | if (extensionSupported == false) 95 | { 96 | std::cout << "Extension not supported:" << glfwExtensions[i] << std::endl; 97 | fullySupported = false; 98 | } 99 | } 100 | 101 | return fullySupported; 102 | } 103 | 104 | }; -------------------------------------------------------------------------------- /renderer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef renderer_h 19 | #define renderer_h 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "commands.h" 26 | 27 | namespace vfsme 28 | { 29 | 30 | class Renderer : Commands 31 | { 32 | public: 33 | Renderer(const VkExtent2D& screenExtent, const VkExtent3D& gridDim, const VkPhysicalDeviceMemoryProperties& memProps); 34 | ~Renderer(); 35 | 36 | ///@note Only define copy and move contructors and assignment operators if they are actually required 37 | Renderer(const Renderer&) = delete; 38 | Renderer(Renderer&&) = delete; 39 | Renderer& operator=(const Renderer&) = delete; 40 | Renderer& operator=(Renderer &&) = delete; 41 | 42 | void Init(VkDevice& device, const VkFormat& surfaceFormat, const VkImageView* imageViews, uint32_t queueFamilyId); 43 | void Destroy(VkDevice& device); 44 | 45 | void ConstructFrames(const VkBuffer& heightBuffer, const VkBuffer& normalBuffer); 46 | 47 | inline VkCommandBuffer* GetFrame(uint32_t index) const { return &drawCommandBuffers[index]; } 48 | 49 | VkCommandBuffer& TransferStaticBuffers(VkDevice& device); 50 | VkCommandBuffer& TransferDynamicBuffers(VkDevice& device); 51 | 52 | private: 53 | void SetupIndexBuffer(VkDevice& device); 54 | void SetupClientSideVertexBuffer(VkDevice& device); 55 | void SetupServerSideVertexBuffer(VkDevice& device); 56 | void SetupUniformBuffer(VkDevice &device); 57 | void SetupDynamicTransfer(VkDevice &device); 58 | void SetupStaticTransfer(VkDevice &device); 59 | void SetupShaderParameters(VkDevice& device); 60 | 61 | VkExtent2D imageExtent; 62 | VkShaderModule vertexShaderModule; 63 | VkShaderModule fragmentShaderModule; 64 | VkPipelineLayout pipelineLayout; 65 | VkRenderPass renderPass; 66 | VkPipeline pipeline; 67 | VkFramebuffer* framebuffers; 68 | VkCommandPool commandPool; 69 | VkCommandBuffer* drawCommandBuffers; 70 | VkCommandBuffer staticTransferCommandBuffer; 71 | VkCommandBuffer dynamicTransferCommandBuffer; 72 | 73 | VkBuffer vertexBuffer; 74 | VkBuffer vertexTransferBuffer; 75 | VkDeviceMemory vertexBufferMemory; 76 | VkDeviceMemory vertexTransferBufferMemory; 77 | 78 | VkBuffer indexTransferBuffer; 79 | VkBuffer indexBuffer; 80 | VkDeviceMemory indexBufferMemory; 81 | VkDeviceMemory indexTransferBufferMemory; 82 | 83 | VkBuffer uniformTransferBuffer; 84 | VkDeviceMemory uniformTransferBufferMemory; 85 | VkBuffer uniformBuffer; 86 | VkDeviceMemory uniformBufferMemory; 87 | 88 | VkBuffer* heightBuffer; 89 | 90 | VkVertexInputAttributeDescription* attributeDescriptions; 91 | VkVertexInputBindingDescription* bindingDescriptions; 92 | VkDescriptorSetLayoutBinding uboLayoutBinding = {}; 93 | VkDescriptorSetLayout descriptorSetLayout; 94 | VkDescriptorPool descriptorPool; 95 | VkDescriptorSet descriptorSet; 96 | 97 | const VkExtent3D grid; 98 | 99 | const uint32_t numFBOs = 2; 100 | const uint32_t numDrawCmdBuffers = 2; 101 | const uint32_t numAttrDesc = 4; 102 | const uint32_t numBindDesc = 3; 103 | const uint32_t numComponents = 3; 104 | const uint32_t numVertexElements = 2; 105 | 106 | uint32_t mat4Size; 107 | uint32_t uboSize; 108 | 109 | float* vertexInfo; 110 | uint16_t* indices; 111 | 112 | uint32_t vertexInfoSize; 113 | uint32_t numIndices; 114 | uint32_t indicesBufferSize; 115 | uint32_t numVerts; 116 | uint32_t numPrims; 117 | }; 118 | 119 | }; 120 | 121 | #endif -------------------------------------------------------------------------------- /commands.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "commands.h" 19 | 20 | #include 21 | #include 22 | 23 | #include "shared.h" 24 | 25 | namespace vfsme 26 | { 27 | 28 | Commands::Commands(const VkPhysicalDeviceMemoryProperties& memProps) 29 | : memProperties(memProps) 30 | { 31 | } 32 | 33 | void Commands::SetupImage(VkDevice& device, VkImage& image, const VkExtent3D& extent, const VkFormat& format, VkDeviceMemory& memory, VkMemoryPropertyFlags props, VkBufferUsageFlags usage) 34 | { 35 | VkImageCreateInfo imageCreateInfo = {}; 36 | imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; 37 | imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; 38 | imageCreateInfo.format = format; 39 | imageCreateInfo.extent = extent; 40 | imageCreateInfo.mipLevels = 1; 41 | imageCreateInfo.arrayLayers = 1; 42 | imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; 43 | imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 44 | imageCreateInfo.usage = usage; 45 | //imageCreateInfo.flags = 0; 46 | imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 47 | imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 48 | 49 | VkResult result = vkCreateImage(device, &imageCreateInfo, nullptr, &image); 50 | 51 | if (result != VK_SUCCESS) 52 | { 53 | throw std::runtime_error("Image creation failed"); 54 | } 55 | 56 | VkMemoryRequirements memRequirements; 57 | vkGetImageMemoryRequirements(device, image, &memRequirements); 58 | 59 | uint32_t imageSize = 0; 60 | uint32_t imageMemTypeIndex = GetMemoryTypeIndex(device, memRequirements, memProperties, props, imageSize); 61 | 62 | VkMemoryAllocateInfo memAllocInfo { }; 63 | memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 64 | memAllocInfo.allocationSize = imageSize; 65 | memAllocInfo.memoryTypeIndex = imageMemTypeIndex; 66 | 67 | result = vkAllocateMemory(device, &memAllocInfo, nullptr, &memory); 68 | 69 | if (result != VK_SUCCESS) 70 | { 71 | throw std::runtime_error("Memory allocation failed"); 72 | } 73 | 74 | result = vkBindImageMemory(device, image, memory, 0); 75 | 76 | if (result != VK_SUCCESS) 77 | { 78 | throw std::runtime_error("Bind image failed"); 79 | } 80 | } 81 | 82 | void Commands::SetupBuffer(VkDevice& device, VkBuffer& buffer, VkDeviceMemory& memory, VkDeviceSize size, VkMemoryPropertyFlags properties, VkBufferUsageFlags usage) 83 | { 84 | VkBufferCreateInfo bufferInfo = {}; 85 | bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 86 | bufferInfo.size = size; 87 | bufferInfo.usage = usage; 88 | bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 89 | 90 | VkResult result = vkCreateBuffer(device, &bufferInfo, nullptr, &buffer); 91 | 92 | if (result != VK_SUCCESS) 93 | { 94 | throw std::runtime_error("Transfer buffer creation failed"); 95 | } 96 | 97 | VkMemoryRequirements memRequirements; 98 | 99 | vkGetBufferMemoryRequirements(device, buffer, &memRequirements); 100 | 101 | uint32_t allocSize; 102 | uint32_t memTypeIndex = GetMemoryTypeIndex(device, memRequirements, memProperties, properties, allocSize); 103 | 104 | VkMemoryAllocateInfo allocInfo = {}; 105 | allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 106 | allocInfo.allocationSize = allocSize; 107 | allocInfo.memoryTypeIndex = memTypeIndex; 108 | 109 | result = vkAllocateMemory(device, &allocInfo, nullptr, &memory); 110 | 111 | if (result != VK_SUCCESS) 112 | { 113 | throw std::runtime_error("Buffer allocation failed"); 114 | } 115 | 116 | vkBindBufferMemory(device, buffer, memory, 0); 117 | } 118 | 119 | uint32_t Commands::GetMemoryTypeIndex(VkDevice& device, const VkMemoryRequirements& memRequirements, const VkPhysicalDeviceMemoryProperties& props, VkMemoryPropertyFlags propFlags, uint32_t& allocSize) const 120 | { 121 | uint32_t memTypeIndex = vfsme::InvalidIndex; 122 | 123 | for (uint32_t i = 0; i < props.memoryTypeCount; ++i) 124 | { 125 | if ((memRequirements.memoryTypeBits & (1 << i)) && 126 | (props.memoryTypes[i].propertyFlags & propFlags) == propFlags) 127 | { 128 | memTypeIndex = i; 129 | } 130 | } 131 | 132 | if (memTypeIndex == vfsme::InvalidIndex) 133 | { 134 | throw std::runtime_error("Memory property combination not supported"); 135 | } 136 | 137 | allocSize = memRequirements.size; 138 | 139 | return memTypeIndex; 140 | } 141 | 142 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /compositor.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "compositor.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace vfsme 26 | { 27 | 28 | Compositor::Compositor(const VkPhysicalDeviceMemoryProperties& memProps) 29 | : imageCount(2), 30 | drawIndex(0), 31 | memProperties(memProps) 32 | { 33 | images = new VkImage[imageCount](); 34 | imageViews = new VkImageView[imageCount](); 35 | } 36 | 37 | Compositor::~Compositor() 38 | { 39 | delete[] images; 40 | delete[] imageViews; 41 | } 42 | 43 | void Compositor::Init(VkDevice& device, 44 | const VkSurfaceKHR& surface, 45 | uint32_t width, 46 | uint32_t height, 47 | uint32_t queueFamilyId, 48 | uint32_t graphicsQueueIndex, 49 | uint32_t presentQueueIndex, 50 | uint32_t computeQueueIndex) 51 | { 52 | VkSurfaceTransformFlagBitsKHR transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 53 | 54 | VkExtent2D screenExtent = {width, height}; 55 | 56 | //actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); 57 | //actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); 58 | 59 | VkSwapchainCreateInfoKHR swapchainCreateInfo = {}; 60 | swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; 61 | swapchainCreateInfo.surface = surface; 62 | swapchainCreateInfo.minImageCount = imageCount; 63 | swapchainCreateInfo.imageFormat = surfaceFormat; 64 | swapchainCreateInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; 65 | swapchainCreateInfo.imageExtent = screenExtent; 66 | swapchainCreateInfo.imageArrayLayers = 1; 67 | swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 68 | swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; 69 | swapchainCreateInfo.queueFamilyIndexCount = 0; 70 | swapchainCreateInfo.pQueueFamilyIndices = nullptr; 71 | swapchainCreateInfo.preTransform = transform; 72 | swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 73 | swapchainCreateInfo.presentMode = presentMode; 74 | swapchainCreateInfo.clipped = VK_TRUE; 75 | swapchainCreateInfo.oldSwapchain = VK_NULL_HANDLE; 76 | 77 | bool result = vkCreateSwapchainKHR(device, &swapchainCreateInfo, nullptr, &swapChain); 78 | 79 | if (result != VK_SUCCESS) 80 | { 81 | throw std::runtime_error("Swapchain creation failed"); 82 | } 83 | 84 | vkGetDeviceQueue(device, queueFamilyId, graphicsQueueIndex, &graphicsQueue); 85 | vkGetDeviceQueue(device, queueFamilyId, presentQueueIndex, &presentQueue); 86 | vkGetDeviceQueue(device, queueFamilyId, computeQueueIndex, &computeQueue); 87 | 88 | vkDeviceWaitIdle(device); 89 | 90 | vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); 91 | vkGetSwapchainImagesKHR(device, swapChain, &imageCount, images); 92 | 93 | for (uint32_t i = 0; i < imageCount; ++i) 94 | { 95 | VkImageViewCreateInfo imageViewCreateInfo = {}; 96 | imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 97 | imageViewCreateInfo.image = images[i]; 98 | imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; 99 | imageViewCreateInfo.format = surfaceFormat; 100 | imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; 101 | imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; 102 | imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; 103 | imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; 104 | imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 105 | imageViewCreateInfo.subresourceRange.baseMipLevel = 0; 106 | imageViewCreateInfo.subresourceRange.levelCount = 1; 107 | imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; 108 | imageViewCreateInfo.subresourceRange.layerCount = 1; 109 | 110 | result = vkCreateImageView(device, &imageViewCreateInfo, nullptr, &imageViews[i]); 111 | 112 | if (result != VK_SUCCESS) 113 | { 114 | throw std::runtime_error("Image view creation failed"); 115 | } 116 | } 117 | 118 | graphicsEngine = new Renderer(screenExtent, grid, memProperties); 119 | 120 | graphicsEngine->Init(device, surfaceFormat, imageViews, queueFamilyId); 121 | 122 | VkCommandBuffer& staticTransferCommandBuffer = graphicsEngine->TransferStaticBuffers(device); 123 | 124 | VkCommandBuffer& dynamicTransferCommandBuffer = graphicsEngine->TransferDynamicBuffers(device); 125 | 126 | computer = new Compute(grid, memProperties); 127 | 128 | computer->Init(device); 129 | 130 | computer->SetupQueue(device, queueFamilyId); 131 | 132 | computeCommandBuffer = computer->SetupCommandBuffer(device, queueFamilyId); 133 | 134 | graphicsEngine->ConstructFrames(computer->GetStorageBuffer(), computer->GetNormalBuffer()); 135 | 136 | VkCommandBuffer transferCommandBuffers[] = { staticTransferCommandBuffer, dynamicTransferCommandBuffer }; 137 | 138 | VkSubmitInfo submitInfo = {}; 139 | submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 140 | submitInfo.commandBufferCount = 2; 141 | submitInfo.pCommandBuffers = transferCommandBuffers; 142 | 143 | vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); 144 | vkQueueWaitIdle(graphicsQueue); 145 | 146 | drawCommandBuffer = graphicsEngine->GetFrame(0); 147 | 148 | VkSemaphoreCreateInfo semaphoreInfo = {}; 149 | semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 150 | 151 | vkCreateSemaphore(device, &semaphoreInfo, nullptr, &waitSemaphore); 152 | vkCreateSemaphore(device, &semaphoreInfo, nullptr, &signalSemaphore); 153 | } 154 | 155 | void Compositor::Destroy(VkDevice& device) 156 | { 157 | vkDestroySemaphore(device, waitSemaphore, nullptr); 158 | vkDestroySemaphore(device, signalSemaphore, nullptr); 159 | 160 | graphicsEngine->Destroy(device); 161 | 162 | computer->Destroy(device); 163 | 164 | delete graphicsEngine; 165 | 166 | delete computer; 167 | 168 | for(uint32_t i = 0; i < imageCount; ++i) 169 | { 170 | vkDestroyImageView(device, imageViews[i], nullptr); 171 | } 172 | 173 | vkDestroySwapchainKHR(device, swapChain, nullptr); 174 | vkDestroyDevice(device, nullptr); 175 | } 176 | 177 | //bool once = true; 178 | 179 | void Compositor::Draw(VkDevice& device) 180 | { 181 | computer->UpdateWave(device); 182 | 183 | VkSubmitInfo submitInfo = {}; 184 | submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 185 | submitInfo.commandBufferCount = 1; 186 | submitInfo.pCommandBuffers = computeCommandBuffer; 187 | 188 | vkQueueSubmit(computeQueue, 1, &submitInfo, VK_NULL_HANDLE); 189 | 190 | ///@todo Move wait for idle to end of rendering or before queue destruction 191 | /// Memory barriers in compute queue should handle synchronization between queues 192 | vkQueueWaitIdle(computeQueue); 193 | 194 | /*if(once) 195 | { 196 | computer->PrintResults(device); 197 | once = false; 198 | }*/ 199 | 200 | transferCommandBuffer = &graphicsEngine->TransferDynamicBuffers(device); 201 | 202 | submitInfo = {}; 203 | submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 204 | submitInfo.commandBufferCount = 1; 205 | submitInfo.pCommandBuffers = transferCommandBuffer; 206 | 207 | vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); 208 | 209 | ///@todo Change to a flush or use a memory barrier 210 | vkQueueWaitIdle(graphicsQueue); 211 | 212 | drawCommandBuffer = graphicsEngine->GetFrame(drawIndex); 213 | 214 | uint32_t imageIndex; 215 | uint64_t max64BitInt = std::numeric_limits::max(); 216 | vkAcquireNextImageKHR(device, swapChain, max64BitInt, waitSemaphore, VK_NULL_HANDLE, &imageIndex); 217 | 218 | VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 219 | 220 | submitInfo = {}; 221 | submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 222 | submitInfo.waitSemaphoreCount = 1; 223 | submitInfo.pWaitSemaphores = &waitSemaphore; 224 | submitInfo.pWaitDstStageMask = &waitStage; 225 | submitInfo.signalSemaphoreCount = 1; 226 | submitInfo.pSignalSemaphores = &signalSemaphore; 227 | submitInfo.commandBufferCount = 1; 228 | submitInfo.pCommandBuffers = drawCommandBuffer; 229 | 230 | VkResult result = vkQueueSubmit(presentQueue, 1, &submitInfo, VK_NULL_HANDLE); 231 | 232 | if (result != VK_SUCCESS) 233 | { 234 | throw std::runtime_error("Queue submit failed"); 235 | } 236 | 237 | VkPresentInfoKHR presentInfo = {}; 238 | presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; 239 | presentInfo.waitSemaphoreCount = 1; 240 | presentInfo.pWaitSemaphores = &signalSemaphore; 241 | presentInfo.swapchainCount = 1; 242 | presentInfo.pSwapchains = &swapChain; 243 | presentInfo.pImageIndices = &imageIndex; 244 | //presentInfo.pResults = nullptr; 245 | 246 | vkQueuePresentKHR(presentQueue, &presentInfo); 247 | 248 | vkQueueWaitIdle(presentQueue); 249 | 250 | // Increment draw index to use correct image view for next frame 251 | drawIndex = (drawIndex + 1) % 2; 252 | } 253 | 254 | }; 255 | -------------------------------------------------------------------------------- /controller.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "controller.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace vfsme 29 | { 30 | 31 | const char* layers[] = { 32 | "VK_LAYER_LUNARG_standard_validation", 33 | "VK_LAYER_RENDERDOC_Capture" 34 | }; 35 | 36 | const uint32_t numLayers = 2; 37 | 38 | static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( 39 | VkDebugReportFlagsEXT flags, 40 | VkDebugReportObjectTypeEXT objType, 41 | uint64_t obj, 42 | size_t location, 43 | int32_t code, 44 | const char* layerPrefix, 45 | const char* msg, 46 | void* userData) 47 | { 48 | std::cerr << msg << std::endl; 49 | 50 | return VK_FALSE; 51 | } 52 | 53 | Controller::Controller() 54 | { 55 | queuePriorities = new float[queueCount](); 56 | } 57 | 58 | Controller::~Controller() 59 | { 60 | delete[] queuePriorities; 61 | } 62 | 63 | void Controller::Init() 64 | { 65 | VkApplicationInfo appInfo = {}; 66 | appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 67 | appInfo.pApplicationName = "Hello Triangle"; 68 | appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); 69 | appInfo.pEngineName = "No Engine"; 70 | appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); 71 | appInfo.apiVersion = VK_API_VERSION_1_0; 72 | 73 | VkInstanceCreateInfo createInfo = {}; 74 | createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 75 | createInfo.pApplicationInfo = &appInfo; 76 | 77 | uint32_t extensionCount = 0; 78 | vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); 79 | 80 | VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount](); 81 | vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions); 82 | 83 | for(uint32_t i = 0; i < extensionCount; ++i) 84 | { 85 | std::cout << extensions[i].extensionName << std::endl; 86 | } 87 | 88 | uint32_t requestedExtensionCount = 3; 89 | 90 | const char* requestedExtensions[] = 91 | { 92 | "VK_KHR_surface", 93 | "VK_KHR_win32_surface", 94 | "VK_EXT_debug_report" 95 | }; 96 | 97 | bool supported = false; 98 | 99 | for(uint32_t i = 0; i < requestedExtensionCount; ++i) 100 | { 101 | supported = false; 102 | 103 | for(uint32_t j = 0; j < extensionCount; ++j) 104 | { 105 | if (strncmp(requestedExtensions[i], extensions[j].extensionName, VK_MAX_EXTENSION_NAME_SIZE) == 0) 106 | { 107 | supported = true; 108 | } 109 | } 110 | 111 | if (supported == false) 112 | { 113 | std::cout << "Extension " << requestedExtensions[i] << " not supported" << std::endl; 114 | 115 | break; 116 | } 117 | } 118 | 119 | if (supported == false) 120 | { 121 | throw std::runtime_error("Extension not supported"); 122 | } 123 | 124 | createInfo.enabledExtensionCount = requestedExtensionCount; 125 | createInfo.ppEnabledExtensionNames = requestedExtensions; 126 | 127 | uint32_t layerCount; 128 | vkEnumerateInstanceLayerProperties(&layerCount, nullptr); 129 | VkLayerProperties* availableLayers = new VkLayerProperties[layerCount]();; 130 | vkEnumerateInstanceLayerProperties(&layerCount, availableLayers); 131 | 132 | supported = false; 133 | 134 | for(uint32_t i = 0; i < numLayers; ++i) 135 | { 136 | for(uint32_t j = 0; j < layerCount; ++j) 137 | { 138 | if (strcmp(layers[i], availableLayers[j].layerName) == 0) 139 | { 140 | supported = true; 141 | break; 142 | } 143 | 144 | std::cout << availableLayers[j].layerName << std::endl; 145 | } 146 | 147 | if (supported == false) 148 | { 149 | std::cout << "Layer not supported:" << layers[i] << std::endl; 150 | } 151 | } 152 | 153 | if (supported == false) 154 | { 155 | throw std::runtime_error("Layer not supported"); 156 | } 157 | 158 | createInfo.enabledLayerCount = 1; 159 | createInfo.ppEnabledLayerNames = layers; 160 | 161 | VkResult result = vkCreateInstance(&createInfo, nullptr, &instance); 162 | 163 | if (result != VK_SUCCESS) 164 | { 165 | throw std::runtime_error("Failed to create instance"); 166 | } 167 | 168 | VkDebugReportCallbackCreateInfoEXT callbackCreateInfo = {}; 169 | callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; 170 | callbackCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; 171 | callbackCreateInfo.pfnCallback = debugCallback; 172 | 173 | auto vkCreateDebugReportCallback = (PFN_vkCreateDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); 174 | 175 | VkResult callbackResult = vkCreateDebugReportCallback(instance, &callbackCreateInfo, nullptr, &callback); 176 | 177 | if (callbackResult != VK_SUCCESS) 178 | { 179 | throw std::runtime_error("Callback not created succesfuly"); 180 | } 181 | 182 | physicalDevice = VK_NULL_HANDLE; 183 | uint32_t deviceCount = 0; 184 | vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); 185 | 186 | if (deviceCount == 0) 187 | { 188 | throw std::runtime_error("Failed to find a device that supports Vulkan"); 189 | } 190 | 191 | VkPhysicalDevice* devices = new VkPhysicalDevice[deviceCount](); 192 | vkEnumeratePhysicalDevices(instance, &deviceCount, devices); 193 | VkPhysicalDeviceProperties deviceProperties; 194 | 195 | bool foundDiscreteGPU = false; 196 | 197 | std::cout << "Device count: " << deviceCount << std::endl; 198 | 199 | for (uint32_t i = 0; i < deviceCount; ++i) 200 | { 201 | vkGetPhysicalDeviceProperties(devices[i], &deviceProperties); 202 | 203 | std::cout << "Device type: " << deviceProperties.deviceType << std::endl; 204 | 205 | std::cout << "Storage buffer offset alignment: " << deviceProperties.limits.minStorageBufferOffsetAlignment << std::endl; 206 | 207 | if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) 208 | { 209 | physicalDevice = devices[i]; 210 | foundDiscreteGPU = true; 211 | break; 212 | } 213 | } 214 | 215 | if (foundDiscreteGPU == false) 216 | { 217 | throw std::runtime_error("failed to find a discrete GPU"); 218 | } 219 | 220 | vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures); 221 | 222 | vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); 223 | 224 | delete[] devices; 225 | delete[] availableLayers; 226 | delete[] extensions; 227 | 228 | CheckFormatPropertyType(VK_FORMAT_R32_SFLOAT, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT); 229 | } 230 | 231 | void Controller::Destroy() 232 | { 233 | auto vkDestroyDebugReportCallback = (PFN_vkDestroyDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); 234 | vkDestroyDebugReportCallback(instance, callback, nullptr); 235 | 236 | vkDestroyInstance(instance, nullptr); 237 | } 238 | 239 | void Controller::SetupQueue() 240 | { 241 | uint32_t queueFamilyCount = 0; 242 | vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr); 243 | 244 | if (queueFamilyCount == 0) 245 | { 246 | throw std::runtime_error("Failed to find a queue that supports the device"); 247 | } 248 | 249 | VkQueueFamilyProperties* queueFamilies = new VkQueueFamilyProperties[queueFamilyCount](); 250 | vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies); 251 | 252 | for (uint32_t i = 0; i < queueFamilyCount; ++i) 253 | { 254 | std::cout << "queue families: " << queueFamilies[i].queueCount << ", " << std::hex << queueFamilies[i].queueFlags << std::dec << std::endl; 255 | 256 | if (queueFamilies[i].queueCount > 0 && queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) 257 | { 258 | queueFamilyId = i; 259 | break; 260 | } 261 | } 262 | 263 | if (queueFamilyId == InvalidIndex) 264 | { 265 | throw std::runtime_error("Failed to get queue family index");; 266 | } 267 | 268 | delete[] queueFamilies; 269 | } 270 | 271 | void Controller::SetupDevice(const VkSurfaceKHR& surface) 272 | { 273 | VkBool32 presentSupport = false; 274 | vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyId, surface, &presentSupport); 275 | 276 | if (presentSupport != true) 277 | { 278 | throw std::runtime_error("surface presetation not supported"); 279 | } 280 | 281 | VkDeviceQueueCreateInfo queueCreateInfo = {}; 282 | 283 | queuePriorities[graphicsQueueIndex] = 1.0f; 284 | queuePriorities[presentQueueIndex] = 1.0f; 285 | 286 | queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 287 | queueCreateInfo.queueFamilyIndex = queueFamilyId; 288 | queueCreateInfo.queueCount = queueCount; 289 | queueCreateInfo.pQueuePriorities = queuePriorities; 290 | 291 | uint32_t deviceExtensionCount; 292 | vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount, nullptr); 293 | 294 | VkExtensionProperties* availableDeviceExtensions = new VkExtensionProperties[deviceExtensionCount](); 295 | vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount, availableDeviceExtensions); 296 | 297 | uint32_t requestedDeviceExtensionCount = 1; 298 | 299 | const char* requestedDeviceExtension = "VK_KHR_swapchain"; 300 | 301 | bool supported = false; 302 | 303 | for(uint32_t i = 0; i < deviceExtensionCount; ++i) 304 | { 305 | std::cout << availableDeviceExtensions[i].extensionName << std::endl; 306 | 307 | if (strncmp(requestedDeviceExtension, availableDeviceExtensions[i].extensionName, VK_MAX_EXTENSION_NAME_SIZE) == 0) 308 | { 309 | supported = true; 310 | } 311 | } 312 | 313 | if (supported == false) 314 | { 315 | throw std::runtime_error("VK_KHR_swapchain device extension not supported"); 316 | } 317 | 318 | VkDeviceCreateInfo deviceCreateInfo = {}; 319 | deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 320 | deviceCreateInfo.pEnabledFeatures = &deviceFeatures; 321 | deviceCreateInfo.enabledLayerCount = 1; 322 | deviceCreateInfo.ppEnabledLayerNames = layers; 323 | deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; 324 | deviceCreateInfo.queueCreateInfoCount = 1; 325 | deviceCreateInfo.enabledExtensionCount = requestedDeviceExtensionCount; 326 | deviceCreateInfo.ppEnabledExtensionNames = &requestedDeviceExtension; 327 | 328 | VkResult deviceResult = vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device); 329 | 330 | if (deviceResult != VK_SUCCESS) 331 | { 332 | throw std::runtime_error("failed to create device"); 333 | } 334 | 335 | delete[] availableDeviceExtensions; 336 | } 337 | 338 | void Controller::Configure(const VkSurfaceKHR& surface) 339 | { 340 | vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities); 341 | 342 | PrintCapabilities(); 343 | 344 | VkSurfaceTransformFlagBitsKHR transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 345 | 346 | if ((capabilities.supportedTransforms & transform) == 0) 347 | { 348 | throw std::runtime_error("Transform not supported"); 349 | } 350 | } 351 | 352 | void Controller::PrintCapabilities() const 353 | { 354 | /*uint32_t minImageCount; 355 | uint32_t maxImageCount; 356 | VkExtent2D currentExtent; 357 | VkExtent2D minImageExtent; 358 | VkExtent2D maxImageExtent; 359 | uint32_t maxImageArrayLayers; 360 | VkSurfaceTransformFlagsKHR supportedTransforms; 361 | VkSurfaceTransformFlagBitsKHR currentTransform; 362 | VkCompositeAlphaFlagsKHR supportedCompositeAlpha; 363 | VkImageUsageFlags supportedUsageFlags;*/ 364 | 365 | std::cout << capabilities.minImageCount << std::endl; 366 | std::cout << capabilities.maxImageCount << std::endl; 367 | std::cout << capabilities.currentExtent.width << std::endl; 368 | std::cout << capabilities.currentExtent.height << std::endl; 369 | std::cout << capabilities.minImageExtent.width << std::endl; 370 | std::cout << capabilities.minImageExtent.height << std::endl; 371 | std::cout << capabilities.maxImageExtent.width << std::endl; 372 | std::cout << capabilities.maxImageExtent.height << std::endl; 373 | std::cout << capabilities.maxImageArrayLayers << std::endl; 374 | std::cout << capabilities.supportedTransforms << std::endl; 375 | std::cout << capabilities.currentTransform << std::endl; 376 | std::cout << capabilities.supportedCompositeAlpha << std::endl; 377 | std::cout << capabilities.supportedUsageFlags << std::endl; 378 | } 379 | 380 | bool Controller::PresentModeSupported(const VkSurfaceKHR& surface, VkPresentModeKHR presentMode) 381 | { 382 | uint32_t presentModeCount; 383 | vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr); 384 | VkPresentModeKHR* supportedPresentModes = new VkPresentModeKHR[presentModeCount](); 385 | vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, supportedPresentModes); 386 | 387 | bool supported = false; 388 | 389 | for(uint32_t i = 0; i < presentModeCount; ++i) 390 | { 391 | std::cout << std::hex << supportedPresentModes[i] << std::endl; 392 | 393 | if (supportedPresentModes[i] == presentMode) 394 | { 395 | supported = true; 396 | } 397 | } 398 | 399 | if (!supported) 400 | { 401 | std::cout << "Present mode not supported" << std::endl; 402 | } 403 | 404 | delete[] supportedPresentModes; 405 | 406 | return supported; 407 | } 408 | 409 | bool Controller::SurfaceFormatSupported(const VkSurfaceKHR& surface, VkFormat surfaceFormat) const 410 | { 411 | uint32_t formatCount; 412 | vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr); 413 | VkSurfaceFormatKHR* surfaceFormats = new VkSurfaceFormatKHR[formatCount](); 414 | vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, surfaceFormats); 415 | 416 | bool supported = false; 417 | 418 | std::cout << std::endl; 419 | for(uint32_t i = 0; i < formatCount; ++i) 420 | { 421 | std::cout << std::hex << surfaceFormats[i].format << ", " << surfaceFormats[i].colorSpace << std::endl; 422 | 423 | if (surfaceFormats[i].format == surfaceFormat) 424 | { 425 | supported = true; 426 | } 427 | } 428 | 429 | if (!supported) 430 | { 431 | std::cout << "Format not supported" << std::endl; 432 | } 433 | 434 | delete[] surfaceFormats; 435 | 436 | return supported; 437 | } 438 | 439 | void Controller::CheckFormatPropertyType(VkFormat format, VkFormatFeatureFlagBits flags) const 440 | { 441 | VkFormatProperties formatProps; 442 | vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProps); 443 | 444 | if ((formatProps.optimalTilingFeatures & flags) == 0) 445 | { 446 | throw std::runtime_error("Format property not optimal"); 447 | } 448 | } 449 | 450 | }; -------------------------------------------------------------------------------- /compute.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "compute.h" 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace vfsme 25 | { 26 | 27 | Compute::Compute(const VkExtent3D& inputExtent, const VkPhysicalDeviceMemoryProperties& props) 28 | : Commands(props), 29 | extent(inputExtent), 30 | uniformBufferSize(sizeof(float) * numWaveComponents), 31 | storageBufferSize(sizeof(float) * inputExtent.width * inputExtent.height), 32 | normalBufferSize(sizeof(float[4]) * inputExtent.width * inputExtent.height), 33 | startTime(std::chrono::high_resolution_clock::now()) 34 | { 35 | const float pi = 3.14159; 36 | wave.lambda = 6.0; 37 | wave.k = 2.0*pi/wave.lambda; 38 | wave.omega = 2.0; 39 | wave.dx = 0.5; 40 | wave.amplitude = 1.0; 41 | } 42 | 43 | void Compute::Init(VkDevice& device) 44 | { 45 | VkMemoryPropertyFlags properties; 46 | VkBufferUsageFlags usage; 47 | 48 | properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 49 | usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; 50 | 51 | SetupBuffer(device, uniformBuffer, uniformBufferMemory, uniformBufferSize, properties, usage); 52 | 53 | properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 54 | usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; 55 | 56 | SetupBuffer(device, storageBuffer, storageBufferMemory, storageBufferSize, properties, usage); 57 | 58 | properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 59 | usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; 60 | 61 | SetupBuffer(device, normalBuffer, normalBufferMemory, normalBufferSize, properties, usage); 62 | } 63 | 64 | void Compute::Destroy(VkDevice& device) 65 | { 66 | vkFreeMemory(device, uniformBufferMemory, nullptr); 67 | vkDestroyBuffer(device, uniformBuffer, nullptr); 68 | 69 | vkFreeMemory(device, storageBufferMemory, nullptr); 70 | vkDestroyBuffer(device, storageBuffer, nullptr); 71 | 72 | vkFreeMemory(device, normalBufferMemory, nullptr); 73 | vkDestroyBuffer(device, normalBuffer, nullptr); 74 | 75 | vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); 76 | vkDestroyDescriptorPool(device, descriptorPool, nullptr); 77 | 78 | vkDestroyPipeline(device, pipeline, nullptr); 79 | vkDestroyPipelineLayout(device, pipelineLayout, nullptr); 80 | vkDestroyShaderModule(device, shaderModule, nullptr); 81 | 82 | vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); 83 | 84 | vkDestroyCommandPool(device, commandPool, nullptr); 85 | 86 | vkDestroyFence(device, fence, nullptr); 87 | } 88 | 89 | void Compute::SetupQueue(VkDevice& device, uint32_t queueFamilyId) 90 | { 91 | uint32_t uniformIndex = 0; 92 | uint32_t storageIndex = 1; 93 | uint32_t normalIndex = 2; 94 | 95 | uint32_t numBindings = 3; 96 | 97 | VkDescriptorSetLayoutBinding layoutBindings[] = {{},{},{}}; 98 | 99 | layoutBindings[uniformIndex].binding = 0; 100 | layoutBindings[uniformIndex].descriptorCount = 1; 101 | layoutBindings[uniformIndex].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 102 | layoutBindings[uniformIndex].pImmutableSamplers = nullptr; 103 | layoutBindings[uniformIndex].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; 104 | 105 | layoutBindings[storageIndex].binding = 1; 106 | layoutBindings[storageIndex].descriptorCount = 1; 107 | layoutBindings[storageIndex].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 108 | layoutBindings[storageIndex].pImmutableSamplers = nullptr; 109 | layoutBindings[storageIndex].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; 110 | 111 | layoutBindings[normalIndex].binding = 2; 112 | layoutBindings[normalIndex].descriptorCount = 1; 113 | layoutBindings[normalIndex].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 114 | layoutBindings[normalIndex].pImmutableSamplers = nullptr; 115 | layoutBindings[normalIndex].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; 116 | 117 | VkDescriptorSetLayoutCreateInfo layoutCreateInfo = {}; 118 | layoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; 119 | layoutCreateInfo.bindingCount = numBindings; 120 | layoutCreateInfo.pBindings = layoutBindings; 121 | 122 | VkResult result = vkCreateDescriptorSetLayout(device, &layoutCreateInfo, nullptr, &descriptorSetLayout); 123 | 124 | if (result != VK_SUCCESS) 125 | { 126 | throw std::runtime_error("Descriptor set layout creation failed"); 127 | } 128 | 129 | VkDescriptorPoolSize poolSizes[2]; 130 | poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 131 | poolSizes[0].descriptorCount = 1; 132 | 133 | poolSizes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 134 | poolSizes[1].descriptorCount = 2; 135 | 136 | VkDescriptorPoolCreateInfo poolCreateInfo = {}; 137 | poolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; 138 | poolCreateInfo.maxSets = 1; 139 | poolCreateInfo.poolSizeCount = 2; 140 | poolCreateInfo.pPoolSizes = poolSizes; 141 | 142 | result = vkCreateDescriptorPool(device, &poolCreateInfo, nullptr, &descriptorPool); 143 | 144 | if (result != VK_SUCCESS) 145 | { 146 | throw std::runtime_error("Descriptor pool creation failed"); 147 | } 148 | 149 | VkDescriptorSetAllocateInfo allocInfo = {}; 150 | allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; 151 | allocInfo.descriptorPool = descriptorPool; 152 | allocInfo.descriptorSetCount = 1; 153 | allocInfo.pSetLayouts = &descriptorSetLayout; 154 | 155 | result = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet); 156 | 157 | if (result != VK_SUCCESS) 158 | { 159 | throw std::runtime_error("Descriptor set allocation failed"); 160 | } 161 | 162 | VkDescriptorBufferInfo bufferInfo[] = { {}, {}, {} };; 163 | bufferInfo[uniformIndex].buffer = uniformBuffer; 164 | bufferInfo[uniformIndex].offset = 0; 165 | bufferInfo[uniformIndex].range = uniformBufferSize; 166 | 167 | bufferInfo[storageIndex].buffer = storageBuffer; 168 | bufferInfo[storageIndex].offset = 0; 169 | bufferInfo[storageIndex].range = storageBufferSize; 170 | 171 | bufferInfo[normalIndex].buffer = normalBuffer; 172 | bufferInfo[normalIndex].offset = 0; 173 | bufferInfo[normalIndex].range = normalBufferSize; 174 | 175 | VkWriteDescriptorSet descriptorWrites[] = { {}, {}, {} }; 176 | descriptorWrites[uniformIndex].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 177 | descriptorWrites[uniformIndex].dstSet = descriptorSet; 178 | descriptorWrites[uniformIndex].dstBinding = 0; 179 | descriptorWrites[uniformIndex].dstArrayElement = 0; 180 | descriptorWrites[uniformIndex].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 181 | descriptorWrites[uniformIndex].descriptorCount = 1; 182 | descriptorWrites[uniformIndex].pBufferInfo = &bufferInfo[uniformIndex]; 183 | 184 | descriptorWrites[storageIndex].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 185 | descriptorWrites[storageIndex].dstSet = descriptorSet; 186 | descriptorWrites[storageIndex].dstBinding = 1; 187 | descriptorWrites[storageIndex].dstArrayElement = 0; 188 | descriptorWrites[storageIndex].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 189 | descriptorWrites[storageIndex].descriptorCount = 1; 190 | descriptorWrites[storageIndex].pBufferInfo = &bufferInfo[storageIndex]; 191 | 192 | descriptorWrites[normalIndex].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 193 | descriptorWrites[normalIndex].dstSet = descriptorSet; 194 | descriptorWrites[normalIndex].dstBinding = 2; 195 | descriptorWrites[normalIndex].dstArrayElement = 0; 196 | descriptorWrites[normalIndex].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 197 | descriptorWrites[normalIndex].descriptorCount = 1; 198 | descriptorWrites[normalIndex].pBufferInfo = &bufferInfo[normalIndex]; 199 | 200 | vkUpdateDescriptorSets(device, numBindings, descriptorWrites, 0, nullptr); 201 | 202 | std::ifstream file("comp.spv", std::ios::ate | std::ios::binary); 203 | 204 | if (!file.is_open()) 205 | { 206 | std::cout << "Failed to open shader file" << std::endl; 207 | } 208 | 209 | size_t shaderFileSize = static_cast(file.tellg()); 210 | char* shader = new char[shaderFileSize](); 211 | 212 | file.seekg(0); 213 | file.read(shader, shaderFileSize); 214 | file.close(); 215 | 216 | VkShaderModuleCreateInfo shaderCreateInfo = {}; 217 | shaderCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 218 | shaderCreateInfo.codeSize = shaderFileSize; 219 | shaderCreateInfo.pCode = (uint32_t*) shader; 220 | 221 | vkCreateShaderModule(device, &shaderCreateInfo, nullptr, &shaderModule); 222 | 223 | delete[] shader; 224 | 225 | VkPipelineShaderStageCreateInfo shaderStageCreateInfo = {}; 226 | shaderStageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 227 | shaderStageCreateInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; 228 | shaderStageCreateInfo.module = shaderModule; 229 | shaderStageCreateInfo.pName = "main"; 230 | 231 | VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; 232 | pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 233 | pipelineLayoutInfo.setLayoutCount = 1; 234 | pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; 235 | 236 | result = vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout); 237 | 238 | if (result != VK_SUCCESS) 239 | { 240 | throw std::runtime_error("Pipeline layout creation failed"); 241 | } 242 | 243 | VkComputePipelineCreateInfo pipelineCreateInfo = {}; 244 | pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; 245 | pipelineCreateInfo.stage = shaderStageCreateInfo; 246 | pipelineCreateInfo.layout = pipelineLayout; 247 | 248 | result = vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &pipelineCreateInfo, nullptr, &pipeline); 249 | 250 | VkCommandPoolCreateInfo cmdPoolInfo = {}; 251 | cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; 252 | cmdPoolInfo.queueFamilyIndex = queueFamilyId; 253 | cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; 254 | result = vkCreateCommandPool(device, &cmdPoolInfo, nullptr, &commandPool); 255 | 256 | VkCommandBufferAllocateInfo cmdBufAllocInfo = {}; 257 | cmdBufAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 258 | cmdBufAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 259 | cmdBufAllocInfo.commandPool = commandPool; 260 | cmdBufAllocInfo.commandBufferCount = 1; 261 | 262 | vkAllocateCommandBuffers(device, &cmdBufAllocInfo, &commandBuffer); 263 | 264 | VkFenceCreateInfo fenceCreateInfo = {}; 265 | fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; 266 | fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; 267 | vkCreateFence(device, &fenceCreateInfo, nullptr, &fence); 268 | } 269 | 270 | VkCommandBuffer* Compute::SetupCommandBuffer(VkDevice& device, uint32_t queueFamilyId) 271 | { 272 | VkCommandBufferBeginInfo beginInfo = {}; 273 | beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 274 | beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; 275 | 276 | VkResult result = vkBeginCommandBuffer(commandBuffer, &beginInfo); 277 | 278 | if (result != VK_SUCCESS) 279 | { 280 | throw std::runtime_error("Compute command buffer beign failed"); 281 | } 282 | 283 | memoryBarriers[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 284 | memoryBarriers[0].buffer = storageBuffer; 285 | memoryBarriers[0].size = storageBufferSize; 286 | memoryBarriers[0].srcAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; 287 | memoryBarriers[0].dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; 288 | memoryBarriers[0].srcQueueFamilyIndex = queueFamilyId; 289 | memoryBarriers[0].dstQueueFamilyIndex = queueFamilyId; 290 | 291 | memoryBarriers[1].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 292 | memoryBarriers[1].buffer = normalBuffer; 293 | memoryBarriers[1].size = normalBufferSize; 294 | memoryBarriers[1].srcAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; 295 | memoryBarriers[1].dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; 296 | memoryBarriers[1].srcQueueFamilyIndex = queueFamilyId; 297 | memoryBarriers[1].dstQueueFamilyIndex = queueFamilyId; 298 | 299 | vkCmdPipelineBarrier(commandBuffer, 300 | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 301 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 302 | 0, 303 | 0, nullptr, 304 | 2, memoryBarriers, 305 | 0, nullptr); 306 | 307 | vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); 308 | vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, 1, &descriptorSet, 0, 0); 309 | vkCmdDispatch(commandBuffer, extent.width, extent.height, 1); 310 | 311 | memoryBarriers[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 312 | memoryBarriers[0].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; 313 | memoryBarriers[0].dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; 314 | memoryBarriers[0].buffer = storageBuffer; 315 | memoryBarriers[0].size = storageBufferSize; 316 | memoryBarriers[0].srcQueueFamilyIndex = queueFamilyId; 317 | memoryBarriers[0].dstQueueFamilyIndex = queueFamilyId; 318 | 319 | memoryBarriers[1].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 320 | memoryBarriers[1].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; 321 | memoryBarriers[1].dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; 322 | memoryBarriers[1].buffer = normalBuffer; 323 | memoryBarriers[1].size = normalBufferSize; 324 | memoryBarriers[1].srcQueueFamilyIndex = queueFamilyId; 325 | memoryBarriers[1].dstQueueFamilyIndex = queueFamilyId; 326 | 327 | vkCmdPipelineBarrier(commandBuffer, 328 | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 329 | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 330 | 0, 331 | 0, nullptr, 332 | 2, memoryBarriers, 333 | 0, nullptr); 334 | 335 | vkEndCommandBuffer(commandBuffer); 336 | 337 | return &commandBuffer; 338 | } 339 | 340 | void Compute::UpdateWave(VkDevice& device) 341 | { 342 | auto currentTime = std::chrono::high_resolution_clock::now(); 343 | float time = std::chrono::duration_cast(currentTime - startTime).count() / 1000.0f; 344 | 345 | void* data; 346 | vkMapMemory(device, uniformBufferMemory, 0, uniformBufferSize, 0, &data); 347 | 348 | float* waveData = static_cast(data); 349 | 350 | ///@todo Only time needs to be dynamically update 351 | /// Move wave parameters to static update 352 | waveData[0] = time; 353 | waveData[1] = wave.dx; 354 | waveData[2] = wave.k; 355 | waveData[3] = wave.omega; 356 | waveData[4] = wave.amplitude; 357 | 358 | vkUnmapMemory(device, uniformBufferMemory); 359 | } 360 | 361 | void Compute::PrintResults(VkDevice& device) 362 | { 363 | void* data; 364 | //vkMapMemory(device, storageBufferMemory, 0, storageBufferSize, 0, &data); 365 | vkMapMemory(device, normalBufferMemory, 0, normalBufferSize, 0, &data); 366 | 367 | float* mem = static_cast(data); 368 | 369 | for(uint32_t i = 0; i < extent.width; ++i) 370 | { 371 | for(uint32_t j = 0; j < extent.height; ++j) 372 | { 373 | //std::cout << static_cast(data)[i*extent.width + j] << ", "; 374 | std::cout << "{ " << mem[i*extent.width + j*4] << ", " 375 | << mem[i*extent.width + j*4 + 1] << ", " 376 | << mem[i*extent.width + j*4 + 2] << ", " 377 | << mem[i*extent.width + j*4 + 3] << " }"; 378 | } 379 | 380 | std::cout << std::endl; 381 | } 382 | 383 | vkUnmapMemory(device, normalBufferMemory); 384 | } 385 | 386 | }; -------------------------------------------------------------------------------- /renderer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 Nigel Williams 3 | * 4 | * Vulkan Free Surface Modeling Engine (VFSME) is free software: 5 | * you can redistribute it and/or modify it under the terms of the 6 | * GNU Lesser General Public License as published by 7 | * the Free Software Foundation, version 3. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "renderer.h" 19 | 20 | #ifdef __STDC_LIB_EXT1__ 21 | #define __STDC_WANT_LIB_EXT1__ 1 22 | #endif 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define GLM_FORCE_RADIANS 34 | #include 35 | #include 36 | #include //"glm/gtx/string_cast.hpp" 37 | 38 | namespace vfsme 39 | { 40 | 41 | Renderer::Renderer(const VkExtent2D& extent, const VkExtent3D& gridDim, const VkPhysicalDeviceMemoryProperties& memProps) 42 | : Commands(memProps), 43 | imageExtent(extent), 44 | grid(gridDim) 45 | { 46 | numVerts = grid.width * grid.height; 47 | numPrims = (grid.width - 1) * (grid.height - 1) * 2; 48 | vertexInfoSize = sizeof(float) * numComponents * numVerts * numVertexElements; 49 | numIndices = numPrims * numComponents; 50 | indicesBufferSize = sizeof(uint16_t) * numIndices; 51 | mat4Size = sizeof(float) * 16; 52 | uboSize = mat4Size * 3 + sizeof(float[3]); 53 | 54 | vertexInfo = new float[vertexInfoSize](); 55 | indices = new uint16_t[indicesBufferSize](); 56 | framebuffers = new VkFramebuffer[numFBOs](); 57 | drawCommandBuffers = new VkCommandBuffer[numDrawCmdBuffers](); 58 | attributeDescriptions = new VkVertexInputAttributeDescription[numAttrDesc](); 59 | bindingDescriptions = new VkVertexInputBindingDescription[numBindDesc](); 60 | } 61 | 62 | Renderer::~Renderer() 63 | { 64 | delete[] vertexInfo; 65 | delete[] indices; 66 | delete[] framebuffers; 67 | delete[] drawCommandBuffers; 68 | delete[] attributeDescriptions; 69 | delete[] bindingDescriptions; 70 | } 71 | 72 | void Renderer::Init(VkDevice& device, const VkFormat& surfaceFormat, const VkImageView* imageViews, uint32_t queueFamilyId) 73 | { 74 | size_t vertexShaderFileSize; 75 | char* vertexShader; 76 | size_t fragmentShaderFileSize; 77 | char* fragmentShader; 78 | 79 | float delta = 0.5f; 80 | uint32_t index = 0; 81 | float xStartPos = - ((grid.width - 1) * delta) / 2; 82 | float yStartPos = - ((grid.height - 1) * delta) / 2; 83 | float xPos = xStartPos; 84 | float yPos = yStartPos; 85 | float zPos = 0.0f; 86 | 87 | for (uint32_t i = 0; i < grid.height; ++i) 88 | { 89 | for (uint32_t j = 0; j < grid.width; ++j) 90 | { 91 | // Position 92 | vertexInfo[index] = xPos; 93 | vertexInfo[index + 1] = zPos; 94 | vertexInfo[index + 2] = yPos; 95 | 96 | // Color 97 | vertexInfo[index + 3] = 0.0f; 98 | vertexInfo[index + 4] = 0.0f; 99 | vertexInfo[index + 5] = 1.0f; 100 | 101 | // Normal 102 | //vertexInfo[index + 6] = 0.0f; 103 | //vertexInfo[index + 7] = 1.0f; 104 | //vertexInfo[index + 8] = 0.0f; 105 | 106 | index += 6; 107 | xPos += delta; 108 | } 109 | 110 | xPos = xStartPos; 111 | yPos += delta; 112 | } 113 | 114 | index = 0; 115 | 116 | for (uint32_t i = 0; i < grid.height - 1; ++i) 117 | { 118 | for (uint32_t j = 0; j < grid.width - 1; ++j) 119 | { 120 | indices[index] = i * grid.width + j; 121 | indices[index + 1] = indices[index] + 1; 122 | indices[index + 2] = indices[index] + grid.width; 123 | 124 | indices[index + 3] = indices[index + 2]; 125 | indices[index + 4] = indices[index + 3] + 1; 126 | indices[index + 5] = indices[index + 1]; 127 | 128 | index += 6; 129 | } 130 | } 131 | 132 | SetupServerSideVertexBuffer(device); 133 | SetupIndexBuffer(device); 134 | SetupUniformBuffer(device); 135 | SetupShaderParameters(device); 136 | 137 | std::ifstream file("vert.spv", std::ios::ate | std::ios::binary); 138 | 139 | if (!file.is_open()) 140 | { 141 | std::cout << "Failed to open shader file" << std::endl; 142 | } 143 | 144 | vertexShaderFileSize = static_cast(file.tellg()); 145 | vertexShader = new char[vertexShaderFileSize](); 146 | 147 | file.seekg(0); 148 | file.read(vertexShader, vertexShaderFileSize); 149 | file.close(); 150 | 151 | file.open("frag.spv", std::ios::ate | std::ios::binary); 152 | 153 | if (!file.is_open()) 154 | { 155 | std::cout << "Failed to open shader file" << std::endl; 156 | } 157 | 158 | fragmentShaderFileSize = static_cast(file.tellg()); 159 | fragmentShader = new char[fragmentShaderFileSize](); 160 | 161 | file.seekg(0); 162 | file.read(fragmentShader, fragmentShaderFileSize); 163 | file.close(); 164 | 165 | VkShaderModuleCreateInfo shaderCreateInfo = {}; 166 | shaderCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 167 | shaderCreateInfo.codeSize = vertexShaderFileSize; 168 | shaderCreateInfo.pCode = (uint32_t*) vertexShader; 169 | 170 | vkCreateShaderModule(device, &shaderCreateInfo, nullptr, &vertexShaderModule); 171 | 172 | shaderCreateInfo.codeSize = fragmentShaderFileSize; 173 | shaderCreateInfo.pCode = (uint32_t*) fragmentShader; 174 | 175 | vkCreateShaderModule(device, &shaderCreateInfo, nullptr, &fragmentShaderModule); 176 | 177 | delete[] fragmentShader; 178 | delete[] vertexShader; 179 | 180 | VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; 181 | vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 182 | vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; 183 | vertShaderStageInfo.module = vertexShaderModule; 184 | vertShaderStageInfo.pName = "main"; 185 | 186 | VkPipelineShaderStageCreateInfo fragShaderStageInfo = {}; 187 | fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 188 | fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; 189 | fragShaderStageInfo.module = fragmentShaderModule; 190 | fragShaderStageInfo.pName = "main"; 191 | 192 | VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo}; 193 | 194 | VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; 195 | vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; 196 | vertexInputInfo.vertexBindingDescriptionCount = numBindDesc; 197 | vertexInputInfo.vertexAttributeDescriptionCount = numAttrDesc; 198 | vertexInputInfo.pVertexBindingDescriptions = bindingDescriptions; 199 | vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions; 200 | 201 | VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; 202 | inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 203 | inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 204 | inputAssembly.primitiveRestartEnable = VK_FALSE; 205 | 206 | VkViewport viewport = {}; 207 | viewport.x = 0.0f; 208 | viewport.y = 0.0f; 209 | viewport.width = (float) imageExtent.width; 210 | viewport.height = (float) imageExtent.height; 211 | viewport.minDepth = 0.0f; 212 | viewport.maxDepth = 1.0f; 213 | 214 | VkRect2D scissor = {}; 215 | scissor.offset = {0, 0}; 216 | scissor.extent = imageExtent; 217 | 218 | VkPipelineViewportStateCreateInfo viewportState = {}; 219 | viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 220 | viewportState.viewportCount = 1; 221 | viewportState.pViewports = &viewport; 222 | viewportState.scissorCount = 1; 223 | viewportState.pScissors = &scissor; 224 | 225 | VkPipelineRasterizationStateCreateInfo rasterizer = {}; 226 | rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; 227 | rasterizer.depthClampEnable = VK_FALSE; 228 | rasterizer.rasterizerDiscardEnable = VK_FALSE; 229 | rasterizer.polygonMode = VK_POLYGON_MODE_FILL; 230 | rasterizer.lineWidth = 1.0f; 231 | //rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; 232 | rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; 233 | rasterizer.depthBiasEnable = VK_FALSE; 234 | //rasterizer.depthBiasConstantFactor = 0.0f; 235 | //rasterizer.depthBiasClamp = 0.0f; 236 | //rasterizer.depthBiasSlopeFactor = 0.0f; 237 | 238 | VkPipelineMultisampleStateCreateInfo multisampling = {}; 239 | multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; 240 | multisampling.sampleShadingEnable = VK_FALSE; 241 | multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; 242 | //multisampling.minSampleShading = 1.0f; 243 | //multisampling.pSampleMask = nullptr; 244 | //multisampling.alphaToCoverageEnable = VK_FALSE; 245 | //multisampling.alphaToOneEnable = VK_FALSE; 246 | 247 | //VkPipelineDepthStencilStateCreateInfo 248 | 249 | VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; 250 | colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; 251 | colorBlendAttachment.blendEnable = VK_FALSE; 252 | //colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; 253 | //colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; 254 | //colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; 255 | //colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; 256 | //colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; 257 | //colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; 258 | //colorBlendAttachment.blendEnable = VK_TRUE; 259 | //colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; 260 | //colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; 261 | //colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; 262 | //colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; 263 | //colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; 264 | //colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; 265 | 266 | VkPipelineColorBlendStateCreateInfo colorBlending = {}; 267 | colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; 268 | colorBlending.logicOpEnable = VK_FALSE; 269 | //colorBlending.logicOp = VK_LOGIC_OP_COPY; 270 | colorBlending.attachmentCount = 1; 271 | colorBlending.pAttachments = &colorBlendAttachment; 272 | //colorBlending.blendConstants[0] = 0.0f; 273 | //colorBlending.blendConstants[1] = 0.0f; 274 | //colorBlending.blendConstants[2] = 0.0f; 275 | //colorBlending.blendConstants[3] = 0.0f; 276 | 277 | //VkDynamicState dynamicStates[] = { 278 | // VK_DYNAMIC_STATE_VIEWPORT, 279 | // VK_DYNAMIC_STATE_LINE_WIDTH 280 | //}; 281 | 282 | //VkPipelineDynamicStateCreateInfo dynamicState = {}; 283 | //dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; 284 | //dynamicState.dynamicStateCount = 2; 285 | //dynamicState.pDynamicStates = dynamicStates; 286 | 287 | VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; 288 | pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 289 | pipelineLayoutInfo.setLayoutCount = 1; 290 | pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; 291 | //pipelineLayoutInfo.pushConstantRangeCount = 0; 292 | //pipelineLayoutInfo.pPushConstantRanges = 0; 293 | 294 | VkResult result = vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout); 295 | 296 | if (result != VK_SUCCESS) 297 | { 298 | throw std::runtime_error("Pipeline layout creation failed"); 299 | } 300 | 301 | VkAttachmentDescription colorAttachment = {}; 302 | colorAttachment.format = surfaceFormat; 303 | colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; 304 | colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; 305 | colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; 306 | colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 307 | colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 308 | colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 309 | colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; 310 | 311 | VkAttachmentReference colorAttachmentRef = {}; 312 | colorAttachmentRef.attachment = 0; 313 | colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 314 | 315 | VkSubpassDescription subPass = {}; 316 | subPass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 317 | subPass.colorAttachmentCount = 1; 318 | subPass.pColorAttachments = &colorAttachmentRef; 319 | 320 | VkSubpassDependency dependency = {}; 321 | dependency.srcSubpass = VK_SUBPASS_EXTERNAL; 322 | dependency.dstSubpass = 0; 323 | dependency.srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; 324 | dependency.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; 325 | dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 326 | dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 327 | 328 | VkRenderPassCreateInfo renderPassInfo = {}; 329 | renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; 330 | renderPassInfo.attachmentCount = 1; 331 | renderPassInfo.pAttachments = &colorAttachment; 332 | renderPassInfo.subpassCount = 1; 333 | renderPassInfo.pSubpasses = &subPass; 334 | renderPassInfo.dependencyCount = 1; 335 | renderPassInfo.pDependencies = &dependency; 336 | 337 | result = vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass); 338 | 339 | if (result != VK_SUCCESS) 340 | { 341 | throw std::runtime_error("Render pass creation failed"); 342 | } 343 | 344 | VkGraphicsPipelineCreateInfo pipelineInfo = {}; 345 | pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 346 | pipelineInfo.stageCount = 2; 347 | pipelineInfo.pStages = shaderStages; 348 | pipelineInfo.pVertexInputState = &vertexInputInfo; 349 | pipelineInfo.pInputAssemblyState = &inputAssembly; 350 | pipelineInfo.pViewportState = &viewportState; 351 | pipelineInfo.pRasterizationState = &rasterizer; 352 | pipelineInfo.pMultisampleState = &multisampling; 353 | //pipelineInfo.pDepthStencilState = nullptr; 354 | pipelineInfo.pColorBlendState = &colorBlending; 355 | //pipelineInfo.pDynamicState = nullptr; 356 | pipelineInfo.layout = pipelineLayout; 357 | pipelineInfo.renderPass = renderPass; 358 | pipelineInfo.subpass = 0; 359 | pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; 360 | pipelineInfo.basePipelineIndex = -1; 361 | 362 | result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline); 363 | 364 | if (result != VK_SUCCESS) 365 | { 366 | throw std::runtime_error("Pipeline creation failed"); 367 | } 368 | 369 | for (uint32_t i = 0; i < numFBOs; ++i) 370 | { 371 | VkFramebufferCreateInfo framebufferInfo = {}; 372 | framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; 373 | framebufferInfo.renderPass = renderPass; 374 | framebufferInfo.attachmentCount = 1; 375 | framebufferInfo.pAttachments = &imageViews[i]; 376 | framebufferInfo.width = imageExtent.width; 377 | framebufferInfo.height = imageExtent.height; 378 | framebufferInfo.layers = 1; 379 | 380 | result = vkCreateFramebuffer(device, &framebufferInfo, nullptr, &framebuffers[i]); 381 | 382 | if (result != VK_SUCCESS) 383 | { 384 | throw std::runtime_error("Framebuffer creation failed"); 385 | } 386 | } 387 | 388 | VkCommandPoolCreateInfo poolInfo = {}; 389 | poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; 390 | poolInfo.queueFamilyIndex = queueFamilyId; 391 | poolInfo.flags = 0; 392 | 393 | vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool); 394 | 395 | if (result != VK_SUCCESS) 396 | { 397 | throw std::runtime_error("Command pool creation failed"); 398 | } 399 | 400 | VkCommandBufferAllocateInfo allocInfo = {}; 401 | allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 402 | allocInfo.commandPool = commandPool; 403 | allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 404 | allocInfo.commandBufferCount = numDrawCmdBuffers; 405 | 406 | result = vkAllocateCommandBuffers(device, &allocInfo, drawCommandBuffers); 407 | 408 | if (result != VK_SUCCESS) 409 | { 410 | throw std::runtime_error("Command buffer creation failed"); 411 | } 412 | 413 | SetupDynamicTransfer(device); 414 | } 415 | 416 | void Renderer::Destroy(VkDevice& device) 417 | { 418 | vkFreeCommandBuffers(device, commandPool, 1, &staticTransferCommandBuffer); 419 | vkFreeCommandBuffers(device, commandPool, 1, &dynamicTransferCommandBuffer); 420 | vkFreeCommandBuffers(device, commandPool, numDrawCmdBuffers, drawCommandBuffers); 421 | 422 | vkDestroyCommandPool(device, commandPool, nullptr); 423 | 424 | vkFreeMemory(device, vertexBufferMemory, nullptr); 425 | vkFreeMemory(device, vertexTransferBufferMemory, nullptr); 426 | 427 | vkDestroyBuffer(device, vertexBuffer, nullptr); 428 | vkDestroyBuffer(device, vertexTransferBuffer, nullptr); 429 | 430 | vkFreeMemory(device, indexBufferMemory, nullptr); 431 | vkFreeMemory(device, indexTransferBufferMemory, nullptr); 432 | 433 | vkDestroyBuffer(device, indexBuffer, nullptr); 434 | vkDestroyBuffer(device, indexTransferBuffer, nullptr); 435 | 436 | vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); 437 | vkDestroyDescriptorPool(device, descriptorPool, nullptr); 438 | 439 | vkDestroyBuffer(device, uniformTransferBuffer, nullptr); 440 | vkFreeMemory(device, uniformTransferBufferMemory, nullptr); 441 | vkDestroyBuffer(device, uniformBuffer, nullptr); 442 | vkFreeMemory(device, uniformBufferMemory, nullptr); 443 | 444 | for (uint32_t i = 0; i < numFBOs; ++i) 445 | { 446 | vkDestroyFramebuffer(device, framebuffers[i], nullptr); 447 | } 448 | 449 | vkDestroyPipeline(device, pipeline, nullptr); 450 | vkDestroyRenderPass(device, renderPass, nullptr); 451 | vkDestroyPipelineLayout(device, pipelineLayout, nullptr); 452 | vkDestroyShaderModule(device, vertexShaderModule, nullptr); 453 | vkDestroyShaderModule(device, fragmentShaderModule, nullptr); 454 | } 455 | 456 | void Renderer::ConstructFrames(const VkBuffer& heightBuffer, const VkBuffer& normalBuffer) 457 | { 458 | VkCommandBufferBeginInfo beginInfo = {}; 459 | beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 460 | beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; 461 | beginInfo.pInheritanceInfo = nullptr; 462 | 463 | VkClearValue clearColor = {0.0f, 0.0f, 0.0f, 1.0f}; 464 | 465 | VkRenderPassBeginInfo renderPassBeginInfo = {}; 466 | renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 467 | renderPassBeginInfo.renderPass = renderPass; 468 | 469 | renderPassBeginInfo.renderArea.offset = {0, 0}; 470 | renderPassBeginInfo.renderArea.extent = imageExtent; 471 | renderPassBeginInfo.clearValueCount = 1; 472 | renderPassBeginInfo.pClearValues = &clearColor; 473 | 474 | VkDeviceSize offsets[] = {0, 0, 0}; 475 | 476 | VkBuffer buffers[] = { vertexBuffer, heightBuffer, normalBuffer}; 477 | 478 | assert(numDrawCmdBuffers == numFBOs); 479 | 480 | for (uint32_t i = 0; i < numDrawCmdBuffers; ++i) 481 | { 482 | renderPassBeginInfo.framebuffer = framebuffers[i]; 483 | 484 | vkBeginCommandBuffer(drawCommandBuffers[i], &beginInfo); 485 | vkCmdBeginRenderPass(drawCommandBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); 486 | vkCmdBindDescriptorSets(drawCommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); 487 | vkCmdBindPipeline(drawCommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); 488 | vkCmdBindVertexBuffers(drawCommandBuffers[i], 0, numBindDesc, buffers, offsets); 489 | vkCmdBindIndexBuffer(drawCommandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT16); 490 | vkCmdDrawIndexed(drawCommandBuffers[i], numIndices, 1, 0, 0, 0); 491 | vkCmdEndRenderPass(drawCommandBuffers[i]); 492 | 493 | VkResult result = vkEndCommandBuffer(drawCommandBuffers[i]); 494 | 495 | if (result != VK_SUCCESS) 496 | { 497 | throw std::runtime_error("Command buffer end failed"); 498 | } 499 | } 500 | } 501 | 502 | void Renderer::SetupShaderParameters(VkDevice& device) 503 | { 504 | bindingDescriptions[0].binding = 0; 505 | bindingDescriptions[0].stride = sizeof(float[3]) * 2; 506 | bindingDescriptions[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; 507 | 508 | bindingDescriptions[1].binding = 1; 509 | bindingDescriptions[1].stride = sizeof(float); 510 | bindingDescriptions[1].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; 511 | 512 | bindingDescriptions[2].binding = 2; 513 | bindingDescriptions[2].stride = sizeof(float[4]); 514 | bindingDescriptions[2].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; 515 | 516 | attributeDescriptions[0].binding = 0; 517 | attributeDescriptions[0].location = 0; 518 | attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; 519 | attributeDescriptions[0].offset = 0; 520 | 521 | attributeDescriptions[1].binding = 0; 522 | attributeDescriptions[1].location = 1; 523 | attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; 524 | attributeDescriptions[1].offset = sizeof(float[3]); 525 | 526 | attributeDescriptions[2].binding = 1; 527 | attributeDescriptions[2].location = 2; 528 | attributeDescriptions[2].format = VK_FORMAT_R32_SFLOAT; 529 | attributeDescriptions[2].offset = 0; 530 | 531 | attributeDescriptions[3].binding = 2; 532 | attributeDescriptions[3].location = 3; 533 | attributeDescriptions[3].format = VK_FORMAT_R32G32B32_SFLOAT; 534 | attributeDescriptions[3].offset = 0; 535 | 536 | uboLayoutBinding.binding = 0; 537 | uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 538 | uboLayoutBinding.descriptorCount = 1; 539 | uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; 540 | //uboLayoutBinding.pImmutableSamplers = nullptr; 541 | 542 | VkDescriptorSetLayoutCreateInfo layoutInfo = {}; 543 | layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; 544 | layoutInfo.bindingCount = 1; 545 | layoutInfo.pBindings = &uboLayoutBinding; 546 | 547 | VkResult result = vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout); 548 | 549 | if (result != VK_SUCCESS) 550 | { 551 | throw std::runtime_error("Descriptor set layout creation failed"); 552 | } 553 | 554 | VkDescriptorPoolSize poolSize = {}; 555 | poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 556 | poolSize.descriptorCount = 1; 557 | 558 | VkDescriptorPoolCreateInfo poolInfo = {}; 559 | poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; 560 | poolInfo.poolSizeCount = 1; 561 | poolInfo.pPoolSizes = &poolSize; 562 | poolInfo.maxSets = 1; 563 | 564 | result = vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool); 565 | 566 | if (result != VK_SUCCESS) 567 | { 568 | throw std::runtime_error("Descriptor pool creation failed"); 569 | } 570 | 571 | VkDescriptorSetAllocateInfo allocInfo = {}; 572 | allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; 573 | allocInfo.descriptorPool = descriptorPool; 574 | allocInfo.descriptorSetCount = 1; 575 | allocInfo.pSetLayouts = &descriptorSetLayout; 576 | 577 | result = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet); 578 | 579 | if (result != VK_SUCCESS) 580 | { 581 | throw std::runtime_error("Descriptor set allocation failed"); 582 | } 583 | 584 | VkDescriptorBufferInfo bufferInfo = {}; 585 | bufferInfo.buffer = uniformBuffer; 586 | bufferInfo.offset = 0; 587 | bufferInfo.range = uboSize; 588 | 589 | VkWriteDescriptorSet descriptorWrite = {}; 590 | descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 591 | descriptorWrite.dstSet = descriptorSet; 592 | descriptorWrite.dstBinding = 0; 593 | descriptorWrite.dstArrayElement = 0; 594 | descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 595 | descriptorWrite.descriptorCount = 1; 596 | descriptorWrite.pBufferInfo = &bufferInfo; 597 | //descriptorWrite.pImageInfo = nullptr; 598 | //descriptorWrite.pTexelBufferView = nullptr; 599 | 600 | vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); 601 | } 602 | 603 | void Renderer::SetupServerSideVertexBuffer(VkDevice& device) 604 | { 605 | VkDeviceSize size = vertexInfoSize; 606 | 607 | VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 608 | VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; 609 | 610 | SetupBuffer(device, vertexTransferBuffer, vertexTransferBufferMemory, size, properties, usage); 611 | 612 | properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 613 | usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; 614 | 615 | SetupBuffer(device, vertexBuffer, vertexBufferMemory, size, properties, usage); 616 | 617 | void* data; 618 | vkMapMemory(device, vertexTransferBufferMemory, 0, size, 0, &data); 619 | memcpy(data, vertexInfo, (size_t) size); 620 | vkUnmapMemory(device, vertexTransferBufferMemory); 621 | } 622 | 623 | void Renderer::SetupDynamicTransfer(VkDevice& device) 624 | { 625 | VkCommandBufferAllocateInfo allocInfo = {}; 626 | allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 627 | allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 628 | allocInfo.commandPool = commandPool; 629 | allocInfo.commandBufferCount = 1; 630 | 631 | vkAllocateCommandBuffers(device, &allocInfo, &dynamicTransferCommandBuffer); 632 | 633 | VkCommandBufferBeginInfo beginInfo = {}; 634 | beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 635 | beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; 636 | 637 | vkBeginCommandBuffer(dynamicTransferCommandBuffer, &beginInfo); 638 | 639 | VkBufferCopy copyRegion = {}; 640 | copyRegion.size = uboSize; 641 | vkCmdCopyBuffer(dynamicTransferCommandBuffer, uniformTransferBuffer, uniformBuffer, 1, ©Region); 642 | 643 | copyRegion.size = vertexInfoSize; 644 | vkCmdCopyBuffer(dynamicTransferCommandBuffer, vertexTransferBuffer, vertexBuffer, 1, ©Region); 645 | 646 | vkEndCommandBuffer(dynamicTransferCommandBuffer); 647 | } 648 | 649 | VkCommandBuffer& Renderer::TransferStaticBuffers(VkDevice& device) 650 | { 651 | VkCommandBufferAllocateInfo allocInfo = {}; 652 | allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 653 | allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 654 | allocInfo.commandPool = commandPool; 655 | allocInfo.commandBufferCount = 1; 656 | 657 | vkAllocateCommandBuffers(device, &allocInfo, &staticTransferCommandBuffer); 658 | 659 | VkCommandBufferBeginInfo beginInfo = {}; 660 | beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 661 | beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; 662 | 663 | vkBeginCommandBuffer(staticTransferCommandBuffer, &beginInfo); 664 | 665 | VkBufferCopy copyRegion = {}; 666 | //copyRegion.srcOffset = 0; 667 | //copyRegion.dstOffset = 0; 668 | 669 | copyRegion.size = indicesBufferSize; 670 | vkCmdCopyBuffer(staticTransferCommandBuffer, indexTransferBuffer, indexBuffer, 1, ©Region); 671 | 672 | vkEndCommandBuffer(staticTransferCommandBuffer); 673 | 674 | return staticTransferCommandBuffer; 675 | } 676 | 677 | VkCommandBuffer& Renderer::TransferDynamicBuffers(VkDevice& device) 678 | { 679 | //static auto startTime = std::chrono::high_resolution_clock::now(); 680 | 681 | //auto currentTime = std::chrono::high_resolution_clock::now(); 682 | //float time = std::chrono::duration_cast(currentTime - startTime).count() / 1000.0f; 683 | 684 | glm::mat4 model; //= glm::rotate(glm::mat4(), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f)); 685 | glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 6.0f, 10.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); 686 | glm::mat4 proj = glm::perspective(glm::radians(90.0f), imageExtent.width / (float) imageExtent.height, 0.1f, 100.0f); 687 | proj[1][1] *= -1; 688 | 689 | float lightPos[] = { 10.0, 10.0, 0.0 }; 690 | 691 | VkDeviceSize size = uboSize; 692 | 693 | void* data; 694 | vkMapMemory(device, uniformTransferBufferMemory, 0, size, 0, &data); 695 | 696 | char* bytes = static_cast(data); 697 | 698 | memcpy(bytes, glm::value_ptr(model), (size_t) mat4Size); 699 | bytes += mat4Size; 700 | memcpy(bytes, glm::value_ptr(view), (size_t) mat4Size); 701 | bytes += mat4Size; 702 | memcpy(bytes, glm::value_ptr(proj), (size_t) mat4Size); 703 | bytes += mat4Size; 704 | memcpy(bytes, lightPos, sizeof(float[3])); 705 | 706 | vkUnmapMemory(device, uniformTransferBufferMemory); 707 | 708 | return dynamicTransferCommandBuffer; 709 | } 710 | 711 | void Renderer::SetupIndexBuffer(VkDevice& device) 712 | { 713 | VkDeviceSize size = indicesBufferSize; 714 | 715 | VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 716 | VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; 717 | 718 | SetupBuffer(device, indexTransferBuffer, indexTransferBufferMemory, size, properties, usage); 719 | 720 | properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 721 | usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; 722 | 723 | SetupBuffer(device, indexBuffer, indexBufferMemory, size, properties, usage); 724 | 725 | void* data; 726 | vkMapMemory(device, indexTransferBufferMemory, 0, size, 0, &data); 727 | memcpy(data, indices, (size_t) size); 728 | vkUnmapMemory(device, indexTransferBufferMemory); 729 | } 730 | 731 | void Renderer::SetupUniformBuffer(VkDevice &device) 732 | { 733 | VkDeviceSize size = uboSize; 734 | 735 | VkMemoryPropertyFlags properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 736 | VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; 737 | 738 | SetupBuffer(device, uniformTransferBuffer, uniformTransferBufferMemory, size, properties, usage); 739 | 740 | properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 741 | usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; 742 | 743 | SetupBuffer(device, uniformBuffer, uniformBufferMemory, size, properties, usage); 744 | } 745 | 746 | }; 747 | --------------------------------------------------------------------------------