svg1

Chapter 0: Prerequisites 📹

📖 Suggested Reading (before embarking on this journey)

  1. Brendan Galea's Vulkan C++ [Youtube Series]

  2. Alternatively:- https://paminerva.github.io/docs/LearnVulkan/01.A-Hello-Window

  3. Alternatively:- you can give this page a try too:-

🙋🏻‍♀️ The 5 Questions


Page-Break

1. 🫳 grab vulkan-sdk, cmake, amGHOST

  1. if you don't have vscode & C++ Compiler

  2. 📥 https://vulkan.lunarg.com/sdk/home

    • make sure VULKAN_SDK & VK_SDK_PATH environment variables are set
    • restart vscode after installing

  3. 📥 https://cmake.org/download/

    • 🎓 Intro/Tutorials

    • restart vscode after installing

    • 📜 REY_DOCs
      • This is how it usually looks. Read through it 💁‍♀️.
      • The app that we will make using amGHOST, will need to have these commands
      cmake_minimum_required(VERSION 3.25 FATAL_ERROR)
      
      project("idk_PROJECT" VERSION 0.1)
      
          set(CMAKE_CXX_STANDARD 23)
          set(CMAKE_CXX_STANDARD_REQUIRED ON)
      
      # --------------------
          set(SRC
              "main.cpp"
          )
      
          set(INC
              ${CMAKE_CURRENT_SOURCE_DIR}
          )
      # --------------------
      
      # --------------------
      # set_source_files_properties(main.cpp PROPERTIES COMPILE_FLAGS "/P /C")     
      # Output Preprocessed File
                  add_executable (idk ${SRC})
      target_include_directories (idk PUBLIC ${INC})
      
      # ------amGHOST-------
               add_subdirectory  (amGHOST)
          target_link_libraries  (idk PUBLIC amGHOST)
      
      # ------install-------
          install(TARGETS idk
              DESTINATION ${CMAKE_CURRENT_SOURCE_DIR})
      

  4. amGHOST

    • amateur's Generic Handy Operating System Toolkit
      • [secretly inspired by blender's GHOST xP 😜]
    • git clone -b win32-intro https://github.com/REYNEP/amGHOST
    • Open it with VSCode
    • F1 --> CMake: Configure
    • F1 --> CMake: Build
    • F1 --> CMake: Install --> .insall dir
    • check's amGHOST's Usage Example inside amGHOST/README.md
      • Option 1:- use cmake for your project too.... using add_subdirectory(amGHOST)
      • Option 2:- use libamGHOST.lib after installing & #include amGHOST/<header>
    • just copy paste amGHOST's Usage Example into a main.cpp for your program
      #include "amGHOST/amGHOST_System.hh"
      
      int main(int argumentCount, char* argumentVector[]) 
      {
          amGHOST_System::create_system();    // initializes amG_HEART
          
          amGHOST_Window* W = amG_HEART->new_window_interface();
          W->create(L"Whatever", 0, 0, 500, 600);
      
          REY::cin.get();     // wait for terminal input
          W->destroy();
      }
      
      • [shorter than readme ex. 1]
      • now you shall have a OS-Window 😊



  5. Viewing these readmes in a Nice Way





Chapter 1: VkInstance

0. amVK wrap 🌯

    #include "amVK_Instance.hh"
        // TwT
    amVK_Instance::AppInfo              // VkApplicationInfo        [public]
    amVK_Instance::CI                   // VkInstanceCreateInfo     [public]
        // You can modify these as you wish 😊
    amVK_Instance::CreateInstance();    // initializes amVK_HEART

1. Notes on Notes

img2

















Page-Break



2. 🛠️ VkApplicationInfo

3. 🛠️ VkInstanceCreateInfo


Page-Break




4. A 😎 Cool vscode / visual-studio extension if you want 💁‍♀️


5. 🏷️ VkInstance m_instance = nullptr;

6. 📦 vkCreateInstance(CI, nullptr, &m_instance)


7. 🚨 Error Handling / Checking / 🪵 Logging

8. 📽️ So far, The result :- 4.guide.chapter1.hh


9. The Unused ones

  1. vkEnumerateInstanceExtensionProperties() --> 🟨 Chapter4.2
  2. Add_InstanceEXT_ToEnable(const char* extName) --> 🟨 Chapter4.2
    • this is a amVK/REY Custom Function




Chapter 2: VkDevice

img1
Take a look into this awesome slide from slide-26 onwards
...to understand what each of these steps above "feel like"/mean/"how to imagine them".
*slide = Vulkanised 2023 Tutorial Part 1




0. amVK wrap 🌯

    #include "amVK_Instance.hh"
    #include "amVK_DeviceQueues.hh"
    #include "amVK_Device.hh"

        // TwT
        REY_LOG("");
    amVK_Instance::EnumeratePhysicalDevices();
    amVK_GPUProps  *GPUProps = amVK_InstanceProps::GetARandom_GPU();
                    GPUProps->GetPhysicalDeviceQueueFamilyProperties();
                    GPUProps->REY_CategorizeQueueFamilies();

    amVK_Device* D = new amVK_Device(GPUProps);
        D->CI                           // VkDeviceCreateInfo       [public]
        D->Queues                       // amVK_DeviceQueues        [public] [take a look inside 😜]
        D->add_1D_QFAMs_QCount_USER()   // amVK_DeviceQueues
        D->CreateDevice(1);             // param1 = GraphicsQueueCount = 
        D->GetDeviceQueues();           //     see:- Queues.TheArrays 😜
        D->Queues.GraphicsQ(0)          // returns   Queues.TheArrays.Graphics[0]

Page-Break

1. 📦 vkCreateDevice()

image4

2. 🛠️ VkDeviceCreateInfo


Page-Break


3. 📜 vkEnumeratePhysicalDevices()

4. 🧊 amVK_InstanceProps::GetARandom_GPU()

</> TheCode 🔗 GITHUB amVK_InstanceProps.hh#L39


5. 🛠️ VkDeviceQueueCreateInfo - 'The Real Deal'




Page-Break



6. 📜 vkGetPhysicalDeviceQueueFamilyProperties()



Page-Break

7. 🏷️ VkQueueFamilyProperties

8. VkDeviceQCI.queueFamilyIndex [OldWay]

9. 🧊 REY_CategorizeQueueFamilies() [NewWay]

</> TheCode 🔗 GITHUB
amVK_GPUProps.hh#L50
amVK_GPUProps.cpp#L260


Page-Break














10. back to 📦 vkCreateDevice() finally calling it 😊

11. 🧊 amVK_DeviceQueues

🔗 amVK_DeviceQueues.hh


Page-Break





🟪 eXtras / TheEnd

11. multiple VkDeviceCreateInfo.pQueueCreateInfos

  1. OldWay 📆 March, 2025

    1. class amVK_InstanceProps
      • EnumeratePhysicalDevices()
      • GetPhysicalDeviceQueueFamilyProperties()
  2. NewWay 📆 May, 2025

  3. vkGetPhysicalDeviceProperties() 🟨 Chapter11

  4. GetFeatures 🟨 Chapter11

  5. MemoryTypes 🟨 Chapter11

  6. Guide on amVK_Array 🟨 Chapter6.6





Chapter 3: Common Patterns: if someone missed to catch it yet 😉

Object  Vk      VkInstance
Types   Vk      VkInstanceCreateInfo
Funcs   vk      vkCreateInstance()
Enums   VK_     VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO

Extensions
    KHR:- Khronos authored,
    EXT:- multi-company authored

Creating "VkZZZ" object
    1. take `VkZZZCreateInfo` --> fill it up
    2. call `vkCreateZZZ()`
    3. also `vkDestroyZZZ()` before closing your app

    4. Some objects get "allocated" rather than "created"
        `VkZZZAllocateInfo` --> `vkAllocateZZZ` --> `vkFreeZZZ`

    5. Sometimes there will be `.zzzCreateInfoCount` & `.pZZZCreateInfos`
                        e.g. `.queueCreateInfoCount` & `.pQueueCreateInfos``
            -> So you could like pass in an array/vector
            -> You will see this in lots of other places

Getting List/Properties
    6. vkEnumerateZZZ() --> \see `[Chapter2.1.] vkEnumeratePhysicalDevices()` example

-- | -- | -- | ----------------------------------------------------------------------------

  1. 🟪 almost every VkStruct is gonna have these 3 field/member 💁‍♀️

    1. sType:-
      • It may seem somewhat redundant, but this information can be useful for the vulkan-loader and actual gpu-driver-implementations to know what type of structure was passed in through pNext.
    2. pNext:-
      • allows to create a linked list between structures.
      • It is mostly used when dealing with extensions that expose new structures to provide additional information to the vulkan-loader, debugging-validation-layers, and gpu-driver-implementations.
        • i.e. they can use the pNext->stype field to know what's ahead in the linked list
    3. .flags:-
      • this one goes mostly ignored / set to 0

  2. .pQueueCreateInfos:- yes, you 'can' pass multiple 😉

    • Sometimes there will be .zzzCreateInfoCount & .pZZZCreateInfos
      • So you could like pass in an array/vector
      • You will see this in lots of other places

-- | -- | -- | ----------------------------------------------------------------------------

  1. CreateInfo StartingPoint
    VkRenderPassCreateInfo CI = {
        .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
        .pNext = nullptr,
        .flags = 0
    };
    
10.  Do remember to check the `Valid Usage` section within each manual-page
  1. Getting/Enumerating VkObject list 💁‍♀️
    uint32_t deviceCount = 0;     
        // [implicit valid usage]:- must be 0 [if 3rd-param = nullptr]
        vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr);
            // it's kinda like the function is 'output-ing into' deviceCount
    
    std::vector<VkPhysicalDevice> HardwareGPU_List(gpuCount);
        // best to save this as a class member variable
        vkEnumeratePhysicalDevices(m_instance, &deviceCount, HardwareGPU_List.data());
            // note: it does return     VkResult return_code
    

-- | -- | -- | ----------------------------------------------------------------------------

  1. Symbols:-
    • 🟪:- kinda means nothing

      • i kinda used to like make it look like a bit pattern-ish iguess 🥴🫢

      • 🟪💁‍♀️: "Pretty Obvious"
    • 🟨:- "Yellow Card"

      • it means, you don't need to hesitate about this thingy right now 💁‍♀️ we will focus on this element later 🤭
      1. ChapterZZZ => Unknown WIP/TBD Chapter
      2. Chapter2.4 => 
          If LATER-CHAPTER => Dont hesitate right now, Do this when you each that LATER-Chapter
          If  PREV-CHAPTER => You can go back and check 😛
              🔗 `SurfCAP.currentTransform`
              🔗 Chapter2.4
      
    • 🟧:- "Orange Card"

      • it means, this element is probably never gonna be 'necessary' for vulkan applications 💁‍♀️

    • 🪐: "Extensions"

      • Same as 🟨 "Yellow Card". But marks a little bit more, that, "Here goes Extension" Features

    • 🔠: "Options"

      • Sometimes you'd "Must Need" to choose between a few options

    • 🏳️: "I Lose, You Win!" / General Flag Icon / Sometimes means -> "Lots of Flags" / IDK / Didn't check [IDC]

    • 🎌: "Nice/Important Flags"

    • 🚩: "One Flag" [IDC]

    • 🏴: "No Flag" [IDC]

    • ⚠️: "Deprecated Feature" / "Other Kinds of Warnings" / I will try to name when using this emoji/sign

    • 🏷️: "Type"

    • 🟨 ChapterZZZ

    • 🔗 Chapter2.1

    • 🔗 GITHUB_WIP

    • 📋🔄 Chapter2.1

      • vkEnumeratePhysicalDevices()
      • it means, Implement Exactly like in Chapter2.1 😉

    • ℹ️: "Create Info"

    • 🌯: amVK_Wrap

    • ↩️📦: "Object Getting return by Vulkan Function"

    • 📜 REY_DOCs

      • Actual Notes
      • Mostly, vkdoc.net documentation is good enough. But if I wanna add smth extra, it goes here
      • This section might get big & robust sometimes 🤭
    • </> TheCode

    • 📽️ So far, The result

      • 📝:- "File Icon"
    • 👀 Visualization / [See it] / JSON Printing

    • 🔬🛠️ 2DriverIMPL

      • To The People Who are gonna Implement the Driver
      • Other Keyword:- "DriverGurantee"

-- | -- | -- | ----------------------------------------------------------------------------

  1. Emojis List
    • 🟪 🟨 🟧 🪐 🔠 ➡️ 🏷️ 📝 ℹ️ 📥 🌋 🧊
    • 🟪💁‍♀️
    • ↩️📦
    • 🔗 SubChapter 2
    • 🔗 Next SubChapter
    • 🔗 Chapter2.1
    • 🟨 ChapterZZZ
    • 📋🔄 Chapter2.1
    • 🔗 GITHUB_WIP
    • ↩️ Return Codes
    • 📜 REY_DOCs
    • </> TheCode
    • </> main.cpp
    • 📽️ So far, The result
    • 🔬🛠️ 2DriverIMPL
    • 👀 Visualization / [See it] / JSON Printing
  2. Templates Below
  3. Extra Emojis

    📟📇
    🎚️🎌🏳️
    🔌🚀
    🚫📜
    ⚠️🧓
    ☢️🧨
    ☢️💀
    ⚠️🏚️

  4. Number BLocks

    1️⃣
    2️⃣
    3️⃣
    4️⃣
    5️⃣
    6️⃣
    7️⃣
    8️⃣
    9️⃣
    🔟
    1️⃣1️⃣
    1️⃣2️⃣
    1️⃣3️⃣
    1️⃣4️⃣
    1️⃣5️⃣
    1️⃣6️⃣
    1️⃣7️⃣
    1️⃣8️⃣
    1️⃣9️⃣
    2️⃣0️⃣

  5. Possible Function Naming Verbs-Emojis
    1. query_SurfCap 🕵️♂️
    2. update_SurfCap 🔄
    3. load_SurfCap 📥
    4. acquire_SurfCap 🔗
    5. get_SurfCap 📤
    6. grab_SurfCap	👐
    7. snag_SurfCap	🎣 (Quick pull)
    8. pluck_SurfCap	✂️ (Precision)
    9. selected_gpu_surfCap	🎯 (Targeted)	Emphasizes the GPU_Index selection.
    10. current_surfCap	⏳ (Stateful)
    11. yoink_SurfCap	🦄 (Playful)	VkSurfaceCapabilitiesKHR* cap = yoink_SurfCap();
    12. procure_SurfCap	🕴️ (Formal)	procure_SurfCap() → Sounds like a business transaction!
    13. obtain_SurfCap	🏆 (Success)
    14. collect_SurfCap	📚 (Gathering)
    15. retrieve_SurfCap	🎯 (Accuracy)
    16. sync_SurfCap	🔄 (Sync State)
    17. pull_SurfCap	🪢 (Tug-of-war)
    18. refresh_SurfCap	💫 (Update)
    19. reload_SurfCap	♻️ (Reload)
    20. populate_SurfCap	🌱 (Fill Data)
    21. enumerate_SurfCap	📇 (Listing)
    22. summon_SurfCap	🧙♂️ (Magic)
    23. harvest_SurfCap	🌾 (Farm)
    24. fish_SurfCap	🎣 (Fishing)
    25. dial in	🎛️ (Precision)
    26. shape up	🌟 (Polishing)
    27. rig	🛠️ (Hacky)
    28. tailor	👗 (Custom-fit)
    29. access_SurfCap 🔍
    30. craft	🧙♂️ (Artisan)
    31. surfCap 📋 (property-style)
    32. surfCap_ptr 🎯 (or surfCapRef)
    
  6. Extra Emojis
    #!/usr/bin/env python3
    # 🎮 Ultimate Vulkan Emoji Guide (1-35)
    
    vulkan_steps = [
        # Core Setup (Original 1-5)
        "1. 🌍 Instance Creation",
        "2. 🖥️ Physical Device Selection",
        "3. ⚙️ Logical Device Setup",
        "4. 🎨 Graphics Pipeline",
        "5. 🖼️ SwapChain Initialization",
    
        # Resource Management (Original 6-10)
        "6. 🗄️ Buffer Allocation",
        "7. 🧠 Memory Binding",
        "8. 🖌️ Descriptor Sets",
        "9. 📦 Image Creation",
        "10. 🎮 Command Pools",
    
        # Execution Flow (Original 11-12)
        "11. 📜 Command Buffers",
        "12. ⏱️ Synchronization",
    
        # Debugging (Original 13-14)
        "13. 🔍 Validation Layers",
        "14. 🐛 Debug Messenger",
    
        # Advanced Features (Original 15-17)
        "15. 🌌 Ray Tracing",
        "16. 🤖 Compute Pipeline",
        "17. 🧵 Multi-Threading",
    
        # Cleanup (Original 18-20)
        "18. 🧹 Resource Destruction",
        "19. 💥 Device Cleanup",
        "20. 🚀 Instance Shutdown",
    
        # New Additions (21-35)
        "21. 🧊 Device Memory",
        "22. 🔄 Memory Barriers",
        "23. 📊 Buffer Views",
        "24. 🎛️ Pipeline Layout",
        "25. 🔮 Shader Modules",
        "26. 🧩 Pipeline Cache",
        "27. 🎆 Render Passes",
        "28. 🖌️ Dynamic Rendering",
        "29. 🌐 Multi-View Rendering",
        "30. ⏳ Timeline Semaphores",
        "31. 🚦 Fences",
        "32. 📡 Debug Markers",
        "33. 📈 Performance Queries",
        "34. 🌀 Compute Dispatches",
        "35. 🚀 Acceleration Structures"
    ]
    
    #!/usr/bin/env python3
    # 🏆 Ultimate Vulkan Emoji Cheatsheet (50+ Concepts)
    
    vulkan_concepts = {
        # === Core Setup ===
        "🌍": "Instance Creation (vkCreateInstance)",
        "🖥️": "Physical Device Selection (vkEnumeratePhysicalDevices)",
        "⚙️": "Logical Device (vkCreateDevice)",
        "📜": "Extensions/Layers (ppEnabledExtensionNames)",
        
        # === Resources ===
        "🗄️": "Buffers (vkCreateBuffer)",
        "🧊": "Device Memory (vkAllocateMemory)",
        "📦": "Images (vkCreateImage)",
        "🔄": "Memory Barriers (vkCmdPipelineBarrier)",
        "🧶": "Image Views (vkCreateImageView)",
        "🧩": "Sparse Resources (VkSparseImageMemoryBind)",
        
        # === Pipeline ===
        "🎨": "Graphics Pipeline (vkCreateGraphicsPipelines)",
        "🤖": "Compute Pipeline (vkCreateComputePipelines)",
        "🔮": "Shader Modules (vkCreateShaderModule)",
        "🎛️": "Pipeline Layout (vkCreatePipelineLayout)",
        "🧪": "Pipeline Cache (vkCreatePipelineCache)",
        
        # === Descriptors ===
        "🖌️": "Descriptor Sets (vkAllocateDescriptorSets)",
        "📇": "Descriptor Pool (vkCreateDescriptorPool)",
        "📊": "Descriptor Set Layout (vkCreateDescriptorSetLayout)",
        
        # === Rendering ===
        "🎆": "Render Passes (vkCreateRenderPass)",
        "🖼️": "Framebuffers (vkCreateFramebuffer)",
        "🎚️": "Dynamic Rendering (VK_KHR_dynamic_rendering)",
        "👁️": "Multi-View (VK_KHR_multiview)",
        
        # === Commands ===
        "🎮": "Command Pools (vkCreateCommandPool)",
        "📜": "Command Buffers (vkAllocateCommandBuffers)",
        "⏱️": "Queue Submission (vkQueueSubmit)",
        
        # === Synchronization ===
        "🚦": "Fences (vkCreateFence)",
        "⏳": "Timeline Semaphores (VK_KHR_timeline_semaphore)",
        "🤝": "Events (vkCreateEvent)",
        
        # === Advanced ===
        "🌌": "Ray Tracing (VK_KHR_ray_tracing_pipeline)",
        "🚀": "Acceleration Structures (vkCreateAccelerationStructureKHR)",
        "🌀": "Mesh Shading (VK_EXT_mesh_shader)",
        "💫": "Task Shaders (VK_EXT_mesh_shader)",
        
        # === Debugging ===
        "🔍": "Validation Layers (VK_LAYER_KHRONOS_validation)",
        "🐛": "Debug Utils (vkCreateDebugUtilsMessengerEXT)",
        "📡": "Debug Markers (vkCmdDebugMarkerBeginEXT)",
        "📈": "Performance Queries (VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR)",
        
        # === Cleanup ===
        "🧹": "Resource Destruction (vkDestroy*)",
        "💥": "Device Cleanup (vkDestroyDevice)",
        "🚀": "Instance Shutdown (vkDestroyInstance)",
        
        # === New Additions ===
        "🔄": "Push Constants (vkCmdPushConstants)",
        "🎚️": "Dynamic States (VkPipelineDynamicStateCreateInfo)",
        "🧠": "Pipeline Derivatives (VK_PIPELINE_CREATE_DERIVATIVE_BIT)",
        "📌": "Specialization Constants (VkSpecializationInfo)",
        "🌐": "External Memory (VK_KHR_external_memory)",
        "🔗": "Linked GPUs (VK_KHR_device_group)"
    }
    
    #!/usr/bin/env python3
    # 🏆 Ultimate Vulkan Cheatsheet (70+ Concepts) 🏆
    
    vulkan_steps = [
        # === Core Setup (1-8) ===
        "1. 🌍 Instance Creation",
        "2. 🖥️ Physical Device Selection",
        "3. ⚙️ Logical Device Setup",
        "4. 🔌 Device Features",
        "5. 📜 Extensions/Layers",
        "6. 🖼️ SwapChain Initialization",
        "7. 🌐 Surface Creation",
        "8. 🧭 Queue Families",
    
        # === Resources (9-24) ===
        "9. 🗄️ Buffer Allocation",
        "10. 🧊 Device Memory",
        "11. 📦 Image Creation",
        "12. 🧶 Image Views",
        "13. 🔄 Memory Barriers",
        "14. 🧩 Sparse Resources",
        "15. 📊 Buffer Views",
        "16. 🧵 Host-Coherent Memory",
        "17. 🚚 Memory Transfers",
        "18. 🧠 Staging Buffers",
        "19. 🔗 External Memory",
        "20. 🧿 Protected Memory",
        "21. 💿 Buffer Device Address",
        "22. 🏷️ Resource Naming",
        "23. 📏 Memory Requirements",
        "24. 🧑‍🔧 Memory Budget",
    
        # === Pipeline (25-40) ===
        "25. 🎨 Graphics Pipeline",
        "26. 🤖 Compute Pipeline",
        "27. 🔮 Shader Modules",
        "28. 🎛️ Pipeline Layout",
        "29. 🧪 Pipeline Cache",
        "30. 🔄 Push Constants",
        "31. 🎚️ Dynamic States",
        "32. 📌 Specialization Constants",
        "33. 🧠 Pipeline Derivatives",
        "34. 💾 Pipeline Libraries",
        "35. 🌀 Tessellation",
        "36. 💫 Geometry Shaders",
        "37. 🧪 Subpasses",
        "38. ✂️ Depth/Stencil",
        "39. 🌈 Blend States",
        "40. 🧵 Multiview Rendering",
    
        # === Commands (41-50) ===
        "41. 🎮 Command Pools",
        "42. 📜 Command Buffers",
        "43. ⏱️ Queue Submission",
        "44. 🔁 Secondary Command Buffers",
        "45. 🧑‍🍳 Indirect Commands",
        "46. 🎛️ Device Groups",
        "47. 🤝 Queue Priorities",
        "48. ⏳ Timeline Semaphores",
        "49. 🚦 Fences",
        "50. 🤝 Events",
    
        # === Advanced (51-70) ===
        "51. 🌌 Ray Tracing",
        "52. 🚀 Acceleration Structures",
        "53. 🌀 Mesh Shading",
        "54. 💫 Task Shading",
        "55. 📡 Debug Markers",
        "56. 📈 Performance Queries",
        "57. 🕵️‍♀️ Object Tracking",
        "58. 🧩 Bindless Resources",
        "59. 🚧 Pipeline Barriers",
        "60. 💾 Pipeline Statistics",
        "61. 🌐 External Semaphores",
        "62. 🔄 Present Modes",
        "63. 🖌️ Dynamic Rendering",
        "64. 🧶 Fragment Density Maps",
        "65. 🌀 Variable Rate Shading",
        "66. 🧿 Protected Swapchains",
        "67. 📜 Shader Printf",
        "68. 🧪 Pipeline Robusness",
        "69. 🛡️ Validation Features",
        "70. 🧹 Resource Cleanup"
    ]
    

-- | -- | -- | ----------------------------------------------------------------------------





Chapter 4: VkSwapchainKHR 🪟

0. VkSwapchainCreateInfoKHR ℹ️

1. amVK wrap 🌯 Part I

    #include "amGHOST_VkSurfaceKHR.hh"

        // TwT
        REY_LOG("");
    amVK_Instance::EnumerateInstanceExtensions();
    amVK_Instance::addTo_1D_Instance_EXTs_Enabled("VK_KHR_surface");
    amVK_Instance::addTo_1D_Instance_EXTs_Enabled(amGHOST_System::get_vulkan_os_surface_ext_name());
        // amGHOST_VkSurfaceKHR::create_surface() needs that extension enabled
    amVK_Instance::CreateInstance();

        REY_LOG("");
    VkSurfaceKHR  VK_S = amGHOST_VkSurfaceKHR::create_surface(W, amVK_Instance::vk_Instance);

    // another 🌯 amVK_Wrap, at the end of this file

Page-Break

2. VkSurfaceKHR 🏄‍♀️

Part I:- Enabling VK_KHR_surface Vulkan Extension

https://vkdoc.net/man/VkSurfaceKHR
https://vkdoc.net/extensions/VK_KHR_surface
Yaaaay, we have reached our first extension to enable
we need to enable it back in vkCreateInstance() from 🔗 Chapter1.2

  1. 📜 vkEnumerateInstanceExtensionProperties()

  2. 🧊 IS_InstanceEXT_Available(const char* extName)

    bool amVK_InstanceProps::IS_InstanceEXT_Available(const char *extName) {
        for (uint32_t k = 0, lim = amVK_EXT_PROPs.n; k < lim; k++) {
            if (strcmp(amVK_EXT_PROPs[k].extensionName, extName) == 0) {    // <cstring>
                return true;
            }
        }
        return false;
    }
    
  3. 🧊 Add_InstanceEXT_ToEnable(const char* extName)

    static inline REY_ArrayDYN<char*> s_Enabled_EXTs = REY_ArrayDYN<char*>(nullptr, 0, 0);
        // It will be automatically allocated, resize, as we keep adding 😊
    #include <string.h>
    void amVK_Instance::Add_InstanceEXT_ToEnable(const char* extName) 
    {
        if (!amVK_InstanceProps::called_EnumerateInstanceExtensions) {
             amVK_InstanceProps::EnumerateInstanceExtensions();
        }
        
        if (amVK_InstanceProps::IS_InstanceEXT_Available(extName)) {
            char  *dont_lose = new char[strlen(extName)];
            strcpy(dont_lose, extName);
    
            s_Enabled_EXTs.push_back(dont_lose);
    
            amVK_Instance::CI.enabledExtensionCount = s_Enabled_EXTs.neXt;
            amVK_Instance::CI.ppEnabledExtensionNames = s_Enabled_EXTs.data;
        }
        else {
            REY_LOG_notfound("Vulkan Extension:- " << extName);
        }
    }
    





Part II:- OS Specfic SurfaceEXT & Creating it

amVK_Instance::Add_InstanceEXT_ToEnable(amGHOST_System::get_vulkan_os_surface_ext_name());
    // or
amVK_Instance::Add_InstanceEXT_ToEnable("VK_KHR_win32_surface");
    // or some other surface name
  1. Win32SurfaceCI
  2. vkCreateWin32SurfaceKHR()
  3. </> TheCode
    pure-virtual VkSurfaceKHR amGHOST_VkSurfaceKHR_WIN32::create(VkInstance I) 
    {
        amGHOST_SystemWIN32 *heart_win32 = (amGHOST_SystemWIN32 *) amGHOST_System::heart;
        VkWin32SurfaceCreateInfoKHR CI = {
            .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
            .pNext = NULL,
            .flags = 0,
            .hinstance = heart_win32->_hInstance,
            .hwnd = this->W->m_hwnd
                // W = amGHOST_WindowWIN32
        };
    
        VkSurfaceKHR S = nullptr;
        VkResult return_code = vkCreateWin32SurfaceKHR(I, &CI, nullptr, &S);
        amVK_return_code_log( "vkCreateWin32SurfaceKHR()" );
        return S;
    }
    
  4. VkXlibSurfaceCreateInfoKHR & vkCreateXlibSurfaceKHR() 🛠️ [wip]
  5. 📜 REY_DOCs
    • you can also check amGHOST_VkSurfaceKHR::create_surface() 😉
  6. 📽️ So far, The result
    • 4.guide.chapter4.2.amGHOST.hh
    • in the end people will just use 1 line
      VkSurfaceKHR VK_S = amGHOST_VkSurfaceKHR::create_surface(amG_WindowOBJ, amVK_Instance::s_vk);
      

Page-Break

3. Naming Patterns ✏️

example naming patterns for storing all these data.... cz it's gonna get overwhelming pretty soon, pretty fast

  1. Arrays

    class amVK_InstanceProps {
        public:
            // Array of `HardWare amVK_1D_GPUs` connected to motherboard
        static inline REY_Array<VkPhysicalDevice>                          amVK_1D_GPUs;
        static inline REY_Array<REY_Array<VkQueueFamilyProperties>>        amVK_2D_GPUs_QFAMs;
        static inline REY_Array<VkExtensionProperties>                     amVK_1D_InstanceEXTs;
        static inline REY_ArrayDYN<char*>                                  amVK_1D_InstanceEXTs_Enabled;
        static inline REY_ArrayDYN<SurfaceInfo>                            amVK_1D_SurfaceInfos; // See Below
        static inline REY_Array<REY_Array<VkExtensionProperties>>          amVK_2D_GPUs_EXTs;
            // REY_Array  doesn't allocate any memory by default
    
        #define amVK_LOOP_GPUs(_var_)           \
            for (uint32_t _var_ = 0, lim = amVK_1D_GPUs.n;             _var_ < lim;  _var_++)
        #define amVK_LOOP_QFAMs(_k_, _var_)     \
            for (uint32_t _var_ = 0, lim = amVK_2D_GPUs_QFAMs[_k_].n;  _var_ < lim;  _var_++)
    };
    
  2. ChildrenStructs

    class amVK_InstanceProps {
        class SurfaceInfo {
          public:
            VkSurfaceKHR S = nullptr;
            SurfaceInfo(void) {}
            SurfaceInfo(VkSurfaceKHR pS) {this-> S = pS;}
    
                    REY_Array<REY_Array<VkSurfaceFormatKHR>>          amVK_2D_GPUs_ImageFMTs;
    
            bool called_GetPhysicalDeviceSurfaceFormatsKHR = false;
            void        GetPhysicalDeviceSurfaceFormatsKHR(void);  // amVK_2D_GPUs_ImageFMTs
        };
    };
    
  3. VkFuncCalls

    class amVK_InstanceProps {
        public:
        static inline bool called_EnumeratePhysicalDevices = false;
        static inline bool called_GetPhysicalDeviceQueueFamilyProperties = false;
        static inline bool called_EnumerateInstanceExtensions = false;
    
        public:
        static void EnumeratePhysicalDevices(void);                         // amVK_1D_GPUs
        static       void GetPhysicalDeviceQueueFamilyProperties(void);     // amVK_2D_GPUs_QFAMs
        static void EnumerateInstanceExtensions(void);                      // amVK_1D_InstanceEXTs
    };
    

Page-Break

4. SwapChain Image Options 🖼️

.imageFormat + .imageColorSpace

  1. vkGetPhysicalDeviceSurfaceFormatsKHR()

  2. VkSurfaceFormatKHR 📺
    • https://vkdoc.net/man/VkSurfaceFormatKHR
      • ||| .format 🖼️🔢 ImageFormat
      • .colorSpace 🖼️🌈 ImageColorSpace
      • No Other options
    • 📜 REY_DOCs
      • This is basically a Combo of 🖼️🔢 ImageFormat & 🖼️🌈 ColorSpace
        • so, the gpu kinda expects you to respect these combos, when you are gonna set these into VkSwapchainCreateInfoKHR. instead of mumbo-jumbo-ing & mixing random stufs alltogether....
        • altho, even if you do so, gpu is probably gonna show you the result of WRONG COLORSPACE/IMAGEFORMATs on the screen

  3. Life is Hard without Images/Visualization


.minImageCount
🖼️ + .imageExtent + .imageArrayLayers + .imageUsage
🧙‍♂️ .compositeAlpha + .preTransform

4. VkSurfaceCapabilitiesKHR

  1. vkGetPhysicalDeviceSurfaceCapabilitiesKHR()

  2. Life is Hard without Images/Visualization 2


.imageSharingMode

  1. VkSharingMode


  2. 📽️ So far, The result:-

    amVK_SwapChain *SC = new amVK_SwapChain(VK_Surface);
        SC->CI.imageFormat = VK_FORMAT_B8G8R8A8_UNORM;
        SC->CI.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
        SC->CI.minImageCount    = amVK_InstanceProps::amVK_1D_SurfaceInfos[0].amVK_1D_GPUs_SurfCAP[0].minImageCount;
        SC->CI.imageExtent      = amVK_InstanceProps::amVK_1D_SurfaceInfos[0].amVK_1D_GPUs_SurfCAP[0].currentExtent;
        SC->CI.imageArrayLayers = amVK_InstanceProps::amVK_1D_SurfaceInfos[0].amVK_1D_GPUs_SurfCAP[0].maxImageArrayLayers;
            // You can just use "1" too, which is guranteed by DRIVER_IMPLEMENTATION [2DriverIMPL]
        SC->CI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
            // `EXCLUSIVE/CONCURRENT` [Toggle]
        SC->CI.imageUsage       = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
            // 2DriverIMPL:- VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT is guranteed to be supported by SurfCAP
    

  3. Abbreviations


  4. VkSwapchainCreateInfoKHR


Page-Break

5. SwapChain Compositing Options 🧙‍♂️

  1. .compositeAlpha

    • https://vkdoc.net/man/VkCompositeAlphaFlagBitsKHR
    • 📜 REY_DOCs
      • Options:- Don't use / Pre-multiplied / Post-multiplied / inherit from OS-native window system
      • Requirement:-
        • You would have to enable @ OS level first, to enable ALPHA/Transparency/GlassEffect for window-s/surfaces
        • then after that, if you query for vkGetPhysicalDeviceSurfaceCapabilitiesKHR()
          • SurfCAP.supportedCompositeAlpha will change
        • by default, it's prolly always gonna support
          • VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR
          • i.e. if you haven't done any mastery wizardry yet, to enable ALPHA/Transparency/GlassEffect
  2. .preTransform

  3. .clipped

    • 📜 REY_DOCs
      • Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the surface area
  4. .presentMode 🏷️ VkPresentModeKHR

  5. .oldSwapChain

    • 📜 REY_DOCs
      • if you are "re-creating" swapchain & you had an oldSwapchain
      • We do this when
        1. Window Size / WindowExtent / Surface was Changed
  6. 📽️ So far, The result

    amVK_SwapChain *SC = new amVK_SwapChain(VK_Surface);
        ... Image Stuffs
        SC->CI.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
        SC->CI.preTransform   = amVK_InstanceProps::amVK_1D_SurfaceInfos[0].amVK_1D_GPUs_SurfCAP[0].currentTransform;
        SC->CI.clipped        = VK_TRUE;
        SC->CI.presentMode    = VK_PRESENT_MODE_FIFO_KHR;
        SC->CI.oldSwapchain   = nullptr;
    

Page-Break

6. SwapChain Extension Enabling 🧩 [VK_KHR_swapchain]

  1. vkEnumerateDeviceExtensionProperties()

    class amVK_InstanceProps {
        ...
        static inline bool called_EnumerateDeviceExtensionProperties = false;
        static void               EnumerateDeviceExtensionProperties(void); // amVK_2D_GPUs_EXTs
    
        static inline REY_Array<REY_Array<VkExtensionProperties>>              amVK_2D_GPUs_EXTs;
        #define amVK_LOOP_GPU_EXTs(_k_, _var_)  for (uint32_t _var_ = 0,  lim = amVK_2D_GPUs_EXTs[_k_].n;   _var_ < lim;  _var_++)
    
        static bool      IS_GPU_EXT_Available(PD_Index GPU_k, const char *extName); // amVK_2D_GPUs_EXTs
        // kinda copy of IS_InstanceEXT_Available
        ...
    };
    
  2. amVK_Device::Add_GPU_EXT_ToEnable(const char* extName)

    class amVK_Device {
        ...
        REY_ArrayDYN<char*>   amVK_1D_DeviceEXTs_Enabled;
        void Log_GPU_EXTs_Enabled(VkResult ret);
        void Add_GPU_EXT_ToEnable(const char* extName);
            // Copy of `amVK_InstanceProps::Add_InstanceEXT_ToEnable()` -> but not static anymore.... 🤷‍♀️
    };
    
  3. 📽️ So far, The result


Page-Break

7. 🌱 vkCreateSwapchainKHR()

8. amVK wrap 🌯 Part II

    amVK_InstanceProps::EnumerateDeviceExtensionProperties();

    amVK_Device* D = new amVK_Device(amVK_InstanceProps::GetARandom_GPU());
        D->select_QFAM_Graphics();
        D->Add_GPU_EXT_ToEnable("VK_KHR_swapchain");
        D->CreateDevice();

9. amVK wrap 🌯 Part III

    #include "amVK_Surface.hh"
    #include "amVK_SwapChain.hh"

        // TwT
        REY_LOG("")
    amVK_Surface           *S  = new amVK_Surface(VK_S);
    amVK_SurfacePresenter  *PR = S->PR;
                            PR->bind_Surface(S);
                            PR->bind_Device(D);
                            PR->create_SwapChain_interface();       
                                // This amVK_SwapChain is Bound to this amVK_Surface

    amVK_SwapChain *SC =    PR->SC;
        SC->konf_ImageSharingMode(VK_SHARING_MODE_EXCLUSIVE);
        SC->konf_Images(
            amVK_IF::RGBA_8bpc_UNORM,   // VK_FORMAT_R8G8B8A8_UNORM
            amVK_CS::sRGB,              // VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
            amVK_IU::Color_Display      // VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
        );
        SC->konf_Compositing(
            amVK_PM::FIFO,              // VK_PRESENT_MODE_FIFO_KHR
            amVK_CC::YES,               // Clipping:- VK_TRUE
            amVK_TA::Opaque             // VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR
        );
        SC->sync_SurfCaps();            // refresh/fetch & set/sync ---> latest SurfCaps

        SC->CI.oldSwapchain     = nullptr;
        SC->CreateSwapChain();




🧙‍♂️ Part 2: The True Arcane Secrets of

RenderPass

(SubPass + Image Layer Transition) & FrameBuffers

Welcome to the inner sanctum where GPU gods decide how fast your pixels live or die.

- ChatGPT


Chapter 5: RenderPass 🥪

"subpasses are the soul of RenderPass! . But it's not just about subpasses only...." - ChatGPT

0. Why RenderPass?

1. What is RenderPass? 🥪

  1. RenderPass is designed around subpasses.
    • The core purpose of a RenderPass is to tell Vulkan:

      • “Hey, I’m going to do these rendering stages (subpasses), in this order, using these attachments.”

    • So yeah, subpasses are the main reason for a RenderPass to exist. subpasses are the soul of RenderPass!

    • But it's not just about subpasses only:-

      1. 🌟 Load/Store Ops — "What should I do with the image before & after rendering?"

        • 🚪 loadOp — When RenderPass begins:
               LOAD: Keep whatever was already in the attachment.
              CLEAR: Wipe it to a specific value (e.g., clear color to black).
          DONT_CARE: Vulkan can throw away old contents (faster, if you don’t care).
          
        • 🚪 storeOp — When RenderPass ends:
              STORE: Save the result (e.g., to present to the screen or use later).
          DONT_CARE: Vulkan can discard the result (like shadow maps or intermediate stuff you don't need to read later).
          
        • ex.
          colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
          colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
              // Meaning: Clear the image before rendering, and store the result so we can present it.
          
      2. 🎯 Image Layout Transitions — "How should the GPU access this image during the pass?"

                                [ VK_IMAGE_LAYOUT_UNDEFINED ]
                                            👇 clear
                                [ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ]
                                            👇 render
                                [ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ]
                                            👇 post-process
                                [ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ]
        
      3. 📜 Attachments — "What images are we using?"

        • RenderPass Attachment is not an actual thing!
        • RenderPass Attachment Description/Descriptor is a thing!
          • However, the idea is.... We do "define" the Attachments right here, as we send the AttachmentDescriptions -> RenderPass
        • RenderPass Attachment != FrameBuffer Attachment
        • FrameBuffer Attachment
          • ----> actual VkImageViews of SwapChain Images



  2. 🎯 Image Layout Transitions
    1. 🏭 1. Different hardware units = different memory access patterns

      GPU Unit	                Access Pattern
      ------------------     -----------------------
      Fragment Shader 	    Texture-like (random)
      Render Output Unit	    Tiled or linear (write-heavy)
      Compute Shader	        Raw buffer-style
      Display Engine	        Linear format
      
      - for ex.
      
      • When an image is used as a color attachment, it might be stored tiled in memory for fast write performance.
      • But when you use the same image as a texture, the shader expects it to be in a format optimized for random read access.
      • 👉 If you tried to read from a tiled format as if it were a texture, you'd either:
        • Get garbage
        • Or pay a huge perf penalty as the driver does conversion.... (every single time you access a single pixel) (a single pixel would = an element in an 2D Array) (Texture might have Millions of Pixel)



    2. 🧱 Physical Layout in VRAM (Tiles vs Linear)

      • Most modern GPUs store image data in tiles internally.
        • (like Z-order, Morton order, or other optimized memory layouts).
        • This helps GPUs fetch memory in cache-friendly blocks for faster rendering.
      • But when an image is to be presented to the screen/monitor, it must be Flat (linear) (as HDMI/display engines can’t decode tiles).
        • Yes — by "linear", we mean a simple 2D array where pixels are stored in a straightforward, left-to-right, top-to-bottom format.
      • So when you do this:-
        finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
        
        • 💡 What you're really telling Vulkan is:
        • “Yo, I’m done rendering — please un-tile this, decompress it, and arrange it in scanlines for display.”

        • If you don’t tell Vulkan, it has to guess or stall — or worse, copy the whole thing behind your back.



    3. 🔄 Transitions let the driver do reordering, compression, or memory reallocation

          //  When you declare:-
      finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
          // you are not just giving a hint.... 
          // ---- you are saying:-
      
      • “After rendering, I'm going to sample this as a texture — so prepare it.”

      This allows the GPU driver to:
      - flush caches
      - Decompress the image (some GPUs compress attachments during render!)
      - Move memory or restructure tiles
      - Or even alias memory with another attachment in a single memory block
      - In modern GPUs, there's hardware image compression, like:-
          - ARM's AFBC (Arm Frame Buffer Compression)
          - AMD's DCC (Delta Color Compression)
          - NVIDIA has their own secret sauce too
      

    4. 🌀 Aliasing & Tile Memory Reuse [ImageLayouts + Barriers]

      • One of the sickest optimizations is this one
      • You can use the same memory for multiple attachments (e.g. shadow map, depth, HDR buffer), as long as you don’t use them at the same time.
      • But to do that safely, Vulkan needs to know:
        • “When does this memory stop being ‘render target’ and start being ‘texture’ or ‘compute input’?”

      Layouts + barriers = safe aliasing.
      
      Drivers can now:
      - Use the same memory pool
      - Skip clearing
      - Not double allocate
      
      You become a GPU memory ninja 💨🗡️
      

    5. 📜 Predictability = Performance

      Explicit layouts give Vulkan this power:
      - It knows exactly when and how you are going to use an image.
      - So it can avoid runtime guessing, which causes:
          - CPU stalls
          - Cache flushes
          - Sync fences
          - Or even full GPU pipeline bubbles 😵‍💫
      
      - Compared to OpenGL or DirectX11, where the driver had to guess what you meant and do hidden magic — Vulkan is like: 
      
      • “If you don’t tell me what layout you want, I’ll trip and fall flat on my face 😭”


    6. 👻 You can skip transitions altogether if you do it right

      • This is the reward -> If your RenderPass is smart — using VK_ATTACHMENT_LOAD_OP_DONT_CARE and reusing image layouts cleverly — you can avoid layout transitions entirely.
        • This is massive for tile-based GPUs (like on mobile phones):
        • No layout transition = no VRAM flush
        • Everything happens on-chip, like magic 💨



    7. 🎮 Analogy: Baking Cookies 🍪

      Let’s say you're:
      - Baking cookies (rendering)
      - Then you plate them for display (presenting)
      - Later you want to show them off or decorate them (sample in shaders)
      
      • Here’s the deal:
      Vulkan Image Layout	                  Cookie Stage
      ------------------------      ---------------------------------
      UNDEFINED	                    Empty tray, nothing on it yet
      COLOR_ATTACHMENT_OPTIMAL	    You're baking the cookies 🔥
      SHADER_READ_ONLY_OPTIMAL	    You’ve finished baking and wanna decorate (like sampling in a post-process shader) 🎨
      PRESENT_SRC_KHR	                You’re plating the cookies to serve 🥂 (sending to the screen)
      
      • But… here's the twist:
        • 💥 You can’t decorate cookies while they’re still baking in the oven.
        • 💥 And you definitely can’t serve someone cookies that are still stuck in a 200°C tray.
      • So Vulkan says:
        • “Please transition between layouts, so I know what stage your cookie is in — and I’ll move it to the right place, with oven mitts, spatulas, etc.”


    8. 🧼 Why does this matter?

      • If you don’t do the transitions:
      You may try to grab a cookie off a 200°C tray and get burned (💀 invalid reads)
      The cookies may not be fully baked (💀 undefined writes)
      Or worse: you show your customer an empty plate because Vulkan never moved them to the PRESENT_SRC_KHR plate 😭
      

    9. 🚀 What makes Vulkan powerful?

      You get to say:
      1. "Bake in tray A"
      2. "Decorate using buffer B"
      3. "Present from plate C"
      
      But you must tell Vulkan when to move cookies from one surface to another.
      Layouts = telling Vulkan exactly thaaat!
      

    10. 🧪 Subpass Optimization (Tile-Based GPUs)

      On tile-based GPUs (like PowerVR or Mali):
      - Entire framebuffers live on-chip, in tiles
      - You can run all subpasses without touching VRAM!
      
      But it only works if Vulkan knows:
      - The image will stay in the same layout
      - No unnecessary STORE or layout transitions
      
      By carefully using:
          layout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL;
          loadOp = DONT_CARE;
          storeOp = DONT_CARE;
      
      You unlock 🥷 zero-cost rendering.
      
      • That's why subpasses and layouts are so closely linked — no layout changeno memory movement.











  3. 🏁 TL;DR: Image Layout Transitions Aren’t Just Bureaucracy

    🎯 They are literal instructions to the driver:
        - "Where this image lives"
        - "How it’s structured"
        - "What GPU unit will touch it next"
        - "Whether you need to prepare, flush, decompress, or alias it"
    
    🎯 And by explicitly telling the GPU, you:
        - Avoid expensive guesses
        - Skip hidden memory ops
        - Unlock mobile-level optimizations
        - Prevent subtle bugs and undefined behavior
    

  4. 📜 RenderPass Attachments Desc.

    • RenderPass Attachment is not an actual thing!
    • RenderPass Attachment Description/Descriptor is a thing!
      • However, the idea is.... We do "define" the Attachments right here, as we send the AttachmentDescriptions -> RenderPass
    • RenderPass Attachment Description/Descriptors are not actual images — they’re a template for what the RenderPass expects!
      • & The FrameBuffers must delivery RenderPass exactly with that
    • RenderPass Attachment != FrameBuffer Attachment

      RenderPass Attachments Framebuffers
      Define what is needed Provide which resources to use
      Abstract (format, usage, layout) Concrete (image views)
      Reusable across Framebuffers Swapchain-dependent (often 1:1)
      Think of it like a Socket & Plug
          - `RenderPass`  🥪 = The RenderPass defines the socket (shape, voltage).
          - `Framebuffer` 📦 = The Framebuffer provides the plug (actual wires) that fits the socket.
      

  5. 📦 FrameBuffer Attachment

    • Actual VkImageView
      Image Views (VkImageView): 
          Handles to specific images (e.g., swapchain images, depth textures).
      Compatibility: 
          Must match the RenderPass’s attachment definitions (format, sample count, size).
      Swapchain Link: 
          Typically, one Framebuffer per swapchain image.
      

  6. 🛒 FrameBuffers [🍞🍅🥚🍗]

    • Binds concrete ImageViews (e.g., SwapChain Images, Depth Textures) to the attachments defined in the RenderPass.
    • Must match the RenderPass’s Attachment Descriptions (format, size, sample count).
    • Is SwapChain-dependent (e.g., each SwapChainImage typically has its own Framebuffer).
    • Analogy
      - `RenderPass`  🥪 = A recipe requiring "2 eggs and 1 cup of flour" (attachments).
      - `Framebuffer` 🛒 = The actual eggs and flour (image views) you use to bake a cake (render a frame).
      

  7. 📦 Attachments

    RenderPass Attachments (Blueprint)Framebuffer (Instance)-------------------------------┐        ┌-----------------------------┐
    │ Attachment 0: Color (SRGB)    │        │ Image View 0: Swapchain IMG │
    │ Attachment 1: Depth (D32_SF)  │        │ Image View 1: Depth Texture │
    └-------------------------------┘        └-----------------------------
    • Attachments are simply images (or buffers) where Vulkan stores or reads data during a RenderPass.
    • Attachments are the actual framebuffer images (swapchain images, depth buffers, offscreen render targets, etc.)

    1. 🖌️ Color Attachments = where the pretty pixels (RGBA) are painted and stored. This is like your paint palette! 🎨
    2. 🏔️ Depth Attachments = the landscapes that prevent objects from clipping or showing up out of order. Imagine topography maps for depth! 🗺️
    3. ✏️ Stencil Attachments = the guides that show where we can paint, like drawing a "map" where only certain areas can be modified. 🗺️

    • What’s inside?
      • A framebuffer that stores things like RGBA values (Red, Green, Blue, Alpha/Transparency).
      • For example,
        • Color Attachment 0 might hold the albedo or the final color of an object, while
        • Color Attachment 1 could store the lighting information or additional passes like ambient occlusion.
    Each attachment you declare includes:
    - Format (VK_FORMAT_B8G8R8A8_SRGB, etc.)
    - Sample count (for MSAA)
    - Load/store ops
    - Layouts (see above)
    
    • Then, each subpass tells Vulkan:
    • "From all the attachments I’ve declared, I’m gonna use these ones in this subpass."

    • in Code:
      attachments[0] = colorAttachment;   // swapchain image
      attachments[1] = depthAttachment;   // depth image
      
      subpass.colorAttachment = &attachments[0];
      subpass.depthAttachment = &attachments[1];
      
      So even if your RenderPass only has one subpass, the Vulkan driver still wants to know:
      - How many attachments
      - What to do with them (clear/store?)
      - What layouts they go into and come out as
      





  8. 🛒 FrameBuffers v/s 📦 Attachments:- The Last Fight, (If Above stuffs got you confused):-

    1. Quick Comparison Table

      Aspect Attachments (RenderPass) ✖ Framebuffers 🖼
      Purpose Define what resources are needed (format, usage, layout transitions) 📝 Specify which actual images (image views) to use for those resources ✏️
      Concrete/Abstract Abstract (blueprint) 📒 Concrete (instance) 🏗
      Lifetime Long-lived (reused across frames) ♻️ Short-lived (often recreated with swapchain) ↻
      Dependencies Independent of images/swapchain ⛔ 🖼 Tied to swapchain images or specific textures 🔗
      Example "Need a color attachment (SRGB) and depth attachment (D32_SFLOAT)" 🎨➕🌑 "Use this swapchain image and that depth texture" 🖼 1️⃣ + 🖼 2️⃣
    2. Lifecycle Flowchart

      RenderPass Creation 🏗️  
      │  
      ├── Define Attachments 📄 (format, load/store ops, layouts)  
      │   └── "I need a color slot (B8G8R8A8_SRGB) and depth slot (D32_SFLOAT)" 🎨🌑
      │  
      └── Define Subpasses 🔗 (how attachments are used in rendering steps)  
      
      ↓  
      
      Framebuffer Creation 🛠️  
      │  
      ├── Bind Image Views to Attachment Slots 🔌  
      │   └── "Slot 0 = Swapchain Image View 🖼️, Slot 1 = Depth Texture View 🧊"  
      │  
      └── Validate Compatibility ✅ (size, format, sample count)  
      
    3. Use-Case Scenarios

      Scenario Attachments (RenderPass) 🧩 Framebuffers 🖼️
      Swapchain Rendering Define color/depth formats and layouts. 🎨🔄🌑 Bind swapchain images + depth texture. 🖼️🔗🧊
      Deferred Rendering Define G-Buffer attachments (Albedo, Normal, Position). 📦📦📦 Bind actual G-Buffer image views. 🖼️1️⃣🖼️2️⃣🖼️3️⃣
      Post-Processing Define input (e.g., HDR color) + output (e.g., SRGB). 🌟➡️🎨 Bind input texture + swapchain image. 🧩🖼️

    4. Key Interactions

      RenderPass Begin Command 🚦  
      │  
      ├── Uses RenderPass Attachments 🧩 (format, load/store rules)  
      │  
      └── Uses Framebuffer 🖼️ (actual images to write to)  
      
      ↓  
      
      GPU Renders 🎮  
      │  
      ├── Reads/Writes to Framebuffer’s Image Views 📊  
      │  
      └── Follows Attachment Rules (clearing, layout transitions) 🔄  
      
    5. Emoji Analogy Time! 🤯

      • Attachments = Recipe Ingredients List 📜 (e.g., "2 eggs 🥚🥚, 1 cup flour 🍚").
      • Framebuffers = Actual Ingredients 🛒 (e.g., "This egg 🥚 from the fridge, that flour 🍚 from the pantry").
      • Rendering = Baking the Cake 🎂 (combine them using the recipe steps!).

  9. Next Chapter will be on 🛒 FrameBuffers!!!! 🤭









Everything above is written with help from chatGPT

Everything below is not!








0. amVK Wrap 😊

    #include "amVK_RenderPass.hh
        
        // TwT
        SC->GetSwapChainImagesKHR();
        SC->CreateSwapChainImageViews();

    amVK_RenderPass *RP = PR->create_RenderPass_interface(); 

2. vkCreateRenderPass()

3. VkRenderPassCreateInfo()

4. ImageViews

  1. vkGetSwapchainImagesKHR()

    • https://vkdoc.net/man/vkGetSwapchainImagesKHR
    • Implement Exactly like Chapter2.5 😉
      • vkGetPhysicalDeviceQueueFamilyProperties()
    • REY_DOCs
      class amVK_SwapChain  {
          ...
        public:
          amVK_Device *D = nullptr;
          VkSwapchainKHR SC = nullptr;
          REY_Array<VkImage>    amVK_1D_SC_IMGs;
          REY_Array<amVK_Image> amVK_1D_SC_IMGs_amVK_WRAP;
          bool called_GetSwapchainImagesKHR = false;
      
        public:
          ...
      
  2. vkCreateImageView()

  3. VkImageViewCreateInfo

    • https://vkdoc.net/man/VkImageViewCreateInfo
    • REY_DOCs
      void amVK_SwapChain::CreateSwapChainImageViews(void) {
          REY_Array_LOOP(amVK_1D_SC_IMGs_amVK_WRAP, i) {
                  // ViewCI.image
                  // ViewCI.format
                      // should be set inside amVK_SwapChain::GetSwapchainImagesKHR()
              amVK_1D_SC_IMGs_amVK_WRAP[i].ViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
      
              amVK_1D_SC_IMGs_amVK_WRAP[i].ViewCI.components = { // Equivalent to:
                  VK_COMPONENT_SWIZZLE_R,        // VK_COMPONENT_SWIZZLE_IDENTITY
                  VK_COMPONENT_SWIZZLE_G,        // VK_COMPONENT_SWIZZLE_IDENTITY
                  VK_COMPONENT_SWIZZLE_B,        // VK_COMPONENT_SWIZZLE_IDENTITY
                  VK_COMPONENT_SWIZZLE_A         // VK_COMPONENT_SWIZZLE_IDENTITY
              };
      
              amVK_1D_SC_IMGs_amVK_WRAP[i].ViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
              amVK_1D_SC_IMGs_amVK_WRAP[i].ViewCI.subresourceRange.baseMipLevel = 0;
              amVK_1D_SC_IMGs_amVK_WRAP[i].ViewCI.subresourceRange.levelCount = 1;
              amVK_1D_SC_IMGs_amVK_WRAP[i].ViewCI.subresourceRange.baseArrayLayer = 0;
              amVK_1D_SC_IMGs_amVK_WRAP[i].ViewCI.subresourceRange.layerCount = 1;
      
              amVK_1D_SC_IMGs_amVK_WRAP[i].createImageView();
          }
      }
      

5. VkAttachmentDescription

6. VkSubpassDescription

7. VkSubpassDependency

8. All the last 3 together ---> Code

class amVK_RenderPass  {
  public:
    REY_ArrayDYN<VkAttachmentDescription> attachments;
    REY_ArrayDYN<VkSubpassDescription> subpasses;
    REY_ArrayDYN<VkSubpassDependency> dependencies;

    void set_attachments_subpasses_dependencies(void);
}
amVK_RenderPass *RP = new amVK_RenderPass(D);
    RP->attachments.push_back({
        .format = SC->CI.imageFormat,                       // Use the color format selected by the swapchain
        .samples = VK_SAMPLE_COUNT_1_BIT,                   // We don't use multi sampling in this example
        .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,              // Clear this attachment at the start of the render pass
        .storeOp = VK_ATTACHMENT_STORE_OP_STORE,            
            // Keep its contents after the render pass is finished (for displaying it)
        .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,   
            // Similar to loadOp, but for stenciling (we don't use stencil here)
        .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 
            // Similar to storeOp, but for stenciling (we don't use stencil here)
        .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,         
            // Layout at render pass start. Initial doesn't matter, so we use undefined
        .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,     
            // Layout to which the attachment is transitioned when the render pass is finished
            // As we want to present the color attachment, we transition to PRESENT_KHR
    });

    VkAttachmentReference colorReference = {
        .attachment = 0,
        .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
    };
    RP->subpasses.push_back({
        .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,

        .inputAttachmentCount = 0,             
            // Input attachments can be used to sample from contents of a previous subpass
        .pInputAttachments = nullptr,          // (Input attachments not used by this example)
        .colorAttachmentCount = 1,             // Subpass uses one color attachment
        .pColorAttachments = &colorReference,  // Reference to the color attachment in slot 0

        .pResolveAttachments = nullptr,        
            // Resolve attachments are resolved at the end of a sub pass and can be used for e.g. multi sampling
        .pDepthStencilAttachment = nullptr,    // (Depth attachments not used by this sample)
        .preserveAttachmentCount = 0,          
            // Preserved attachments can be used to loop (and preserve) attachments through subpasses
        .pPreserveAttachments = nullptr        // (Preserve attachments not used by this example)
    });

    RP->dependencies.push_back({
        // Setup dependency and add implicit layout transition from final to initial layout for the color attachment.
        // (The actual usage layout is preserved through the layout specified in the attachment reference).
        .srcSubpass = VK_SUBPASS_EXTERNAL,
        .dstSubpass = 0,
        .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
        .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
        .srcAccessMask = VK_ACCESS_NONE,
        .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
    });

    RP->set_attachments_subpasses_dependencies();
    RP->createRenderPass();

    ------------------------------------- Made with help from P.A.Minerva Vulkan Guide -------------------------------------
    https://paminerva.github.io/docs/LearnVulkan/01.A-Hello-Window#416---creating-a-render-pass




9. By This time, VkSurfaceKHR deserves it's very own class amVK_Surface





Chapter 6

amVK_ColorSpace.hh, amVK_Surface, amVK_SurfacePresenter, Renaming Things in amVK

1. amVK_ColorSpace.hh

/**
 * ex. 1   amVK_IF::RGBA_8bpc_UNORM
 */
namespace amVK_ImageFormat {
    // 8bpc = 8-bits per channel
    inline constexpr VkFormat RGBA_8bpc_UNORM    = VK_FORMAT_R8G8B8A8_UNORM;    // 37
    inline constexpr VkFormat RGBA_8bpc_SNORM    = VK_FORMAT_R8G8B8A8_SNORM;    // 38
    inline constexpr VkFormat RGBA_8bpc_USCALED  = VK_FORMAT_R8G8B8A8_USCALED;  // 39
    inline constexpr VkFormat RGBA_8bpc_SSCALED  = VK_FORMAT_R8G8B8A8_SSCALED;  // 40
    inline constexpr VkFormat RGBA_8bpc_UINT     = VK_FORMAT_R8G8B8A8_UINT;     // 41
    inline constexpr VkFormat RGBA_8bpc_SINT     = VK_FORMAT_R8G8B8A8_SINT;     // 42
    inline constexpr VkFormat RGBA_8bpc_SRGB     = VK_FORMAT_R8G8B8A8_SRGB;     // 43

    // Common Depth/Stencil Formats
    inline constexpr VkFormat D32_SFLOAT         = VK_FORMAT_D32_SFLOAT;
    inline constexpr VkFormat D24_UNORM_S8_UINT  = VK_FORMAT_D24_UNORM_S8_UINT;
}
#define amVK_IF amVK_ImageFormat
#define amVK_PF amVK_ImageFormat
#define amVK_PixelFormat amVK_ImageFormat

2. amVK_Surface

/**
 * VULKAN-EXT:- `VK_KHR_surface`
 *       IMPL:- `amVK_1D_SurfaceInfos`
 */
class amVK_Surface {
  public:
    VkSurfaceKHR S = nullptr;       // Set in CONSTRUCTOR
    amVK_SurfacePresenter *PR = nullptr;   // Set in CONSTRUCTOR
    
    amVK_Surface(void) {}
    amVK_Surface(VkSurfaceKHR pS);

                REY_Array<REY_Array<VkSurfaceFormatKHR>>              amVK_2D_GPUs_ImageFMTs;
                REY_Array<VkSurfaceCapabilitiesKHR>                   amVK_1D_GPUs_SurfCAP;

    bool called_GetPhysicalDeviceSurfaceFormatsKHR = false;
    bool called_GetPhysicalDeviceSurfaceCapabilitiesKHR = false;
    void        GetPhysicalDeviceSurfaceInfo(void);
    void        GetPhysicalDeviceSurfaceCapabilitiesKHR(void);
};

Page-Break

3. amVK_SurfacePresenter

class amVK_SurfacePresenter {
  public:
    amVK_Surface  *S  = nullptr;
    amVK_SwapChain *SC = nullptr;
    amVK_RenderPass *RP = nullptr;
        //   SC.VkDevice = RP.VkDevice
    amVK_Device        *D = nullptr;
    VkPhysicalDevice   GPU = nullptr;
        // amVK_Device.m_PD = this->GPU;
    amVK_GPU_Index GPU_Index = 0;
    
  public:
    void bind_Device(amVK_Device *D);
    amVK_SurfacePresenter  (amVK_Surface* pS) {this->S = pS;}

  public:
    amVK_SwapChain*  create_SwapChain(void);
    amVK_RenderPass* create_RenderPass(void);
    // Defined currently inside amVK_SwapChain.cpp
    
    void                      refresh_SurfCaps(void) { this->S->GetPhysicalDeviceSurfaceCapabilitiesKHR(); }
    VkSurfaceCapabilitiesKHR* fetched_SurfCaps(void) {
        return &( this->S->amVK_1D_GPUs_SurfCAP[this->GPU_Index] );
    }
};

4. amVK Naming Conventions 😊

  1. Calling Vulkan Library Functions:-

    bool called_GetPhysicalDeviceSurfaceFormatsKHR = false;
    bool called_GetPhysicalDeviceSurfaceCapabilitiesKHR = false;
    void        GetPhysicalDeviceSurfaceInfo(void);
    void        GetPhysicalDeviceSurfaceCapabilitiesKHR(void);
    
  2. vkCreateZZZ() wrappers

    amVK_SwapChain {
        void CreateSwapChain(void) {
            VkResult return_code = vkCreateSwapchainKHR(this->D->m_device, &CI, nullptr, &this->SC);
            amVK_return_code_log( "vkCreateSwapchainKHR()" );     // above variable "return_code" can nott be named smth else
        }
    }
    
  3. amVK_Object/Instance-Creation

    amVK_SwapChain* amVK_SurfacePresenter::create_SwapChain(void);
    




  4. amVK_Object::Functions()

    amVK_SwapChain*   create_SwapChain(void);           // Creates amVK_Object
    amVK_RenderPass*  create_RenderPass(void);          // Creates amVK_Object
    void                      refresh_SurfCaps(void);   // SurfCapabilities changes if Window is Resized
    VkSurfaceCapabilitiesKHR* fetched_SurfCaps(void);   // Returns the REFRESHED/FETCHED element
    
    void            amVK_SwapChain::sync_SurfCaps(void);/** Refreshes & Syncs `SurfaceCapabilites` */
    void            amVK_SwapChain::konf_Images(
        VkFormat IF, 
        VkColorSpaceKHR CS, 
        VkImageUsageFlagBits IU, 
        bool autoFallBack = true
    )
    void            amVK_SwapChain::konf_Compositing(
        VkPresentModeKHR PM,
        amVK_CompositeClipping CC,
        VkCompositeAlphaFlagBitsKHR CA
    );
    void            amVK_SwapChain::konf_ImageSharingMode(VkSharingMode ISM);
    VkFormat        amVK_SwapChain::active_PixelFormat(void)                    {return CI.imageFormat;}
    VkColorSpaceKHR amVK_SwapChain::active_ColorSpace (void)                    {return CI.imageColorSpace;}
    
  5. VkObject Variables

    class amVK_Image {
      public:
        amVK_Device *D = nullptr;
        VkImage     vk_Image = nullptr;
        VkImageView vk_ImageView = nullptr;
    };
    
    class amVK_FrameBuffer {
      public:
        amVK_SurfacePresenter *PR = nullptr;       // Basically, Parent Pointer
        VkFramebuffer vk_FrameBuffer = nullptr;
    };
    
    class amVK_RenderPass {
      public:
        amVK_SurfacePresenter *PR = nullptr;       // Basically, Parent Pointer
        VkRenderPass vk_RenderPass = nullptr; 
    };
    
    class amVK_Surface {
      public:
        amVK_SurfacePresenter *PR = nullptr;   // Created in CONSTRUCTOR
        VkSurfaceKHR vk_SurfaceKHR = nullptr;   //     Set in CONSTRUCTOR
    }
    

Page-Break

5. amVK_RenderPass_Descriptors.hh

namespace amVK_RP_AttachmentDescription
{
        // Change .format before using
    inline VkAttachmentDescription ColorPresentation = {
        .format = VK_FORMAT_UNDEFINED,            // you should use the ImageFormat selected by the swapchain
        .samples = VK_SAMPLE_COUNT_1_BIT,         // We don't use multi sampling in this example
        .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,    // Clear this attachment at the start of the render pass
        .storeOp = VK_ATTACHMENT_STORE_OP_STORE,  
            // Keep its contents after the render pass is finished (for displaying it)
        .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,   
            // Similar to loadOp, but for stenciling (we don't use stencil here)
        .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, 
            // Similar to storeOp, but for stenciling (we don't use stencil here)
        .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 
            // Layout at render pass start. Initial doesn't matter, so we use undefined
        .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 
            // Layout to which the attachment is transitioned when the render pass is finished
            // As we want to present the color attachment, we transition to PRESENT_KHR
    };
};

#define amVK_RPADes amVK_RP_AttachmentDescription
#define amVK_RPARef amVK_RP_AttachmentReference
#define amVK_RPSDes amVK_RP_SubpassDescription
#define amVK_RPSDep amVK_RP_SubpassDependency
amVK_RenderPass *RP = PR->create_RenderPass_interface();
    amVK_RPADes::ColorPresentation.format = SC->CI.imageFormat;

    RP->AttachmentInfos .push_back(amVK_RPADes::ColorPresentation);
    RP->SubpassInfos    .push_back(amVK_RPSDes::ColorPresentation);
    RP->Dependencies    .push_back(amVK_RPSDep::ColorPresentation);

    RP->sync_Attachments_Subpasses_Dependencies();
    RP->CreateRenderPass();

6. REY_Utils.hh

  1. REY_Array
REY_ArrayDYN<VkDeviceQueueCreateInfo> Array = REY_ArrayDYN<VkDeviceQueueCreateInfo>(nullptr, 0, 0);
    // No MemoryAllocation by default 😊
    //      1. REY_ArrayDYN.initialize(10)
    //      2. REY_ARRAY_PUSH_BACK(Array) = your_QueueCI;        [not a function. but rather a preprocessor macro]




Chapter 7: 🛒 FrameBuffer [🍞🍅🥚🍗]

1. 🛠️ vkCreateFramebuffer()

2. 📦 VkFramebufferCreateInfo()



3. VkImageView .pAttachments





Chapter 8: CommandBuffer 📝

Rendering commands have to be Recorded in a CommandBuffer.
Only then the GPU can work on it 💁‍♀️.
That's the idea, since decades ago, so yeah, xD.

0. amVK wrap 🌯

    #include "amVK_Synchronization.hh"
    #include "amVK_CommandPoolMAN.hh"

        // TwT
        REY_LOG("");
        #define amVK_S amVK_Sync
        #define CPCF CommandPoolCreateFlags
    amVK_CommandPoolMAN*CPMAN = new amVK_CommandPoolMAN(D);
                        CPMAN->init_CMDPool_Graphics(amVK_S::CPCF::RecordBuffer_MoreThanOnce);
                        CPMAN->CreateCommandPool_Graphics(flags);
                        CPMAN->AllocateCommandBuffers1_Graphics(1);

    amVK_CommandBufferPrimary *CB = new amVK_CommandBufferPrimary(CPMAN->BUFFs1.Graphics[0]);

1. VkCommandPool

🛠️ VkCommandPoolCreateInfo

📦 vkCreateCommandPool()

📜 REY_DOCs

🧊 amVK 🔗 amVK_CommandPoolMAN.hh







2. VkCommandBuffer

🛠️ VkCommandBufferAllocateInfo

📦 vkAllocateCommandBuffers()

🧊 amVK 🔗 amVK_CommandPoolMAN.hh#L63





EntryNotFound (FileSystemError): Error: ENOENT: no such file or directory, open 'c:\Users\REY\Desktop\idk\amGHOST\amVK_Guide\P1\CH9.md'




Chapter 10: 📽️ So far, The result

#include "amGHOST_System.hh"
#include "amVK_Instance.hh"
#include "amVK_Device.hh"

#include "amGHOST_VkSurfaceKHR.hh"
#include "amVK_Surface.hh"

#include "amVK_SwapChain.hh"
#include "amVK_ColorSpace.hh"
#include "amVK_RenderPass.hh"
#include "amVK_RenderPass_Descriptors.hh"
#include "amVK_CommandPoolMAN.hh"

int main(int argumentCount, char* argumentVector[]) {
    REY::cout << "\n";

    // ------------------------- amGHOST ----------------------------
        amGHOST_System::create_system();

        amGHOST_Window *W = amGHOST_System::heart->new_window_interface();
        W->create(L"Whatever", 0, 0, 500, 600);
    // ------------------------- amGHOST ----------------------------

    REY_LOG("");
    REY_LOG("");
    // --------------------------- amVK -----------------------------
            REY_LOG("");
        amVK_Instance::EnumerateInstanceExtensions();
        amVK_Instance::EnumerateInstanceLayerProperties();
        amVK_Instance::addTo_1D_Instance_Layers_Enabled("VK_LAYER_KHRONOS_validation");
        amVK_Instance::addTo_1D_Instance_EXTs_Enabled("VK_KHR_surface");
        amVK_Instance::addTo_1D_Instance_EXTs_Enabled(amGHOST_System::get_vulkan_os_surface_ext_name());
        amVK_Instance::CreateInstance();

            REY_LOG("");
        VkSurfaceKHR  VK_S = amGHOST_VkSurfaceKHR::create_surface(W, amVK_Instance::vk_Instance);

            REY_LOG("");
        amVK_Instance::EnumeratePhysicalDevices();
        amVK_GPUProps  *GPUProps = amVK_InstanceProps::GetARandom_GPU();
                        GPUProps->GetPhysicalDeviceQueueFamilyProperties();
                        GPUProps->EnumerateDeviceExtensionProperties();
                        GPUProps->REY_CategorizeQueueFamilies();

        amVK_Device* D = new amVK_Device(GPUProps);
            D->addTo_1D_GPU_EXTs_Enabled("VK_KHR_swapchain");
            D->CreateDevice(1);
            D->GetDeviceQueues();
        
            REY_LOG("")
        amVK_Surface   *S  = new amVK_Surface(VK_S);
            S->GetPhysicalDeviceSurfaceInfo();
            S->GetPhysicalDeviceSurfaceCapabilitiesKHR();






        // --------------------------- SwapChain, RenderPass, FrameBuffers -----------------------------
            REY_LOG("")
        amVK_SwapChain *SC = new amVK_SwapChain(this->S, this->D);;
            SC->konf_ImageSharingMode(VK_SHARING_MODE_EXCLUSIVE);
            SC->konf_Images(
                amVK_IF::RGBA_8bpc_UNORM,   // VK_FORMAT_R8G8B8A8_UNORM
                amVK_CS::sRGB,              // VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
                amVK_IU::Color_Display      // VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
            );
            SC->konf_Compositing(
                amVK_PM::FIFO,              // VK_PRESENT_MODE_FIFO_KHR
                amVK_CC::YES,               // Clipping:- VK_TRUE
                amVK_TA::Opaque             // VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR
            );
            SC->sync_SurfCaps();            // refresh/fetch & set/sync ---> latest SurfCaps

            SC->CI.oldSwapchain     = nullptr;
            SC->CreateSwapChain();

        amVK_SwapChainIMGs *SC_IMGs = new amVK_SwapChainIMGs(this->SC);
            SC_IMGs->   GetSwapChainImagesKHR();
            SC_IMGs->CreateSwapChainImageViews();



        amVK_RenderPass *RP = new amVK_RenderPass(this->D);
            amVK_RPADes::ColorPresentation.format = SC->CI.imageFormat;

            RP->AttachmentInfos.push_back(amVK_RPADes::ColorPresentation);
            RP->SubpassInfos   .push_back(amVK_RPSDes::ColorPresentation);
            RP->Dependencies   .push_back(amVK_RPSDep::ColorPresentation);

            RP->sync_Attachments_Subpasses_Dependencies();
            RP->CreateRenderPass();

        amVK_RenderPassFBs *RP_FBs = PR->create_FrameBuffers_interface();
            RP_FBs->CreateFrameBuffers();
        // --------------------------- SwapChain, RenderPass, FrameBuffers -----------------------------



        amVK_CommandPoolMAN  *CPMAN = PR->create_CommandPoolMAN_interface();
                              CPMAN->init_CMDPool_Graphics();
                              CPMAN->CreateCommandPool_Graphics(amVK_Sync::CommandPoolCreateFlags::RecordBuffer_MoreThanOnce);
                              CPMAN->AllocateCommandBuffers1_Graphics(1);

        amVK_CommandBufferPrimary *CB = new amVK_CommandBufferPrimary(CPMAN->BUFFs1.Graphics[0]);
    // --------------------------- amVK -----------------------------
    REY_LOG("");
    REY_LOG("");


    // ------------------------- CleanUp & ExportJSON ----------------------------
        REY::cin.get();     // wait for terminal input
            amVK_InstancePropsEXPORT::Export_nilohmannJSON_EXT();
                destroy_everything_serially();         // Last Chapter, copy code from there
                W->m_amGHOST_VkSurface->destroy();
                amVK_Instance::DestroyInstance();
            W->destroy();
    // ------------------------- CleanUp & ExportJSON ----------------------------

    REY::cout << "\n";
}



Chapter 11: 🔮 Shader

Vertex Shader

#version 450

layout(location = 0) out vec3 fragColor;

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

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

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

Fragment Shader

#version 450

layout (location = 0) in vec3 fragColor;

layout (location = 0) out vec4 outColor;

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

Compiling & Loading

glslangValidator -V triangle.vert -o triangle.vert.spv
glslangValidator -V triangle.frag -o triangle.frag.spv

Stay Tuned, Adding more in this Chapter 💁‍♀️





Chapter 12: 🛠️ Pipeline

0. ℹ️ VkGraphicsPipelineCreateInfo


🧊 amVK wrap 🌯

    amVK_PipelineGRAPHICS* PLG = new amVK_PipelineGRAPHICS(RP_FBs);
        PLG->CreateGraphicsPipeline();

1. Pipeline Objects

🔗 amVK_Vertex.hh
🔗 amVK_GeoMetry.hh
🔗 amVK_PipelineGRAPHICS.cpp


Page-Break

3. VkPipelineLayout

  1. ℹ️ VkPipelineLayoutCreateInfo

  2. 📦 vkCreatePipelineLayout()





Chapter 13: RenderLoop 🖥️🎨

🌋 Vulkan wrap 🌯

    while(true) {
        vkAcquireNextImageKHR();

        vkResetCommandBuffer();     // req:- VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
        vkBeginCommandBuffer();
            vkCmdBeginRenderPass();
                vkCmdSetViewport();
                vkCmdSetScissor();
                vkCmdBindPipeline();
                    vkCmdDraw();
            vkCmdEndRenderPass();
        vkEndCommandBuffer();
        
        vkQueueSubmit();
        vkQueuePresentKHR();

        vkQueueWaitIdle();
        PROCESS_InputEvents();
        REY_NoobTimer::wait(10); // wait 10ms
    }

🧊 amVK wrap 🌯

    while(true) {
        W->dispatch_events_with_OSModalLoops();
        
        RP_FBs->RPBI_AcquireNextFrameBuffer();

        CB->BeginCommandBuffer(amVK_Sync::CommandBufferUsageFlags::Submit_Once);
        // ------------------------- CommandBufferRecording ----------------------------
            
            RP_FBs->CMDBeginRenderPass(CB->vk_CommandBuffer);
                RP_FBs->CMDSetViewport_n_Scissor(CB->vk_CommandBuffer);
                PLG->CMDBindPipeline(CB->vk_CommandBuffer);
                    VB.CMDDraw(CB->vk_CommandBuffer);
            RP_FBs->CMDEndRenderPass(CB->vk_CommandBuffer);
            
        // ------------------------- CommandBufferRecording ----------------------------
        CB->EndCommandBuffer();

        // This was Done Before in CH4 : SwapChain
            amVK_SurfacePresenter  *PR = new amVK_SurfacePresenter();
                                    PR->bind_Surface(S);
                                    PR->bind_Device(D);
        // This was Done Before in CH4 : SwapChain

        PR->set_CommandBuffer(CB->vk_CommandBuffer);
        PR->submit_CMDBUF(D->Queues.GraphicsQ(0));
        PR->Present(D->Queues.GraphicsQ(0));

        vkQueueWaitIdle(D->Queues.GraphicsQ(0));
        REY_NoobTimer::wait(10); // wait 10ms
    }

1. vkAcquireNextImageKHR()


1.1. Can you use 1 SwapChainIMG? 💁‍♀️

  1. 1 IMG Modes

    • VK_PRESENT_MODE_IMMEDIATE_KHR
      • You will see Tearing
      • vkAcquireNextImageKHR():- Returns VK_SUCCESS immediately (no synchronization).
    • VK_PRESENT_MODE_FIFO_RELAXED_KHR
      • If you submit frames slower than the display refresh rate, it might work with 1 image (but risky).
  2. Multi IMG Modes

    • VK_PRESENT_MODE_FIFO_KHR a.k.a VSync :- Needs ≥2 images (front + back buffer).
    • VK_PRESENT_MODE_MAILBOX_KHR (Triple buffering) :- Needs ≥3 images.
      • Some games will also flag this as VSync
  3. GPU Driver:-

    vkGetPhysicalDeviceSurfaceCapabilitiesKHR(...);
    // caps.minImageCount is often 2+ (driver may ignore your request when creating SwapChain)
    

1.2. vkQueueWaitIdle()

1.3. Synchronization


Page-Break

2. Command Recording I

  1. VkCommandBufferBeginInfo

    • https://vkdoc.net/man/VkCommandBufferBeginInfo

      • .sType 🟪 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
      • .pNext 🟪 nullptr
        • 🪐 VkDeviceGroupCommandBufferBeginInfo
      • .flags 🔠 VkCommandBufferUsageFlagBits
      • .pInheritanceInfo 🪐 [secondary command buffer]

    • 📜 REY_DOCs
      • Rendering commands have to be Recorded in a CommandBuffer.
      • Only then the GPU can work on it 💁‍♀️.
      • That's the idea, since decades ago, so yeah, xD.

    • 📜 REY_DOCs : There are a few ways that you can record CMDBUF
      1. Recording a VkCommandBuffer only Once

      2. Recording a VkCommandBuffer more than Once

        • more than Once --> requires, CMDBUF to be reset by vkResetCommandBuffer() before recording again
          • Note:- vkBeginCommandBuffer() also does do an implicit reset
          • which I don't believe should exist 💁‍♀️
          • I always believe "Explicit is better than implicit"
        • REQ:-
          • VkCommandPoolCreateInfo.flags 🟪 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT

      3. Submitting a VkCommandBuffer only Once

        • REQ:-
          • VkCommandBufferBeginInfo.flags 🟪 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
        • People usually uses SUBMIT_ONCE with a RESET_CMDBUF
      4. Implementing Synchronization features is so fked up. After Present Image, call vkQueueWaitIdle()

  2. VkRenderPassBeginInfo


Page-Break

2. Command Recording II

  1. vkBeginCommandBuffer()

    • https://vkdoc.net/man/vkBeginCommandBuffer
      • .commandBuffer 🟪 💁‍♀️
      • .pBeginInfo 🟪 💁‍♀️
    • </> TheCode
      amVK_CommandPool {
        public:
          REY_Array<VkCommandBuffer>      vk_CommandBuffers;
          REY_Array<VkCommandBuffer> AllocateCommandBuffers(void);
      
        public:
          VkCommandBufferBeginInfo BI = {
              .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
              .pNext = 0,
              .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
                  // People usually uses `SUBMIT_ONCE` with a `RESET_CMDBUF` & records CMDBUF every frame
              .pInheritanceInfo = nullptr
          };
          void BeginCommandBuffer(uint32_t CMDBUF_Index) {
              VkResult return_code = vkBeginCommandBuffer(vk_CommandBuffers[CMDBUF_Index], &BI);
              amVK_return_code_log( "vkBeginCommandBuffer()" );
          }
      }
      
  2. vkCmdBeginRenderPass()


  1. vkCmdSetViewport()

  1. vkCmdSetScissor()

  1. vkBindPipeline()

    • https://vkdoc.net/man/vkBindPipeline

      • .commandBuffer 🟪 💁‍♀️

    • 📜 REY_DOCs
      • Once we bind a pipeline, then we can call Draw()
      • After binding pipeline, is where you specify VertexBuffers
        • More on VertexBuffer 🟨 Chapter16
  2. vkCmdDraw()


  1. vkCmdEndRenderPass()

  2. vkEndCommandBuffer()


Page-Break

3. Submit Command Buffer & Present

  1. VkSubmitInfo

    • https://vkdoc.net/man/VkSubmitInfo
      • .sType 🟪 VK_STRUCTURE_TYPE_SUBMIT_INFO
      • .pNext 🪐 NULL
      • .pWaitSemaphores 🔗 Chapter9.1
        • 🟪 amVK_SwapChain::AcquireNextImage_SemaPhore
      • .pWaitDstStageMask 🟪 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
      • .pCommandBuffers 🟪 💁‍♀️
      • .pSignalSemaphores
        • 🟪 amVK_SurfacePresenter::RenderingFinished_SemaPhore

  2. vkQueueSubmit()

  3. vkGetDeviceQueue()

    • https://vkdoc.net/man/vkGetDeviceQueue
      • .device
      • .queueFamilyindex 🔗 Chapter2.7
        • amVK_Device::amVK_1D_QCIs::select_QFAM_Graphics()
      • .queueIndex 🔗 Chapter2.4
        • VkDeviceQueueCreateInfo.queueCount
      • .pQueue ↩️📦
  4. VkPresentInfoKHR

    • https://vkdoc.net/man/VkPresentInfoKHR
      • .sType 🟪 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR
      • .pNext 🪐 NULL
        • 🪐 Maybe some interesting extensions, idk
      • .pWaitSemaphores 🔗 Chapter9.6
        • 🟪 amVK_SwapChain::RenderingFinished_SemaPhore
      • .pSwapchains 🟪 💁‍♀️
      • .pImageIndices
      • .pResults

  5. vkQueuePresentKHR()

  6. Coloring Window
  7. 📽️ So far, The result 🔗 GITHUB

Page-Break

4. The RenderLoop

0. amVK wrap 🌯

    while(true) {
        W->dispatch_events_with_OSModalLoops();         // No way to disable ModalLoop so far in win32

        RP_FBs->RPBI_AcquireNextFrameBuffer();

        CB->BeginCommandBuffer(amVK_Sync::CommandBufferUsageFlags::Submit_Once);
        // ------------------------- CommandBufferRecording ----------------------------
            
            RP_FBs->CMDBeginRenderPass(CB->vk_CommandBuffer);
                RP_FBs->CMDSetViewport_n_Scissor(CB->vk_CommandBuffer);
                PLG->CMDBindPipeline(CB->vk_CommandBuffer);
                    VB.CMDDraw(CB->vk_CommandBuffer);
            RP_FBs->CMDEndRenderPass(CB->vk_CommandBuffer);
            
        // ------------------------- CommandBufferRecording ----------------------------
        CB->EndCommandBuffer();

        // This was Done Before in CH4 : SwapChain
            amVK_SurfacePresenter  *PR = new amVK_SurfacePresenter();
                                    PR->bind_Surface(S);
                                    PR->bind_Device(D);
        // This was Done Before in CH4 : SwapChain

        PR->set_CommandBuffer(CB->vk_CommandBuffer);
        PR->submit_CMDBUF(D->Queues.GraphicsQ(0));
        PR->Present(D->Queues.GraphicsQ(0));

        vkQueueWaitIdle(D->Queues.GraphicsQ(0));
        REY_NoobTimer::wait(10); // wait 10ms
    }

5. Synchronization & SemaPhores

VkSemaphore 🟨 ChapterZZZ

  1. VkSemaphoreCreateInfo

  2. vkCreateSemaphore


🟪 eXtras / neXt chapters









Chapter 14: Handling OS 🖱️ InputEvents 🕹️

we are gonna take an backwards unfolding approach here

1. 📨 dispatch_events

  • amGHOST StackTrace [Surface ---> Deep]
    amGHOST:- lets your headache dissappear about OS::Stuffs/Functions
    
    1. amGHOST_Window     ::dispatch_events_with_OSModalLoops()     🔗[github][1]
    2. amGHOST_WindowWIN32::dispatch_events_with_OSModalLoops()     🔗[github][2] 
    3. amGHOST_System     ::dispatch_events_with_OSModalLoops()     🔗[github][3]
    4. amGHOST_SystemWIN32::dispatch_events_with_OSModalLoops()     🔗[github][4]
    5. amGHOST_SystemWIN32.cpp::actual_implementaion                🔗[github][5]
    


Page-Break

2. win32 🖥️

  1. General Info ℹ️
    1. ::CreateWindowA()
      • Every win32 window needs a WNDCLASSA during ::CreateWindowA() 🌱 \
      • Window gets bound to the calling/creating thread as owner thread
    2. ::Peek/Get/DispatchMessage()
      • does not peek/get/dispatch messages of windows from other threads
    3. WNDCLASSA.lpfnWndProc 🔗
      • Binds the window to a static WndProc() ⚙️
    4. static WndProc()

3. ModalLoop 🔄


ModalLoop 🔄 : win32

  1. FAQ❓

    • Exactly where does the ModalLoop gets Trigger? 🎬

      • When we pass WM_SYSCOMMAND to ::DefWindowProc()

    • WM_LBUTTONDOWN vs WM_NCLBUTTONDOWN 🖱️

      • Pressing mouse on OS-Window Frame/Corner/Border ➡️ sends WM_NCLBUTTONDOWN (not WM_LBUTTONDOWN)
      • NC = Non-Client 🏷️
      • LBUTTON = Left Mouse Button
    • What if we ignore WM_NCLBUTTONDOWN?

      • WM_SYSCOMMAND won’t generate!
      • Must call ::DefWindowProc() on WM_NCLBUTTONDOWN
      • Passing This one to ::DefWindowProc() is exactly how the OS internally keeps track of MouseButtonDown 💁‍♀️

    • When does WM_ENTERSIZEMOVE occur? 🔄

      • When you call ::DefWindowProc() with WM_SYSCOMMAND
    • ModalLoop starts on passing WM_SYSCOMMAND or WM_ENTERSIZEMOVE? 🤔

      • I believe, it's WM_SYSCOMMAND [gotta test 🧪]

    • If, WM_SYSCOMMAND starts the ModalLoop, why'd we even catch WM_ENTERSIZEMOVE in our static WndProc()?

      • Well, it's because, win32 wanted us to catch all those events, but still wanted us to call ::DefWindowProc() on those


ModalLoop 🔄 : xlib


ModalLoop 🔄 : summary


Page-Break

4. Resizing ↔️

5. Window Creation & Destruction

  1. amGHOST Events <-- (Win32/XCB/X11/Wayland/macOS)
    1. EventTypes




Chapter 15: Resizing & SwapChain Recreation

🌋 Vulkan wrap 🌯

void reSize(void) {
     RP_FBs->DestroyFrameBuffers();
    SC_IMGs->DestroySwapChainImageViews();

    SC->reCreateSwapChain();        // calls --> sync_SurfCaps();

    SC_IMGs->GetSwapChainImagesKHR();
    SC_IMGs->CreateSwapChainImageViews();
     RP_FBs->CreateFrameBuffers();
}

🧊 amVK wrap 🌯

amGHOST_SwapChainResizer* SC_Resizer = new amGHOST_SwapChainResizer(RP_FBs, W);




Chapter 16: Multi-Threading

0. amVK wrap 🌯

// ------------------------- Render Loop -------------------------
amTHREAD phoenix;
phoenix.run([&]() {
    REY_LOG("Thread started.");

    while(true) {
        RP_FBs->RPBI_AcquireNextFrameBuffer();
        // ------------------------- CommandBufferRecording -------------------------
        // -------------------------    Submit & Present    -------------------------
        vkQueueWaitIdle(D->Queues.GraphicsQ(0));
        REY_NoobTimer::wait(10); // wait 10ms
    }

    REY_LOG("Thread finished.");
});

while(true) {
    W->dispatch_events_with_OSModalLoops(); // dispatch events
    REY_NoobTimer::wait(1);               // wait 100ms
}
// ------------------------- Render Loop -------------------------











Chapter 17: Vertex 📍 & VertexBuffer 🗄️

1. Mesh/Vertices

  1. amVK_Vertex

    struct amVK_Vertex {
        float position[3];
        float color[4];
    };
    
  2. Vertex Buffer


  3. VkBufferCreateInfo

  4. vkCreateBuffer()

  5. 📽️ So far, The result:- CH11.1.VertexBuffer.hh


Page-Break

2. A lesson in Memory

https://www.youtube.com/watch?v=uXgKXfVMeFw

(obviously i am not talking about Vulkan / Implementation Programming)
(i am talking about Algorithms/CP/CodeForces/MIT6.046)



  1. vkGetBufferMemoryRequirements()

  2. VkMemoryRequirements

  3. .memoryTypeIndex | VkPhysicalDeviceMemoryProperties

  4. VkPhysicalDeviceFeatures

  5. 📽️ So far, The result

    class amVK_InstanceProps {
        static       void GetPhysicalDeviceFeatures(void);               // amVK_1D_GPUs_Features
        static       void GetPhysicalDeviceMemoryProperties(void);       // amVK_1D_GPUs_MEMProps
    
        static inline REY_Array<VkPhysicalDeviceFeatures>                   amVK_1D_GPUs_Features;
        static inline REY_Array<VkPhysicalDeviceMemoryProperties>           amVK_1D_GPUs_MEMProps;
    }
        // The other one is copy of this one
    void amVK_InstanceProps::GetPhysicalDeviceFeatures(void) {
        amVK_1D_GPUs_Features.reserve(amVK_1D_GPUs.n);
        amVK_LOOP_GPUs(k) {
            vkGetPhysicalDeviceFeatures(amVK_1D_GPUs[k], &amVK_1D_GPUs_Features[k]);
        }
        called_GetPhysicalDeviceFeatures = true;
    }
    

  6. 👀 Visualization / [See it] / JSON Printing:- 🔗 GITHUB amVK_InstancePropsExport_nlohmann.cpp#L1-L117

  7. REY_CategorizeMemoryHeaps() 🔗 GITHUB amVK_GPUProps.cpp#L56-264

    • Just Copy-Paste this one yk....
    • I Believe, the tags that I Created for this one, Vulkan should have given us those by default 🥴💁‍♀️
  8. Refactoring is pretty smooth now, I did it again, in this commit 🥴 🔗 GITHUB


  9. VkMemoryAllocateInfo

    • https://vkdoc.net/man/VkMemoryAllocateInfo
      • This documentation page is pretty big 😶‍🌫️
      • .sType 🟪 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
      • .pNext 🪐 nullptr
        • 🪐 interesting extensions
      • .allocationSize 🟪 VkMemoryRequirements.size
      • .memoryTypeIndex 🏷️ uint32_t

  10. vkAllocateMemory()

  11. </> TheCode

    void amVK_VertexBuffer::AllocateMemory(void) {
        if(called_GetBufferMemoryRequirements == false) {
            this->GetBufferMemoryRequirements();
        }
        if (this->D->GPU_Props->called_REY_CategorizeMemoryHeaps == false) {
            this->D->GPU_Props->       REY_CategorizeMemoryHeaps();
        }
            AI.allocationSize  = vk_MemoryReq.size;
            AI.memoryTypeIndex = this->D->GPU_Props->MEMTypeID.CPU_GPU_Synced;
    
        VkResult return_code = vkAllocateMemory(this->D->vk_Device, &AI, nullptr, &this->vk_DeviceMemory);
        amVK_return_code_log( "vkAllocateMemory()" );
    }
    
  12. vkMapMemory()

  13. vkUnmapMemory()

  14. vkBindBufferMemory()

  15. </> TheCode

    void      amVK_VertexBuffer::MapMemory(void) {
        VkResult return_code = vkMapMemory(D->vk_Device, vk_DeviceMemory, 0, vk_MemoryReq.size, 0, &vk_MappedMemoryData);
        amVK_return_code_log( "vkMapMemory()" );
    }
    void   amVK_VertexBuffer::CopyIntoMemory(void) {
        REY_memcpy(vk_MappedMemoryData, Vertices.data, CI.size);
    }
    void      amVK_VertexBuffer::UnMapMemory(void) {
        vkUnmapMemory(D->vk_Device, vk_DeviceMemory);
    }
    void      amVK_VertexBuffer::BindBufferMemory(void) {
        VkResult return_code = vkBindBufferMemory(D->vk_Device, vk_Buffer, vk_DeviceMemory, 0);
        amVK_return_code_log( "vkBindBufferMemory()" );
    }
    




Chapter 18: ImageRendering / TextureBuffer





Chapter 19: Grab/Translate/Rotate/Scale & 3D Camera





Chapter 20: Handling OS 🖱️ InputEvents 🕹️ II

// WIP //

6. amVK_SurfacePresenter

Can't have everything scatterred now, everything is getting too much sophisticating.... 🤔 🤦‍♀️ must Refactor....

Major Decision Change

Right now, amVK_Surface::CTOR creates amVK_SurfacePresenter. & SwapChain, RenderPass, CommandPool are supposed to be created from amVK_SurfacePresenter.

class amVK_Surface
    amVK_SurfacePresenter {
        create_SwapChain_interface()
            new amVK_SwapChain(this)
                this->CI.surface = PR->S->vk_SurfaceKHR;
                // later amVK_SwapChain::CreateSwapChain(void) uses this->PR->D->vk_Device
        create_RenderPass_interface()
            new amVK_RenderPass(this)
                this->PR = PR;
        create_CommandPool_interface()
            new amVK_CommandPool(this)
                this->CI.queueFamilyIndex = this->PR->D->amVK_1D_QCIs.ptr_Default()->queueFamilyIndex;
        create_FrameBuffers()
            new amVK_FrameBuffer(this)
                this->CI.renderPass = this->PR->RP->vk_RenderPass;

Problem #1:- I think this is just a little too much deep to handle....
Problem #2:- if amVK_SwapChain.hh included amVK_SurfacePresenter.hh, then the reverse can't happen. 💁‍♀️
Thus a lot of 1-liner functions would have to be put inside .cpp even tho i don't want it to.

  1. Problem #2:- in Details

    • amVK_SurfacePresenter.hh#L37
    • amVK_SwapChain.hh#L48
    • The Solution
      • C1:- Don't include amVK_SurfacePresenter.hh in amVK_SwapChain.hh but rather inside amVK_SwapChain.cpp
      • C2:- Don't include amVK_SwapChain.hh in amVK_SurfacePresenter.hh but rather inside amVK_SurfacePresenter.cpp
    • Case 1:-
      • amVK_SwapChain::CONSTRUCTOR
      • sync_SurfCaps()
      • both of these have to go inside amVK_SwapChain.cpp
    • Case 2:-
      • amVK_SurfacePresenter::sync_SC_SurfCaps()
      • amVK_SurfacePresenter::synced_ImageExtent()
      • both of these (& as of my plan right now, heck ton of other 1 liner function) are gonna have to go inside amVK_SurfacePresenter.cpp
  2. Weeelll

    • There is one other solution.... That is to change the design.... Which is what I figured is should do.... Not everybody would want to use amVK_SurfacePresenter anyway 💁‍♀️
    • 2 Ways:-
    1. Making amVK_SurfacePresenter Optional
      1. None of the other amVK_Class is gonna depend on this anymore
      2. amVK_SurfacePresenter serving as like a top level NODETREE system with extra PRESET Functions / soo. (If you are looking from a NodeEditor perspective)
      3. This is like having a BIG BAD NODE, and then connecting everything into it
      4. You can have anything you want in the header
      5. Let's try the other one and see what happens
    2. Making amVK_SurfacePresenter Code part
      1. EveryBody is gonna depend on this
      2. They are only gonna keep a pointer to this parent
      3. from this one, they are gonna get everything that they need
      4. even the VkDevice
      5. It's like having all the nodes inside a TOP LEVEL FRAME NODE
      6. Separating Code into .hh & .cpp is kinda crazy..... You basically can't have anything in the header....
      7. i already tried this


📽️ So far, The result [🔗 GITHUB]




Page-Break

10. Windows WndProc

SCREENSHOT1

Feature WM_PAINT WM_PRINT
Purpose Sent by the system to request that a window redraw its client area. Sent by an application to request that a window draw itself into a specified device context (e.g., for printing or capturing).
Trigger Automatically triggered by the system when the client area becomes invalid (e.g., resizing, minimizing). Explicitly sent by an application using SendMessage to request the window to draw itself.
Message ID 0x800F 0x0317
Who Sends It Sent by the system. Sent by the application (e.g., using SendMessage(hwnd, WM_PRINT, ...)).
Default Behavior Calls the window's WndProc to handle the redraw. Calls the window's WndProc to handle the drawing into the specified device context.
Device Context Uses the device context provided by BeginPaint and EndPaint. Uses the device context passed in wParam.
Use Case Used for normal window redrawing (e.g., after invalidation or resizing). Used for off-screen rendering, printing, or capturing the window's content.
System-Generated Yes, automatically generated when the client area is invalid. No, must be explicitly sent by the application.
Parameters - wParam: Not used.
- lParam: Not used.
- wParam: Handle to the device context (HDC).
- lParam: Flags specifying what to draw.
Flags in lParam Not applicable. Flags include:
- PRF_CHECKVISIBLE: Only draw if the window is visible.
- PRF_CHILDREN: Draw child windows.
- PRF_CLIENT: Draw the client area.
- PRF_NONCLIENT: Draw the non-client area.
- PRF_ERASEBKGND: Erase the background.
Child Windows Does not automatically draw child windows. Can optionally draw child windows if the PRF_CHILDREN flag is set.
Non-Client Area Does not draw the non-client area (e.g., title bar, borders). Can optionally draw the non-client area if the PRF_NONCLIENT flag is set.
Example Usage Used in the WndProc to handle normal window painting. Used for capturing the window's content into a bitmap or for printing.

Screenshot2
alt text
alt text

classDiagram class WM_PAINT { <<Message>> Purpose: "Request window redraw (client area)" Trigger: "System (automatic)" MessageID: "0x800F" DefaultBehavior: "Calls WndProc" DeviceContext: "BeginPaint/EndPaint" UseCase: "Normal window redrawing" Parameters: "wParam/lParam unused" ChildWindows: "No" NonClientArea: "No" } class WM_PRINT { <<Message>> Purpose: "Request window draw into HDC" Trigger: "Application (manual)" MessageID: "0x0317" DefaultBehavior: "Calls WndProc" DeviceContext: "HDC in wParam" UseCase: "Printing/capturing" Parameters: "wParam: HDC \n lParam: Flags \n (PRF_CHECKVISIBLE, PRF_CHILDREN...)" ChildWindows: "Optional (PRF_CHILDREN)" NonClientArea: "Optional (PRF_NONCLIENT)" } WM_PAINT --|> SystemGenerated WM_PRINT --|> ApplicationGenerated