├── 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 | 
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 |
--------------------------------------------------------------------------------