Рамочное приложение Vulkan на MASM x64

Тема в разделе "Vulkan", создана пользователем ml64, 9 май 2026 в 22:17.

  1. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    33
    Долго тема стояла пустая. Попробую расшевелить - может, что получится.
    Почему тема оставалась нетронутой - понятно: Vulkan - это кроссплатформенная библиотека, по сути, набор API-функций.
    Разработчик (в широком смысле) волен выбирать, на каком языке вызывать API-функции,
    и язык ассемблера для этого - не самый удобный инструмент, а идея кроссплатформенности теряется.
    За основу берём код с сайта vulkan-tutorial.com. И здесь сразу наблюдаем курьёз: на заглавной странице этого сайта честно говорится:
    А vulkan.org отправляет обратно:
    Вот этому руководству и будем следовать. Задача насколько амбициозная, настолько же и бессмысленная, но ассемблер - это дзен, а для самурая, как известно, путь важнее цели
     
    Последнее редактирование: 11 май 2026 в 05:56
    aa_dav и Mikl___ нравится это.
  2. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    2.175
    Наверное стоило качать СДК, а не туториал.
     
  3. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    33
    Шаг 1. Создаём оконное приложение
    Исходный код на С++ показывает, насколько автор мыслит категориями ООП.
    Даже само приложение - это класс.
    Код (C++):
    1. //https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Base_code
    2. #define GLFW_INCLUDE_VULKAN
    3. #include <GLFW/glfw3.h>
    4.  
    5. #include <iostream>
    6. #include <stdexcept>
    7. #include <cstdlib>
    8.  
    9. const uint32_t WIDTH = 800;
    10. const uint32_t HEIGHT = 600;
    11.  
    12. class HelloTriangleApplication {
    13. public:
    14.     void run() {
    15.         initWindow();
    16.         initVulkan();
    17.         mainLoop();
    18.         cleanup();
    19.     }
    20.  
    21. private:
    22.     GLFWwindow* window;
    23.  
    24.     void initWindow() {
    25.         glfwInit();
    26.  
    27.         glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    28.         glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
    29.  
    30.         window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
    31.     }
    32.  
    33.     void initVulkan() {
    34.  
    35.     }
    36.  
    37.     void mainLoop() {
    38.         while (!glfwWindowShouldClose(window)) {
    39.             glfwPollEvents();
    40.         }
    41.     }
    42.  
    43.     void cleanup() {
    44.         glfwDestroyWindow(window);
    45.  
    46.         glfwTerminate();
    47.     }
    48. };
    49.  
    50. int main() {
    51.     HelloTriangleApplication app;
    52.  
    53.     try {
    54.         app.run();
    55.     } catch (const std::exception& e) {
    56.         std::cerr << e.what() << std::endl;
    57.         return EXIT_FAILURE;
    58.     }
    59.  
    60.     return EXIT_SUCCESS;
    61. }
    ООП - это прекрасно. Но (в данном конкретном случае) для ассемблера этот подход не годится, т.к. содержит слишком много лишних переходов,
    что усложняет восприятие и в редакторе, и в дебаггере.
    Упрощаем:
    Код (C):
    1. #define GLFW_INCLUDE_VULKAN
    2. #include <GLFW/glfw3.h>
    3.  
    4. #include <iostream>
    5. #include <stdexcept>
    6. #include <cstdlib>
    7.  
    8. GLFWwindow* window;
    9.  
    10. int main() {
    11. //initWindow();
    12.         glfwInit();
    13.         glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    14.         glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
    15.         window = glfwCreateWindow(800, 600, "Vulkan", nullptr, nullptr);
    16. //initVulkan();
    17.     //TODO
    18. //mainLoop();
    19.     while (!glfwWindowShouldClose(window)) { glfwPollEvents(); }
    20. //cleanup();
    21.     glfwDestroyWindow(window);
    22.     glfwTerminate();
    23.     return 0;
    24. }

    Вот теперь у нас есть стройная последовательность вызовов. Переводим:
    Код (ASM):
    1. ;100_base_code.asm
    2. option casemap:none
    3. option prologue:none
    4. option epilogue:none
    5.  
    6. ;Standard Libraries
    7. includelib D:\bin\dev\asm\ml64\VS2019\lib\user32.lib
    8. includelib D:\bin\dev\asm\ml64\VS2019\lib\kernel32.lib
    9. ;GLFW
    10. includelib D:\bin\dev\ogl\glfw-3.4.bin.WIN64\lib-vc2022\glfw3dll.lib
    11.  
    12. ;WinMain
    13. extrn glfwInit:PROC
    14. extrn glfwWindowHint:PROC
    15. extrn glfwCreateWindow:PROC
    16. extrn glfwWindowShouldClose:PROC
    17. extrn glfwPollEvents:PROC
    18. extrn glfwDestroyWindow:PROC
    19. extrn glfwTerminate:PROC
    20. extrn ExitProcess:PROC
    21.  
    22. .data
    23. hWnd dq 0
    24. szAppTitle db "Vulkan", 0
    25.  
    26. .code
    27. WinMain proc
    28.  
    29. ;Prologue:
    30. push rbp
    31. mov rbp,rsp
    32.  
    33. and rsp,-16 ;Align the Stack
    34. sub rsp,100h ;Create the Buffer
    35.  
    36. call glfwInit
    37. test rax,rax
    38. jz lbl_WinMain_Err
    39.  
    40. mov rcx,22001h; GLFW_CLIENT_API
    41. xor rdx,rdx ;GLFW_NO_API = 0
    42. call glfwWindowHint
    43.  
    44. mov rcx,20003h ;GLFW_RESIZABLE
    45. xor rdx,rdx ;GLFW_FALSE = 0
    46. call glfwWindowHint
    47.  
    48. mov rcx,3C0h ;1920/2=960
    49. mov rdx,21Ch ;1080/2=540
    50. lea r8,szAppTitle
    51. xor r9,r9
    52. mov qword ptr[rsp+20h],0 ;share = NULL
    53. call glfwCreateWindow
    54. mov hWnd,rax
    55. test rax,rax
    56. jz lbl_WinMain_Err
    57.  
    58. lbl_WinMain_Loop:
    59. mov rcx,hWnd
    60. call glfwWindowShouldClose
    61. test rax,rax
    62. jnz lbl_WinMain_CleanUp
    63. call glfwPollEvents
    64. jmp lbl_WinMain_Loop
    65.  
    66. lbl_WinMain_CleanUp:
    67. mov rcx,hWnd
    68. call glfwDestroyWindow
    69. call glfwTerminate
    70. xor rcx,rcx
    71. call ExitProcess
    72.  
    73. lbl_WinMain_Err:
    74. call glfwTerminate
    75. mov rcx,1
    76. call ExitProcess
    77.  
    78. WinMain endp
    79.  
    80. ;include procedures
    81.  
    82. end
    Хорошо. Делаем батник:
    Код (Text):
    1. @echo off
    2.  
    3. set AppName=100_base_code
    4. set BinPath=D:\bin\dev\asm\ml64\VS2019\bin
    5.  
    6. if exist %AppName%.obj del %AppName%.obj
    7. if exist %AppName%.exe del %AppName%.exe
    8.  
    9. %BinPath%\ml64 /c /Fo %AppName%.obj %AppName%.asm
    10. %BinPath%\link.exe %AppName%.obj /ENTRY:WinMain /SUBSYSTEM:WINDOWS
    11.  
    12. del %AppName%.obj
    13.  
    14. dir %AppName%.*
    15.  
    16. pause
    Скачиваем актуальную библиотеку GLFW. Надо брать актуальные файлы glfw3dll.lib и glfw3.dll.
    Важный момент: библиотека glfw3.dll должна лежать в папке, где будет лежать наш исполняемый файл 100_base_code.exe, иначе приложение не запустится.

    Результат Шага 1 должен быть таким:
    100_base_code.jpg




    Шаг 2. Собственно вулкан. Создаём экземпляр Vulkan (или как там переводится Vulkan Instance?)
    В класс приложения добавляется метод initVulkan(), содержащий пока одну функцию createInstance() следующего содержания:
    Код (C++):
    1.     void createInstance() {
    2.         VkApplicationInfo appInfo{};
    3.         appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
    4.         appInfo.pApplicationName = "Hello Triangle";
    5.         appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
    6.         appInfo.pEngineName = "No Engine";
    7.         appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
    8.         appInfo.apiVersion = VK_API_VERSION_1_0;
    9.  
    10.         VkInstanceCreateInfo createInfo{};
    11.         createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    12.         createInfo.pApplicationInfo = &appInfo;
    13.  
    14.         uint32_t glfwExtensionCount = 0;
    15.         const char** glfwExtensions;
    16.         glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
    17.  
    18.         createInfo.enabledExtensionCount = glfwExtensionCount;
    19.         createInfo.ppEnabledExtensionNames = glfwExtensions;
    20.  
    21.         createInfo.enabledLayerCount = 0;
    22.  
    23.         if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
    24.             throw std::runtime_error("failed to create instance!");
    25.         }

    Для нас это означает, что надо объявить две структуры: VkApplicationInfo и VkInstanceCreateInfo, -
    добавить их экземпляры в секцию данных и заполнить в секции кода.
    Попутно надо вызвать функцию glfwGetRequiredInstanceExtensions,
    а по итогу вызвать vkCreateInstance и для этого подключить библиотеку vulkan-1.lib.
    Она находится в составе SDK, о котором говорил коллега выше. Скачивать SDK надо на сайте LunarG.

    Получится что-то вроде этого:
    Код (ASM):
    1. ;createInstance.asm
    2. createInstance proc
    3.  
    4. ;Prologue
    5. push rbp
    6. mov rbp,rsp
    7.  
    8. and rsp,-16 ;Align the Stack
    9. sub rsp,100h ;Create the Buffer
    10.  
    11. ;Fill the VkApplicationInfo Structure
    12. mov appInfo.sType,0 ;VK_STRUCTURE_TYPE_APPLICATION_INFO
    13. mov appInfo.pNext,0 ;nullptr
    14. lea rax,sz_AppName
    15. mov appInfo.pApplicationName,rax
    16. mov appInfo.applicationVersion,1
    17. lea rax,sz_EngineName
    18. mov appInfo.pEngineName,rax
    19. mov appInfo.engineVersion,1
    20. ;VK_API_VERSION_1_0 == ((((uint32_t)(0)) << 29U) | (((uint32_t)(1)) << 22U) | (((uint32_t)(0)) << 12U) | ((uint32_t)(0)));
    21. mov appInfo.apiVersion,400000h
    22.  
    23. ;Fill the VkInstanceCreateInfo Structure
    24. mov createInfo.sType,1 ;VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
    25. mov createInfo.pNext,0 ;nullptr
    26. mov createInfo.flags,0
    27. lea rax,appInfo
    28. mov createInfo.pApplicationInfo,rax
    29. mov createInfo.enabledLayerCount,0 ;Temporarily 0
    30. mov createInfo.ppEnabledLayerNames,0 ;Temporarily nullptr
    31. lea rcx,glfwExtensionCount ;Load Address
    32. call glfwGetRequiredInstanceExtensions
    33. ;mov glfwExtensions,rax
    34. mov createInfo.ppEnabledExtensionNames,rax ;glfwExtensions
    35. mov ecx,glfwExtensionCount ;Load Value
    36. mov createInfo.enabledExtensionCount,ecx
    37.  
    38. lea rcx,createInfo
    39. xor rdx,rdx
    40. lea r8,ghVkInstance
    41. call vkCreateInstance
    42. test rax,rax
    43. jne lbl_createInstance_Err ;!= VK_SUCCESS
    44. jmp lbl_createInstance_Return0
    45.  
    46. lbl_createInstance_Err:
    47. xor rcx,rcx
    48. lea rdx,sz_createInstance_Err ;Failed to create a vk Instance!
    49. lea r8,sz_createInstance ;MessageBox Title
    50. mov r9,30h ;MB_OK|MB_ICONEXCLAMATION
    51. call MessageBoxA
    52. mov rax,-1
    53. jmp lbl_createInstance_End
    54.  
    55. lbl_createInstance_Return0:
    56. xor rax,rax
    57.  
    58. lbl_createInstance_End:
    59. ;Epilogue
    60. leave
    61. ret
    62. createInstance endp
     

    Вложения:

    Последнее редактирование модератором: 10 май 2026 в 02:24
    Research и Mikl___ нравится это.
  4. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    646
    ml64,

    Обьясните плз что это и зачем нужно.

    Судя по коду это скрипт, генератор из г&п.
    Это виртуальная машина?, нет, тогда что??

    Код (Text):
    1. call glfwWindowShouldClose
    2. test rax,rax
    3. jnz lbl_WinMain_CleanUp
    4. call glfwPollEvents
    Что вы курите ?
     
  5. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    33
    Курим исключительно мануалы.
    Автор мануала Alexander Overvoorde придерживается общей идеологии Kronos и LunarG, в которой реализованы как OpenGL, так и Vulkan,
    а именно: максимально возможной кроссплатформенности при низкоуровневом управлении аппаратной частью.
    Поэтому для создания оконного приложения он использует кроссплатформенную библиотеку GLFW, что не является обязательным.
    Можно создать окно без библиотек на голом API/ABI.
    Но автор выбрал GLFW, а я решил проверить, как его решение работает с MASM, поэтому окно рисуется четырьмя функциями:
    Код (C):
    1. glfwInit();
    2. glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    3. glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
    4. window = glfwCreateWindow(800, 600, "Vulkan", nullptr, nullptr);
    Основной цикл приложения - это две функции:
    Код (C):
    1. while (!glfwWindowShouldClose(window)) { glfwPollEvents(); }
    И завершение приложения:
    Код (C):
    1. glfwDestroyWindow(window);
    2. glfwTerminate();
    На втором шаге к этому приложению добавляется собственно библиотека Vulkan. Экземпляр контекста Vulkan создаётся в методе createInstance():
    Код (C):
    1. vkCreateInstance(&createInfo, nullptr, &instance);
    На третьем шаге добавляется мессенджер VK. Серьёзно. Это делается так:
    Код (C++):
    1. void setupDebugMessenger() {
    2. VkDebugUtilsMessengerCreateInfoEXT createInfo;
    3. populateDebugMessengerCreateInfo(createInfo);
    4. CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) ; }
     

    Вложения:

    • Шаг2.zip
      Размер файла:
      2,3 КБ
      Просмотров:
      8
    • Шаг1.zip
      Размер файла:
      12,5 КБ
      Просмотров:
      9
    Последнее редактирование: 10 май 2026 в 21:00
    Mikl___ и Research нравится это.
  6. R81...

    R81... Active Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    187
    !!! Подход весьма поддерживаю, но исполнение...
    Код (ASM):
    1. ....
    2. call vkCreateInstance
    3. test rax,rax
    4. ;jne lbl_createInstance_Err ;!= VK_SUCCESS
    5. ;jmp lbl_createInstance_Return0
    6.  jz lbl_createInstance_End
    7.  
    8. ;!= VK_SUCCESS
    9. ;lbl_createInstance_Err:
    10. xor rcx,rcx
    11. lea rdx,sz_createInstance_Err ;Failed to create a vk Instance!
    12. lea r8,sz_createInstance ;MessageBox Title
    13. mov r9,30h ;MB_OK|MB_ICONEXCLAMATION
    14. call MessageBoxA
    15. mov rax,-1
    16. ;В x64 не знаю,
    17. ;а в x31? не:
    18. ;Mov eAx,-1
    19. ;а:
    20. ;Or eAx,-1
    21. ;- это уже конечно не экономия памяти,
    22. ;а показатель собранности и аккуратности
    23. ;низкоуровнего программирования.
    24. ;jmp lbl_createInstance_End
    25.  
    26. ;lbl_createInstance_Return0:
    27. ;xor rax,rax ; при jz lbl_createInstance_End он и так уже 0
    28.  
    29. lbl_createInstance_End:
    30. ;Epilogue
    31. leave
    32. ret
    33. createInstance endp
    1 вместо 6 возможно это
    имеелось ввиду?
     
    ml64 нравится это.
  7. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    33
    Соглашусь: mov rax,-1 выглядит топорно.

    Но тут масштаб задачи такой, что это простительно.
    Собранность и аккуратность здесь в другом проявляются.

    Например, надо сравнить два массива строковых переменных (не две строки, а два массива разной длины!),
    причём один массив - это последовательность буферов:
    Код (ASM):
    1. sz_validationLayer0 db 'VK_LAYER_KHRONOS_validation',0
    2. sz_validationLayer1 db 'Validation_Layer_1',0
    3. gpValidationLayers dq offset sz_validationLayer0
    а другой массив - это последовательность экземпляров структуры, количество которых программа получает динамически:
    Код (ASM):
    1. VkLayerProperties struct
    2. layerName db 256 dup(0) ;char[256]
    3. specVersion dd 0 ;VkVersion
    4. implementationVersion dd 0 ;VkVersion
    5. description db 256 dup(0) ;char[256]
    6. VkLayerProperties ends
    Как-то вот так:
    Код (C++):
    1. for (const char* layerName : validationLayers) {
    2.     bool layerFound = false;
    3.     for (const auto& layerProperties : availableLayers) {
    4.         if (strcmp(layerName, layerProperties.layerName) == 0) {
    5.             layerFound = true;
    6.             break;
    7.         }
    8.     }
    9.     if (!layerFound) {
    10.         return false;
    11.     }
    12. }
    13. return true;
    Для ассемблера важна каждая инструкция. Это понимают все, кто проводил ночи в дебаггере в поисках какой-нибудь переменной не того размера. Или целочисленного аргумента, который Kronos решил передавать через xmm.
    Но тут, как говорится, потом напильником доработаем, иначе в конечное время задачу не решим

    Шаг 3. Слои валидации и отладочный мессенджер

    Сразу скажу: вышеуказанное сравнение строк я ниасилил.
    Мне сейчас больше интересен сам Вулкан.
    Там, оказывается, чуть ли не своя операционная система.
    Реализован свой мессенджер, который реагирует на ошибки.
    Например, если (по рекомендации туториала) закомментировать функцию очистки, то перед выходом Вулкан поругается.
    Причём есть возможность направлять сообщения и в консоль, и в лог, и в MessageBox:
    Шаг3.jpg
     

    Вложения:

    Последнее редактирование модератором: 11 май 2026 в 12:07
  8. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    591
    Строго говоря этот код и не является ООП-нутым. Код классами, но без ООП. Если можно код с классами превратить в код со структурами просто переделав все методы на свободные функции принимающие первый параметр указатель на экземпляр класса, то это не ООП, а обычное процедурное программирование с синтаксическим сахаром классов.
    Не получится сделать такое преобразование если класс используется виртуальные функции и именно применение и использование виртуальных функций и делает код ООП-нутным - оопнутость это когда мы в алгоритм можем засунуть заранее неизвестный тип объекта через указатель/ссылку на его базовый класс.

    Что касается затеи - эпичненько конечно же. Я лично когда узнал что в вулкане код по инициализации отрисовки одного моноцветного треугольника занимает тысячу или несколько тысяч строк даже знакомиться с ним стало лень.
     
    ml64 нравится это.
  9. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    33
    Это в полной комплектации. На минималках там такие же принципы: контекст, конвейер и шейдеры.
    А вообще, что-то мне подсказывает, что со временем для Vulkan выйдут в мейнстрим такие же библиотеки, как для OpenGL. А возможно, и те же самые: GLU, GLFW, GLM. Просто скажут, что отныне OpenGL - это legacy. Или форки появятся. Или самостоятельные проекты.
     
    Последнее редактирование: 11 май 2026 в 13:33
  10. ml64

    ml64 Member

    Публикаций:
    0
    Регистрация:
    29 окт 2017
    Сообщения:
    33
    Итак, шаг 3 готов на 120%
    Реализовано не только сравнение срок:
    Код (ASM):
    1. ;2_0_2_checkLayers.asm
    2. ; ------------------------------------------------------------------
    3. ; Returns: RAX = 0 if all requested layers are available,
    4. ;          RAX = 1 if at least one layer missing,
    5. ;          RAX = BAD if bad data
    6. ; ------------------------------------------------------------------
    7.  
    8. ;For i = 0 to layerCount-1
    9. ; layerFound = 0
    10. ; For j = 0 to availableLayersCount-1
    11. ;  If validationLayers[i] = availableLayers[j].layerName Then
    12. ;   layerFound = 1
    13. ;   break
    14. ;  End If
    15. ; Next j
    16. ; If layerFound == 0 Then Return false
    17. ;Next i
    18. ;Return true
    19.  
    20. ;Source pattern:
    21. ;const std::vector<const char*> validationLayers = {"VK_LAYER_KHRONOS_validation"};
    22. ;sz_validationLayer0 db 'VK_LAYER_0',0
    23. ;sz_validationLayer1 db 'VK_LAYER_1',0
    24. ;gpValidationLayer0 dq offset sz_validationLayer0
    25. ;gpValidationLayer1 dq offset sz_validationLayer1
    26. ;dq 0 ;Array terminated by a null pointer
    27.  
    28. ;Destination Pattern:
    29. ;VkLayerProperties struct
    30. ;layerName db 256 dup(0) ;char[256]
    31. ;specVersion dd 0 ;VkVersion
    32. ;implementationVersion dd 0 ;VkVersion
    33. ;description db 256 dup(0) ;char[256]
    34. ;VkLayerProperties ends
    35.  
    36. checkLayers proc
    37.  
    38.     ; Load validation layer count into r9d (volatile, not used elsewhere)
    39.     mov r9d, nValidationLayersCount
    40.     test r9d, r9d
    41.     jz lbl_checkLayers_Success
    42.  
    43.     ; Load available layer count into r10d
    44.     mov r10d, nAvailableLayersCount
    45.     test r10d, r10d
    46.     jz lbl_checkLayers_LayerMissing
    47.  
    48.     ; Point to first validation layer pointer array
    49.     lea rsi, gpValidationLayer0
    50.  
    51. lbl_checkLayers_OuterLoop:
    52.     mov r8, [rsi]                       ; R8 = pointer to validation layer name string
    53.  
    54.     ; Quick first-character test (must be 'V')
    55.     cmp byte ptr [r8], 'V'
    56.     jne lbl_checkLayers_Err_BadData
    57.  
    58.     ; Inner loop: scan available layers
    59.     mov rdi, ghAvailableLayers          ; start of VkLayerProperties array
    60.     mov r11d, r10d                      ; inner counter = available layer count
    61.  
    62. lbl_checkLayers_InnerLoop:
    63.     ; Compare strings: validation (R8) vs available layer name (RDI)
    64.     mov rcx, r8                         ; RCX = validation string
    65.     mov rdx, rdi                        ; RDX = available layer name
    66.  
    67. lbl_checkLayers_CompareBytes:
    68.     mov al, [rcx]
    69.     cmp al, byte ptr [rdx]
    70.     jne lbl_checkLayers_NextAvailable
    71.     test al, al
    72.     je lbl_checkLayers_FoundMatch
    73.     inc rcx
    74.     inc rdx
    75.     jmp lbl_checkLayers_CompareBytes
    76.  
    77. lbl_checkLayers_NextAvailable:
    78.     add rdi, 208h                       ; sizeof(VkLayerProperties) = 520 bytes
    79.     dec r11d
    80.     jnz lbl_checkLayers_InnerLoop
    81.  
    82.     ; No match for this validation layer
    83.     jmp lbl_checkLayers_LayerMissing
    84.  
    85. lbl_checkLayers_FoundMatch:
    86.     add rsi, 8                          ; move to next validation layer pointer
    87.     dec r9d
    88.     jnz lbl_checkLayers_OuterLoop
    89.  
    90.     ; All validation layers found
    91.     jmp lbl_checkLayers_Success
    92.  
    93. lbl_checkLayers_LayerMissing:
    94.     mov rax, 1
    95.     ret
    96.  
    97. lbl_checkLayers_Err_BadData:
    98.     mov rax, 0BADh
    99.     ret
    100.  
    101. lbl_checkLayers_Success:
    102.     xor rax, rax
    103.     ret
    104.  
    105. checkLayers endp
    106.  

    но и дамп слоёв, что очень полезно и чего нет в оригинале:
    Код (ASM):
    1. ;2_0_3_dumpAvailableLayers.asm
    2. ; Dumps all available Vulkan layer properties to "AvailableLayers.txt"
    3.  
    4. dumpAvailableLayers proc
    5.     push rbp
    6.     mov rbp, rsp
    7.     and rsp, -16
    8.     sub rsp, 100h
    9.  
    10.     ; Create/overwrite output file
    11.     lea rcx, sz_DumpFileName
    12.     mov rdx, 40000000h          ; GENERIC_WRITE
    13.     mov r8, 1                   ; FILE_SHARE_READ
    14.     xor r9, r9
    15.     mov qword ptr [rsp+20h], 2  ; CREATE_ALWAYS
    16.     mov qword ptr [rsp+28h], 80h; FILE_ATTRIBUTE_NORMAL
    17.     mov qword ptr [rsp+30h], 0
    18.     call CreateFileA
    19.     cmp rax, -1
    20.     je dump_end
    21.     mov hDumpFile, rax
    22.  
    23.     ; Write header
    24.     mov rcx, hDumpFile
    25.     lea rdx, sz_Header
    26.     mov r8, sizeof sz_Header - 1
    27.     lea r9, dwBytesWritten
    28.     mov qword ptr [rsp+20h], 0   ; lpOverlapped = NULL
    29.     call WriteFile
    30.  
    31.     ; Get available layer count and pointer
    32.     mov r14d, nAvailableLayersCount
    33.     test r14d, r14d
    34.     jz close_file
    35.     mov r15, ghAvailableLayers
    36.     test r15, r15
    37.     jz close_file
    38.  
    39.     xor r12d, r12d              ; index
    40.  
    41. next_layer:
    42.     mov rax, r12
    43.     imul rax, 520
    44.     lea r13, [r15 + rax]        ; R13 = VkLayerProperties*
    45.  
    46.     ; "Layer X: "
    47.     mov rcx, hDumpFile
    48.     lea rdx, sz_LayerHeader
    49.     mov r8, sizeof sz_LayerHeader - 1
    50.     lea r9, dwBytesWritten
    51.     mov qword ptr [rsp+20h], 0
    52.     call WriteFile
    53.  
    54.     ; Convert index to decimal
    55.     mov eax, r12d
    56.     lea rdi, tempBuffer + 31
    57.     mov byte ptr [rdi], 0
    58.     mov r10d, 10
    59.     test eax, eax
    60.     jnz idx_conv
    61.     mov byte ptr [rdi-1], '0'
    62.     dec rdi
    63.     jmp idx_write
    64. idx_conv:
    65.     xor edx, edx
    66.     div r10d
    67.     add dl, '0'
    68.     dec rdi
    69.     mov [rdi], dl
    70.     test eax, eax
    71.     jnz idx_conv
    72. idx_write:
    73.     mov rcx, hDumpFile
    74.     mov rdx, rdi
    75.     lea r8, tempBuffer + 31
    76.     sub r8, rdi
    77.     lea r9, dwBytesWritten
    78.     mov qword ptr [rsp+20h], 0
    79.     call WriteFile
    80.  
    81.     ; ": "
    82.     mov rcx, hDumpFile
    83.     lea rdx, sz_ColonSpace
    84.     mov r8, sizeof sz_ColonSpace - 1
    85.     lea r9, dwBytesWritten
    86.     mov qword ptr [rsp+20h], 0
    87.     call WriteFile
    88.  
    89.     ; newline
    90.     mov rcx, hDumpFile
    91.     lea rdx, sz_NewLine
    92.     mov r8, sizeof sz_NewLine - 1
    93.     lea r9, dwBytesWritten
    94.     mov qword ptr [rsp+20h], 0
    95.     call WriteFile
    96.  
    97.     ; "  Name: "
    98.     mov rcx, hDumpFile
    99.     lea rdx, sz_IndentName
    100.     mov r8, sizeof sz_IndentName - 1
    101.     lea r9, dwBytesWritten
    102.     mov qword ptr [rsp+20h], 0
    103.     call WriteFile
    104.  
    105.     ; layerName (string at R13)
    106.     mov rcx, hDumpFile
    107.     mov rdx, r13
    108.     mov rbx, r13
    109.     dec rbx
    110. @@: inc rbx
    111.     cmp byte ptr [rbx], 0
    112.     jne @b
    113.     sub rbx, r13
    114.     mov r8, rbx
    115.     lea r9, dwBytesWritten
    116.     mov qword ptr [rsp+20h], 0
    117.     call WriteFile
    118.  
    119.     ; newline
    120.     mov rcx, hDumpFile
    121.     lea rdx, sz_NewLine
    122.     mov r8, sizeof sz_NewLine - 1
    123.     lea r9, dwBytesWritten
    124.     mov qword ptr [rsp+20h], 0
    125.     call WriteFile
    126.  
    127.     ; "  Spec Version: "
    128.     mov rcx, hDumpFile
    129.     lea rdx, sz_IndentSpec
    130.     mov r8, sizeof sz_IndentSpec - 1
    131.     lea r9, dwBytesWritten
    132.     mov qword ptr [rsp+20h], 0
    133.     call WriteFile
    134.  
    135.     ; specVersion (dword at R13+256)
    136.     mov eax, dword ptr [r13 + 256]
    137.     lea rdi, tempBuffer + 31
    138.     mov byte ptr [rdi], 0
    139.     mov r10d, 10
    140.     test eax, eax
    141.     jnz spec_conv
    142.     mov byte ptr [rdi-1], '0'
    143.     dec rdi
    144.     jmp spec_write
    145. spec_conv:
    146.     xor edx, edx
    147.     div r10d
    148.     add dl, '0'
    149.     dec rdi
    150.     mov [rdi], dl
    151.     test eax, eax
    152.     jnz spec_conv
    153. spec_write:
    154.     mov rcx, hDumpFile
    155.     mov rdx, rdi
    156.     lea r8, tempBuffer + 31
    157.     sub r8, rdi
    158.     lea r9, dwBytesWritten
    159.     mov qword ptr [rsp+20h], 0
    160.     call WriteFile
    161.  
    162.     ; newline
    163.     mov rcx, hDumpFile
    164.     lea rdx, sz_NewLine
    165.     mov r8, sizeof sz_NewLine - 1
    166.     lea r9, dwBytesWritten
    167.     mov qword ptr [rsp+20h], 0
    168.     call WriteFile
    169.  
    170.     ; "  Implementation Version: "
    171.     mov rcx, hDumpFile
    172.     lea rdx, sz_IndentImpl
    173.     mov r8, sizeof sz_IndentImpl - 1
    174.     lea r9, dwBytesWritten
    175.     mov qword ptr [rsp+20h], 0
    176.     call WriteFile
    177.  
    178.     ; implementationVersion (dword at R13+260)
    179.     mov eax, dword ptr [r13 + 260]
    180.     lea rdi, tempBuffer + 31
    181.     mov byte ptr [rdi], 0
    182.     mov r10d, 10
    183.     test eax, eax
    184.     jnz impl_conv
    185.     mov byte ptr [rdi-1], '0'
    186.     dec rdi
    187.     jmp impl_write
    188. impl_conv:
    189.     xor edx, edx
    190.     div r10d
    191.     add dl, '0'
    192.     dec rdi
    193.     mov [rdi], dl
    194.     test eax, eax
    195.     jnz impl_conv
    196. impl_write:
    197.     mov rcx, hDumpFile
    198.     mov rdx, rdi
    199.     lea r8, tempBuffer + 31
    200.     sub r8, rdi
    201.     lea r9, dwBytesWritten
    202.     mov qword ptr [rsp+20h], 0
    203.     call WriteFile
    204.  
    205.     ; newline
    206.     mov rcx, hDumpFile
    207.     lea rdx, sz_NewLine
    208.     mov r8, sizeof sz_NewLine - 1
    209.     lea r9, dwBytesWritten
    210.     mov qword ptr [rsp+20h], 0
    211.     call WriteFile
    212.  
    213.     ; "  Description: "
    214.     mov rcx, hDumpFile
    215.     lea rdx, sz_IndentDesc
    216.     mov r8, sizeof sz_IndentDesc - 1
    217.     lea r9, dwBytesWritten
    218.     mov qword ptr [rsp+20h], 0
    219.     call WriteFile
    220.  
    221.     ; description (string at R13+264)
    222.     mov rcx, hDumpFile
    223.     lea rdx, [r13 + 264]
    224.     mov rbx, rdx
    225.     dec rbx
    226. @@: inc rbx
    227.     cmp byte ptr [rbx], 0
    228.     jne @b
    229.     sub rbx, rdx
    230.     mov r8, rbx
    231.     lea r9, dwBytesWritten
    232.     mov qword ptr [rsp+20h], 0
    233.     call WriteFile
    234.  
    235.     ; newline
    236.     mov rcx, hDumpFile
    237.     lea rdx, sz_NewLine
    238.     mov r8, sizeof sz_NewLine - 1
    239.     lea r9, dwBytesWritten
    240.     mov qword ptr [rsp+20h], 0
    241.     call WriteFile
    242.  
    243.     ; double newline between layers
    244.     mov rcx, hDumpFile
    245.     lea rdx, sz_DoubleNewLine
    246.     mov r8, sizeof sz_DoubleNewLine - 1
    247.     lea r9, dwBytesWritten
    248.     mov qword ptr [rsp+20h], 0
    249.     call WriteFile
    250.  
    251.     inc r12d
    252.     cmp r12d, r14d
    253.     jb next_layer
    254.  
    255. close_file:
    256.     mov rcx, hDumpFile
    257.     call CloseHandle
    258.  
    259. dump_end:
    260.     leave
    261.     ret
    262. dumpAvailableLayers endp

    Пример дампа:
    Available Vulkan Layers:
    Layer 0:
    Name: VK_LAYER_NV_optimus
    Spec Version: 4211013
    Implementation Version: 1
    Description: NVIDIA Optimus layer
    Layer 1:
    Name: VK_LAYER_NV_present
    Spec Version: 4211013
    Implementation Version: 1
    Description: NVIDIA Presentation Layer
    Layer 2:
    Name: VK_LAYER_EOS_Overlay
    Spec Version: 4202632
    Implementation Version: 1
    Description: Vulkan overlay layer for Epic Online Services
    Layer 3:
    Name: VK_LAYER_LUNARG_api_dump
    Spec Version: 4211029
    Implementation Version: 2
    Description: LunarG API dump layer
    Layer 4:
    Name: VK_LAYER_LUNARG_gfxreconstruct
    Spec Version: 4211029
    Implementation Version: 4194309
    Description: GFXReconstruct Capture Layer Version 1.0.5
    Layer 5:
    Name: VK_LAYER_KHRONOS_synchronization2
    Spec Version: 4211029
    Implementation Version: 1
    Description: Khronos Synchronization2 layer
    Layer 6:
    Name: VK_LAYER_KHRONOS_validation
    Spec Version: 4211029
    Implementation Version: 1
    Description: Khronos Validation Layer
    Layer 7:
    Name: VK_LAYER_LUNARG_monitor
    Spec Version: 4211029
    Implementation Version: 1
    Description: Execution Monitoring Layer
    Layer 8:
    Name: VK_LAYER_LUNARG_screenshot
    Spec Version: 4211029
    Implementation Version: 1
    Description: LunarG image capture layer
    Layer 9:
    Name: VK_LAYER_KHRONOS_profiles
    Spec Version: 4211029
    Implementation Version: 1
    Description: Khronos Profiles layer
    Layer 10:
    Name: VK_LAYER_KHRONOS_shader_object
    Spec Version: 4211029
    Implementation Version: 1
    Description: Khronos Shader object layer
    Layer 11:
    Name: VK_LAYER_LUNARG_crash_diagnostic
    Spec Version: 4211029
    Implementation Version: 1
    Description: Crash Diagnostic Layer is a crash/hang debugging tool that helps determines GPU progress in a Vulkan application.

    "Исправлены ошибки, повышена устойчивость"
    ...И на этой позитивной ноте позволю себе взять паузу, перевести дух и осмыслить проделанное, ибо следующий шаг - это "Физические устройства и семьи очередей" - что бы это ни значило.
     

    Вложения:

    Последнее редактирование модератором: 12 май 2026 в 01:23