├── CMakeLists.txt ├── LICENSE ├── README.md ├── Windows_Build.bat ├── main.c ├── shader.frag └── shader.vert /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(vulkan) 4 | 5 | set(CMAKE_C_STANDARD 17) 6 | set(CMAKE_C_STANDARD_REQUIRED ON) 7 | 8 | add_executable(vulkan-triangle 9 | main.c) 10 | 11 | if(UNIX AND NOT APPLE) 12 | #[[ 13 | Build for linux, basically you don't need to do anything, 14 | but if you ONLY BUILD glfw or vulkanSDK 15 | without install it into '/usr' directory, you should 16 | 17 | 1. add extra 'target_include_directories' option 18 | 2. modify the 'target_link_libraries' option 19 | 20 | based on your build directories 21 | ]] 22 | target_link_libraries(vulkan-triangle 23 | /usr/lib/libvulkan.so 24 | /usr/lib/libglfw.so) 25 | elseif(WIN32) 26 | #[[ 27 | Build for windows, PLEASE USE MinGW, 28 | DO NOT USE visual c++ beacuse it doesn't fully support c99 29 | especially 'Variable Length Array' feature 30 | 31 | Before build, you should 32 | 33 | 1. modify the 'target_include_directories' option 34 | if it's different from the path provided below. 35 | 36 | 2. modify the 'target_link_libraries' option 37 | if it's different from the library file provided below. 38 | 39 | based on your install directories 40 | ]] 41 | target_include_directories(vulkan-triangle PRIVATE 42 | C:/VulkanSDK/1.2.176.1/Include 43 | C:/glfw/include) 44 | 45 | target_link_libraries(vulkan-triangle 46 | C:/VulkanSDK/1.2.176.1/Lib/vulkan-1.lib 47 | C:/glfw/lib-mingw-w64/libglfw3dll.a) 48 | 49 | target_link_options(vulkan-triangle PRIVATE 50 | -mwindows) 51 | endif() 52 | 53 | add_custom_target(vert.spv 54 | COMMAND glslangValidator --quiet -V ${CMAKE_SOURCE_DIR}/shader.vert -o ${CMAKE_BINARY_DIR}/vert.spv) 55 | 56 | add_custom_target(frag.spv 57 | COMMAND glslangValidator --quiet -V ${CMAKE_SOURCE_DIR}/shader.frag -o ${CMAKE_BINARY_DIR}/frag.spv) 58 | 59 | if(UNIX AND NOT APPLE) 60 | add_dependencies(vulkan-triangle 61 | vert.spv 62 | frag.spv) 63 | elseif(WIN32) 64 | #[[ 65 | Windows need glfw3.dll to run this program, 66 | modify the path to source dll to your own path 67 | ]] 68 | add_custom_target(glfw3.dll 69 | COMMAND ${CMAKE_COMMAND} -E copy C:/glfw/lib-mingw-w64/glfw3.dll ${CMAKE_BINARY_DIR}/) 70 | 71 | add_dependencies(vulkan-triangle 72 | vert.spv 73 | frag.spv 74 | glfw3.dll) 75 | endif() 76 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 lonelydevil 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NOTE!!! 2 | 3 | This project has been archived, a improved version is [**here**][VK_BETTER] 4 | 5 | # About this project 6 | 7 | This is the C-implementation code of vulkan triangle based on [**vulkan-tutorial.com**][VK_TUT] 8 | 9 | # Why use C instead of C++? 10 | 11 | Because some newcomers don't know C++ or STL. Implement the code with C will help them have a better understanding with the tutorial. 12 | 13 | # How many chapters this code had actually implemented? 14 | 15 | From [**chapter 1**][TUT_START] to [**chapter 16**][TUT_END], you can view comments from the source code to see how they're implemented. 16 | 17 | # How to build it? 18 | 19 | You shouldn't stick to the [**Original Tutorial**][TUT_BUILD] because this code contains VLA(Variable Length Array) features, which is not supported in C++, especially Visual C++. 20 | 21 | **FOR WINDOWS USERS** 22 | 23 | You need to install [**VulkanSDK**][WIN_VKSDK], [**MinGW**][WIN_GCC](GNU C/C++ Compiler for Windows), [**CMake**][WIN_CMAKE]. Then download and extract [**GLFW prebuild library for windows**][WIN_GLFW_LIB] (and move it under C:/ if possible). 24 | 25 | Now fetch this source code through [**Git**][GIT] or Direct-Download. 26 | 27 | Then you should read through [**CMakeLists.txt**][BUILD_FILE] and modify the path to suit your needs. 28 | 29 | Then open the project folder press **Shift + Right Click** and select **open in terminal**, Type the following command(change argument with <> to what you want): 30 | 31 | ``` 32 | 33 | cmake -G "MinGW Makefiles" -B 34 | 35 | cmake --build --target all -j 36 | 37 | ``` 38 | 39 | If you don't like typing command line, **Double Click 'Windows_Build.bat'** and it will automatically build inside a subdirectory named **'build'**. 40 | 41 | **FOR LINUX USERS** 42 | 43 | You need to install a **Desktop Environment**, **vulkan driver for your GPU**, **gcc**, **glslang**, **cmake** and **glfw**, they should be included inside your package manager if you're using popular distro. If not, fetch their source code, build and install them manually. 44 | 45 | Now fetch this source code through [**Git**][GIT] or Direct-Download. 46 | 47 | Then read through [**CMakeLists.txt**][BUILD_FILE], confirm that the path was absolutely correct. 48 | 49 | Then open the terminal by pressing **Ctrl + Alt + T** to open the terminal(If your Desktop Environment doesn't support this shortcut, open it manually through application launcher), Type the following command: 50 | 51 | ``` 52 | 53 | cd 54 | 55 | cmake -B 56 | 57 | cmake --build --target all -j 58 | 59 | ``` 60 | 61 | # Where is the program after the build steps? 62 | 63 | Open file manager(or use **cd** if you like typing command) and open your build folder, double click the program named 'vulkan-triangle', a colorful triangle with purple background will pop up. 64 | 65 | # How to change the color of The Background or The Triangle ? 66 | 67 | **BACKGROUND COLOR**: 68 | 69 | Search "VkClearValue" in [**main.c**][CODE_MAIN], the four-floating-number-array after clear_val is the background color, represents "R", "G", "B" and "A", curretly only RGB value has effect. 70 | 71 | **TRIANGLE COLOR**: 72 | 73 | Search "vec3 colors" in [**shader.vert**][CODE_VERT], there are three three-floating-number-array after that. It's the RGB value of three vertex colors of the triangle. 74 | 75 | 76 | [VK_BETTER]: https://github.com/lonelydevil/Vulkan-Triangle 77 | [VK_TUT]: https://vulkan-tutorial.com/ 78 | [TUT_START]: https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Base_code 79 | [TUT_END]: https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentation 80 | [TUT_BUILD]: https://vulkan-tutorial.com/Development_environment 81 | [WIN_VKSDK]: https://vulkan.lunarg.com/sdk/home#windows 82 | [WIN_GCC]: http://mingw-w64.org/doku.php/download/mingw-builds 83 | [WIN_CMAKE]: https://cmake.org/download/ 84 | [WIN_GLFW_LIB]: https://www.glfw.org/download.html 85 | [GIT]: https://git-scm.com/downloads 86 | [BUILD_FILE]: https://github.com/lonelydevil/vulkan-tutorial-C-implementation/blob/main/CMakeLists.txt 87 | [CODE_MAIN]: https://github.com/lonelydevil/vulkan-tutorial-C-implementation/blob/main/main.c 88 | [CODE_VERT]: https://github.com/lonelydevil/vulkan-tutorial-C-implementation/blob/main/shader.vert 89 | -------------------------------------------------------------------------------- /Windows_Build.bat: -------------------------------------------------------------------------------- 1 | cmake -G "MinGW Makefiles" -B build 2 | cmake --build .\build\ --target all -j16 -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include"stdio.h" 2 | #include"stdlib.h" 3 | #include"string.h" 4 | #include"limits.h" 5 | #include"time.h" 6 | 7 | #include"vulkan/vulkan.h" 8 | #include"GLFW/glfw3.h" 9 | #define GLFW_INCLUDE_VULKAN 10 | 11 | int main(int argc,char **argv){ 12 | glfwInit(); 13 | // 14 | // 15 | //instance creation part line_15 to line_69 16 | // 17 | //create application info 18 | // 19 | VkApplicationInfo app_info; 20 | 21 | app_info.sType=VK_STRUCTURE_TYPE_APPLICATION_INFO; 22 | app_info.pNext=NULL; 23 | char app_name[VK_MAX_EXTENSION_NAME_SIZE]; 24 | strcpy(app_name,"vulkan_project"); 25 | app_info.pApplicationName=app_name; 26 | app_info.applicationVersion=VK_MAKE_VERSION(0,0,1); 27 | char app_engine_name[VK_MAX_EXTENSION_NAME_SIZE]; 28 | strcpy(app_engine_name,"vulkan_engine"); 29 | app_info.pEngineName=app_engine_name; 30 | app_info.engineVersion=VK_MAKE_VERSION(0,0,1); 31 | app_info.apiVersion=VK_API_VERSION_1_0; 32 | // 33 | //create instance create info 34 | // 35 | VkInstanceCreateInfo inst_cre_info; 36 | 37 | inst_cre_info.sType=VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 38 | inst_cre_info.pNext=NULL; 39 | inst_cre_info.flags=0; 40 | inst_cre_info.pApplicationInfo=&app_info; 41 | uint32_t inst_layer_count=1; 42 | inst_cre_info.enabledLayerCount= 43 | inst_layer_count; 44 | char pp_inst_layers[inst_layer_count] 45 | [VK_MAX_EXTENSION_NAME_SIZE]; 46 | strcpy(pp_inst_layers[0],"VK_LAYER_KHRONOS_validation"); 47 | char *pp_inst_layer_names[inst_layer_count]; 48 | for(uint32_t i=0;imax_mem_size){ 129 | phy_devi_best_index=discrete_gpu_list[i]; 130 | max_mem_size=phy_devis_mem_total[i]; 131 | } 132 | } 133 | }else if(intergrated_gpu_count!=0){ 134 | for(uint32_t i=0;imax_mem_size){ 136 | phy_devi_best_index=intergrated_gpu_list[i]; 137 | max_mem_size=phy_devis_mem_total[i]; 138 | } 139 | } 140 | } 141 | 142 | printf("best device index:%u\n",phy_devi_best_index); 143 | printf("device name:%s\n",phy_devis_props 144 | [phy_devi_best_index].deviceName); 145 | printf("device type:"); 146 | if(discrete_gpu_count!=0){ 147 | printf("discrete gpu\n"); 148 | }else if(intergrated_gpu_count!=0){ 149 | printf("intergrated gpu\n"); 150 | }else{ 151 | printf("unknown\n"); 152 | } 153 | printf("memory total:%llu\n",phy_devis_mem_total[ 154 | phy_devi_best_index 155 | ]); 156 | VkPhysicalDevice *phy_best_devi= 157 | &(phy_devis[phy_devi_best_index]); 158 | // 159 | //query queue families 160 | // 161 | uint32_t qf_prop_count=0; 162 | vkGetPhysicalDeviceQueueFamilyProperties 163 | (*phy_best_devi,&qf_prop_count,NULL); 164 | VkQueueFamilyProperties 165 | qf_props[qf_prop_count]; 166 | vkGetPhysicalDeviceQueueFamilyProperties 167 | (*phy_best_devi,&qf_prop_count,qf_props); 168 | 169 | uint32_t qf_q_count[qf_prop_count]; 170 | for(uint32_t i=0;imax_q_count){ 239 | qf_best_index=qf_graph_list[i]; 240 | } 241 | } 242 | printf("best queue family index:%d\n", 243 | qf_best_index); 244 | 245 | VkQueue q_graph,q_pres; 246 | vkGetDeviceQueue 247 | (dev,qf_best_index,0,&q_graph); 248 | char single_queue=1; 249 | if(qf_props[qf_best_index] 250 | .queueCount<2){ 251 | vkGetDeviceQueue 252 | (dev,qf_best_index,0,&q_pres); 253 | printf("using single queue for drawing.\n"); 254 | }else{ 255 | single_queue=0; 256 | vkGetDeviceQueue 257 | (dev,qf_best_index,1,&q_pres); 258 | printf("using double queues for drawing.\n"); 259 | } 260 | // 261 | // 262 | //window and surface creation part line_262 to line_276 263 | // 264 | //create window and surface 265 | // 266 | glfwWindowHint(GLFW_CLIENT_API,GLFW_NO_API); 267 | glfwWindowHint(GLFW_RESIZABLE,GLFW_FALSE); 268 | GLFWwindow *window= 269 | glfwCreateWindow(600,600,"",NULL,NULL); 270 | printf("window created.\n"); 271 | VkSurfaceKHR surf; 272 | glfwCreateWindowSurface 273 | (inst,window,NULL,&surf); 274 | printf("surface created.\n"); 275 | // 276 | // 277 | //swapchain and image view creation part line_277 to line_476 278 | // 279 | //verify surface support 280 | // 281 | VkBool32 phy_surf_supported; 282 | vkGetPhysicalDeviceSurfaceSupportKHR 283 | (*phy_best_devi,qf_best_index, 284 | surf,&phy_surf_supported); 285 | if(phy_surf_supported==VK_TRUE){ 286 | printf("surface supported.\n"); 287 | }else{ 288 | printf("warning:surface unsupported!\n"); 289 | } 290 | // 291 | //fetch surface capabilities 292 | // 293 | VkSurfaceCapabilitiesKHR surf_caps; 294 | vkGetPhysicalDeviceSurfaceCapabilitiesKHR 295 | (*phy_best_devi,surf,&surf_caps); 296 | printf("fetched caps from surface.\n"); 297 | char extent_suitable=1; 298 | int wind_w,wind_h; 299 | glfwGetFramebufferSize(window,&wind_w,&wind_h); 300 | VkExtent2D actual_extent; 301 | actual_extent.width=wind_w; 302 | actual_extent.height=wind_h; 303 | if(surf_caps.currentExtent.width 304 | !=wind_w 305 | ||surf_caps.currentExtent.height 306 | !=wind_h){ 307 | extent_suitable=0; 308 | printf("actual extent size doesn't match framebuffers, resizing...\n"); 309 | actual_extent.width= 310 | wind_w>surf_caps 311 | .maxImageExtent.width? 312 | surf_caps 313 | .maxImageExtent.width 314 | :wind_w; 315 | actual_extent.width= 316 | wind_wsurf_caps 323 | .maxImageExtent.height? 324 | surf_caps 325 | .maxImageExtent.height 326 | :wind_h; 327 | actual_extent.height= 328 | wind_h