Vulkan入門教程 | 第二部分:創建實例

前言:本教程為筆者依據教程https://docs.vulkan.net.cn/spec/latest/index.html#_about進行Vulkan學習并結合自己的理解整理的筆記,供大家學習和參考。

(注意:代碼僅為片段,非完整程序)

學習前提:

支持Vulkan的顯卡以及驅動程序(NVIDIA,AMD,Intel)
具備C++編程經驗(熟悉RAII,初始化列表)
支持C++的編譯器(Visual Studio 2017+,GCC 7+)

往期回顧:
Vulkan入門教程 | 第一部分:Vulkan簡介

一、概述

本教程將逐步解釋如何創建一個基礎的Vulkan實例,這是所有Vulkan程序的起點。Vulkan實例是應用程序與Vulkan驅動程序之間的連接橋梁,它相當于一個"會話",告訴系統"我的程序要使用Vulkan了,請為我分配相應的資源"。傳統的OpenGL采用全局狀態機模式,而Vulkan采用顯式的對象模型。這意味著:

  • 顯式控制:你必須明確告訴系統你要做什么
  • 多實例支持:同一個程序可以創建多個Vulkan實例
  • 更好的錯誤檢測:每個操作都有明確的返回值

實例負責以下關鍵功能:

  • 初始化Vulkan系統?- 加載驅動和底層資源

  • 管理擴展和驗證層?- 控制額外功能和調試工具

  • 查詢可用硬件?- 發現系統中的物理設備(GPU)

  • 平臺抽象?- 提供跨不同操作系統的一致接口

二、完整流程

1、添加頭文件

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>#include <iostream>
#include <stdexcept>
#include <cstdlib>

(1)?#define GLFW_INCLUDE_VULKAN 是GLFW庫的配置宏,它的核心作用是啟用GLFW對Vulkan的原生支持。當定義此宏后,GLFW會在內部進行以下關鍵操作:

  • 自動包含Vulkan核心頭文件<vulkan/vulkan.h>

  • 激活GLFW中與Vulkan相關的函數實現

  • 建立GLFW窗口系統與Vulkan之間的連接橋梁

  • 處理不同平臺上Vulkan頭文件的包含差異

沒有這個宏定義,GLFW將無法提供Vulkan所需的窗口表面擴展,導致實例創建失敗。它是連接GLFW窗口系統和Vulkan API的關鍵開關

(2)#include <GLFW/glfw3.h>是GLFW庫的主頭文件,提供跨平臺的窗口創建和事件處理功能。在Vulkan開發中,它具體負責:

  • 創建和管理操作系統原生窗口

  • 處理鍵盤、鼠標等輸入事件

  • 提供與Vulkan兼容的窗口表面

  • 封裝不同操作系統的原生窗口API(Windows的Win32、macOS的Cocoa、Linux的X11/Wayland)

  • 實現glfwGetRequiredInstanceExtensions()函數,獲取平臺特定的Vulkan擴展

GLFW抽象了底層平臺的窗口創建細節,使開發者能夠用統一的API創建適用于Vulkan的渲染窗口,無需編寫平臺特定的代碼。

(3)#include <iostream>C++標準輸入輸出庫頭文件,主要用于錯誤報告和控制臺輸出

(4)#include <stdexcept>C++標準異常處理頭文件,提供標準異常類。這個頭文件實現了錯誤處理的標準化,使代碼能通過統一的異常處理機制管理Vulkan API可能返回的各種錯誤。

(5)#include <cstdlib>C標準庫的C++封裝頭文件,提供程序基本控制功能

  • 定義程序退出碼EXIT_SUCCESSEXIT_FAILURE

  • 當捕獲到異常時,返回EXIT_FAILURE表示異常終止

  • 程序正常結束時返回EXIT_SUCCESS

  • 提供內存管理、隨機數生成等基礎功能

2、類封裝的整體架構設計

class HelloTriangleApplication {
public:void run() {initWindow();//1、初始化階段initVulkan();//2、資源準備階段mainLoop();//3、運行階段cleanup();//4、清理階段}
private:GLFWwindow* window;//GLFW窗口指針VkInstance instance;//Vulkan實例句柄,這是我們與Vulkan驅動通信的橋梁// 其他私有成員...
};

類封裝遵循RAII原則,資源獲取即初始化,離開作用域自動清理,確保了資源的正確分配和釋放,保證即使程序出現異常,析構函數也會被調用。

run()函數體現了一個經典的應用程序生命周期模式:初始化—>資源準備—>運行主循環—>清理資源,每個階段都可以獨立測試。

3、初始化窗口系統(GLFW)

const uint32_t WIDTH = 800;//定義窗口的寬度
const uint32_t HEIGHT = 600;//定義窗口的高度//類的私有成員函數
void initWindow() {glfwInit();//初始化GLFW庫glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);//不使用OpenGLglfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);//禁用窗口大小調整//創建實際的窗口,參數分別是寬度、高度、窗口標題、顯示器和共享上下文window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
}

?這個函數只負責窗口相關的初始化,不涉及任何Vulkan代碼。其中窗口大小變化涉及交換鏈重建等復雜概念,初學時選擇禁用窗口大小調整。

4、創建Vulkan實例

//類的私有成員函數
void initVulkan() {createInstance();
}void createInstance() {// 配置應用程序信息VkApplicationInfo appInfo{};appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;appInfo.pApplicationName = "Hello Triangle";appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);appInfo.pEngineName = "No Engine";appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);appInfo.apiVersion = VK_API_VERSION_1_0;// 獲取GLFW所需的Vulkan擴展uint32_t glfwExtensionCount = 0;const char** glfwExtensions;glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);// 配置實例創建信息VkInstanceCreateInfo createInfo{};createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;createInfo.pApplicationInfo = &appInfo;createInfo.enabledExtensionCount = glfwExtensionCount;createInfo.ppEnabledExtensionNames = glfwExtensions;createInfo.enabledLayerCount = 0; // 禁用驗證層// 創建Vulkan實例if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {throw std::runtime_error("failed to create instance!");}
}

目前只在Vulkan初始化函數initVulkan()中調用了createInstance(),這是Vulkan初始化的第一步,在完成的Vulkan應用中,這里還會包括物理設備選擇、邏輯設備創建等步驟。createInstance() 是創建實例的核心內容,分為以下幾個部分:

//第一部分:應用程序信息結構體
VkApplicationInfo appInfo{};//描述應用程序的基本信息
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;//結構體類型標識符,Vulkan的所有結構體都需要設置這個字段
appInfo.pApplicationName = "Hello Triangle";//應用程序名稱,可以被驅動程序用于優化
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);//應用程序版本號,使用VK_MAKE_VERSION宏創建
appInfo.pEngineName = "No Engine";//使用的引擎名稱,這里寫"No Engine"表示沒有使用特定引擎
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);//引擎版本號
appInfo.apiVersion = VK_API_VERSION_1_0;//應用程序期望使用的Vulkan API版本

sType是結構體類型標識符,Vulkan的所有結構體都需要設置這個字段。在Vulkan的C語言環境中,由于缺乏C++的類型系統,每個結構體都必須通過sType字段來聲明自己的類型。當這個結構體稍后被傳遞給驅動程序時,驅動程序會首先檢查這個字段,確認接收到的確實是一個ApplicationInfo結構體,然后才會按照相應的格式來解析其他字段。

為什么需要sType?

  • 類型安全:Vulkan使用C語言編寫,沒有C++的類型系統,sType提供運行時類型檢查
  • 版本兼容性:不同版本的Vulkan可能有不同的結構體布局,sType幫助驅動程序正確解析
  • 擴展支持:未來的擴展可以通過sType識別新的結構體類型
//第二部分:實例創建信息結構體
VkInstanceCreateInfo createInfo{};//用于創建Vulkan實例的信息結構體
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;//同樣需要設置結構體類型標識符
createInfo.pApplicationInfo = &appInfo;//指向前面創建的應用程序信息結構體

這個階段開始構建實例創建的主控制結構。VkInstanceCreateInfo是整個創建過程的核心數據結構,它將收集所有必要的信息,然后一次性傳遞給實例創建函數。

createInfo.pApplicationInfo = &appInfo;這行代碼建立了創建信息與應用程序信息之間的引用關系。通過指針傳遞而不是值拷貝,避免了大量數據的復制開銷。當稍后調用vkCreateInstance時,驅動程序會通過這個指針訪問應用程序信息。pApplicationInfo指針的作用:

  • 信息傳遞:將應用程序信息傳遞給實例創建過程
  • 內存效率:避免復制大量數據,使用指針引用
  • 可選性:pApplicationInfo可以為nullptr,但提供信息有助于優化
//第三部分:GLFW擴展配置
uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);//GLFW告訴我們需要哪些Vulkan擴展才能與窗口系統交互
createInfo.enabledExtensionCount = glfwExtensionCount;//指定要啟用的擴展數量
createInfo.ppEnabledExtensionNames = glfwExtensions;//指定要啟用的擴展名稱列表

前三行代碼執行了一個需求查詢過程。GLFW作為窗口管理庫,了解當前平臺需要哪些Vulkan擴展才能實現窗口與Vulkan的集成。glfwGetRequiredInstanceExtensions函數的執行過程是這樣的:GLFW內部會檢測當前的操作系統和窗口系統,然后返回相應的擴展名稱列表。在Windows上,它可能返回VK_KHR_surface和VK_KHR_win32_surface;在Linux上,可能返回VK_KHR_surface和VK_KHR_xlib_surface。

GLFW需要的典型擴展:

  • VK_KHR_surface:跨平臺窗口表面抽象
  • VK_KHR_win32_surface(Windows)或VK_KHR_xlib_surface(Linux):平臺特定的表面擴展

后兩行代碼將GLFW提供的擴展需求注冊到創建信息中。enabledExtensionCount告訴驅動程序有多少個擴展需要啟用,ppEnabledExtensionNames提供了擴展名稱的字符串數組。

當驅動程序稍后處理創建請求時,會逐一檢查這些擴展是否可用,如果任何一個擴展不存在或不兼容,整個創建過程就會失敗。

//第四部分:驗證層配置
createInfo.enabledLayerCount = 0;//設置為0表示不啟用任何驗證層,適用于發布版本

這行代碼明確設置不啟用任何驗證層。驗證層是Vulkan提供的調試和開發輔助工具,它們會攔截API調用進行額外的檢查和驗證。將計數設置為0表示這是一個發布版本的配置,追求最佳性能而不是調試便利性。下一篇會詳細介紹驗證層,驗證層的攔截機制為:

應用程序調用 → 驗證層 → 驅動程序
? ? ?↑ ? ? ? ? ? ? ? ?↓
? ?返回結果 ? ? ? ?檢查參數/狀態

//第五部分:創建實例
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {throw std::runtime_error("failed to create instance!");//如果不等于VK_SUCCESS,說明創建失敗,拋出異常
}

?這段代碼執行了整個過程的核心系統調用。vkCreateInstance函數接收三個參數:

第一個參數&createInfo將前面精心準備的所有配置信息傳遞給驅動程序。驅動程序會詳細檢查這個結構體中的每一個字段,驗證應用程序的需求是否可以滿足。

第二個參數nullptr表示使用默認的內存分配器。Vulkan允許應用程序提供自定義的內存分配策略,但在這個簡單示例中使用系統默認的分配器。

第三個參數&instance是一個輸出參數,成功創建后,新實例的句柄會被寫入這個變量中。

函數調用完成后,代碼立即檢查返回值可能的返回值及含義:

  • VK_SUCCESS:創建成功
  • VK_ERROR_OUT_OF_HOST_MEMORY:主機內存不足
  • VK_ERROR_OUT_OF_DEVICE_MEMORY:設備內存不足
  • VK_ERROR_INITIALIZATION_FAILED:初始化失敗
  • VK_ERROR_LAYER_NOT_PRESENT:請求的驗證層不可用
  • VK_ERROR_EXTENSION_NOT_PRESENT:請求的擴展不可用
  • VK_ERROR_INCOMPATIBLE_DRIVER:驅動程序不兼容

5、主循環

void mainLoop() {while (!glfwWindowShouldClose(window)) {//檢查窗口是否應該關閉glfwPollEvents();//處理窗口事件(如鍵盤、鼠標輸入)}
}

?標準的GLFW事件循環。

6、資源清理

void cleanup() {vkDestroyInstance(instance, nullptr);//銷毀Vulkan實例,釋放相關資源glfwDestroyWindow(window);//銷毀GLFW窗口glfwTerminate();//終止GLFW庫
}

?7、主函數和異常處理

int main() {HelloTriangleApplication app;//對象創建//如果運行過程中拋出任何繼承自std::exception的異常,程序會捕獲并處理try {app.run();//應用程序的主要執行函數} catch (const std::exception& e) {std::cerr << e.what() << std::endl;//錯誤信息輸出到標準錯誤流return EXIT_FAILURE;}return EXIT_SUCCESS;
}

使用異常處理機制,確保程序能夠優雅地處理錯誤,如果出現異常,打印錯誤信息并返回失敗狀態。

總結

vvkCreateInstance成功返回后,instance變量中就包含了一個有效的Vulkan實例句柄。這個句柄實際上是一個指向復雜內部結構的指針,該結構包含了:

  • 所有啟用擴展的函數指針表
  • 應用程序信息的副本
  • 平臺特定的窗口系統集成代碼
  • 內存分配器的配置信息
  • 錯誤處理和調試回調的設置

此時,應用程序就獲得了訪問Vulkan功能的基礎憑證,可以進行后續的物理設備枚舉、邏輯設備創建等操作。實例的生命周期將貫穿整個應用程序運行期間,直到程序退出時在cleanup()函數中被銷毀。

這整個創建過程體現了Vulkan先配置后執行的設計哲學:應用程序需要詳細描述自己的需求和配置,然后系統根據這些描述一次性完成所有初始化工作,避免了運行時的不確定性和性能開銷。

該部分的完整代碼如下:
(1)無注釋版:

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>#include <iostream>
#include <stdexcept>
#include <cstdlib>const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;class HelloTriangleApplication {
public:void run() {initWindow();initVulkan();mainLoop();cleanup();}private:GLFWwindow* window;VkInstance instance;void initWindow() {glfwInit();glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);}void initVulkan() {createInstance();}void mainLoop() {while (!glfwWindowShouldClose(window)) {glfwPollEvents();}}void cleanup() {vkDestroyInstance(instance, nullptr);glfwDestroyWindow(window);glfwTerminate();}void createInstance() {VkApplicationInfo appInfo{};appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;appInfo.pApplicationName = "Hello Triangle";appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);appInfo.pEngineName = "No Engine";appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);appInfo.apiVersion = VK_API_VERSION_1_0;VkInstanceCreateInfo createInfo{};createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;createInfo.pApplicationInfo = &appInfo;uint32_t glfwExtensionCount = 0;const char** glfwExtensions;glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);createInfo.enabledExtensionCount = glfwExtensionCount;createInfo.ppEnabledExtensionNames = glfwExtensions;createInfo.enabledLayerCount = 0;if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {throw std::runtime_error("failed to create instance!");}}
};int main() {HelloTriangleApplication app;try {app.run();} catch (const std::exception& e) {std::cerr << e.what() << std::endl;return EXIT_FAILURE;}return EXIT_SUCCESS;
}

(2)詳細注釋版:

// 定義GLFW_INCLUDE_VULKAN宏,讓GLFW自動包含Vulkan頭文件
// 這樣我們就不需要單獨包含vulkan.h了
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>// 標準C++庫頭文件
#include <iostream>    // 用于輸出錯誤信息
#include <stdexcept>   // 用于異常處理
#include <cstdlib>     // 用于EXIT_SUCCESS和EXIT_FAILURE常量// 定義窗口的寬度和高度常量
const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;class HelloTriangleApplication {
public:// 主運行函數,按順序執行初始化、主循環和清理void run() {initWindow();    // 初始化GLFW窗口initVulkan();    // 初始化Vulkan相關資源mainLoop();      // 進入主事件循環cleanup();       // 清理所有資源}private:GLFWwindow* window;    // GLFW窗口指針VkInstance instance;   // Vulkan實例句柄,這是使用Vulkan API的入口點// 初始化GLFW窗口void initWindow() {// 初始化GLFW庫glfwInit();// 設置窗口提示:不使用任何圖形API(因為我們要使用Vulkan)glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);// 設置窗口提示:禁止窗口大小調整(簡化示例代碼)glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);// 創建窗口:寬度、高度、標題、監視器(nullptr表示窗口模式)、共享窗口(nullptr表示不共享)window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);}// 初始化Vulkan相關資源void initVulkan() {createInstance();    // 創建Vulkan實例}// 主事件循環void mainLoop() {// 持續運行直到用戶關閉窗口while (!glfwWindowShouldClose(window)) {glfwPollEvents();    // 處理窗口事件(如鍵盤、鼠標輸入)}}// 清理所有資源void cleanup() {// 銷毀Vulkan實例(必須在glfwTerminate之前調用)vkDestroyInstance(instance, nullptr);// 銷毀GLFW窗口glfwDestroyWindow(window);// 終止GLFW庫glfwTerminate();}// 創建Vulkan實例的核心函數void createInstance() {// 步驟1:填充應用程序信息結構體VkApplicationInfo appInfo{};    // {}初始化所有成員為零// 指定結構體類型(Vulkan中每個結構體都需要指定類型)appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;// 應用程序名稱(可選,但有助于驅動程序優化)appInfo.pApplicationName = "Hello Triangle";// 應用程序版本(使用VK_MAKE_VERSION宏創建版本號:主版本.次版本.補丁版本)appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);// 引擎名稱(如果使用游戲引擎的話)appInfo.pEngineName = "No Engine";// 引擎版本appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);// 要使用的Vulkan API版本appInfo.apiVersion = VK_API_VERSION_1_0;// 步驟2:填充實例創建信息結構體VkInstanceCreateInfo createInfo{};// 指定結構體類型createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;// 指向應用程序信息的指針createInfo.pApplicationInfo = &appInfo;// 步驟3:獲取GLFW需要的Vulkan擴展uint32_t glfwExtensionCount = 0;    // 擴展數量const char** glfwExtensions;        // 擴展名稱數組// GLFW告訴我們它需要哪些Vulkan擴展來創建窗口表面glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);// 將GLFW需要的擴展添加到實例創建信息中createInfo.enabledExtensionCount = glfwExtensionCount;      // 擴展數量createInfo.ppEnabledExtensionNames = glfwExtensions;        // 擴展名稱數組// 步驟4:驗證層設置(這里暫時設為0,不啟用任何驗證層)createInfo.enabledLayerCount = 0;// 步驟5:創建Vulkan實例// 參數:創建信息、自定義分配器(nullptr使用默認)、實例句柄的指針if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {// 如果創建失敗,拋出運行時異常throw std::runtime_error("failed to create instance!");}}
};// 主函數
int main() {HelloTriangleApplication app;    // 創建應用程序對象try {app.run();    // 運行應用程序} catch (const std::exception& e) {    // 捕獲異常std::cerr << e.what() << std::endl;    // 輸出錯誤信息return EXIT_FAILURE;    // 返回失敗狀態碼}return EXIT_SUCCESS;    // 返回成功狀態碼
}


?歡迎學習和交流,歡迎指正!🌹🌹?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/916737.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/916737.shtml
英文地址,請注明出處:http://en.pswp.cn/news/916737.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PHP云原生架構:容器化、Kubernetes與Serverless實踐

引言 隨著云計算的普及,PHP應用也在向云原生架構演進。本文將深入探討PHP在云原生環境中的最佳實踐,包括容器化部署、Kubernetes編排、Serverless架構以及云原生監控與日志方案,幫助開發者構建現代化、可擴展的PHP應用。 容器化PHP應用 基礎Dockerfile優化 # 多階段構建…

【華為機試】5. 最長回文子串

文章目錄5. 最長回文子串描述示例 1示例 2示例 3示例 4提示解題思路方法一&#xff1a;中心擴展法&#xff08;推薦&#xff09;方法二&#xff1a;動態規劃方法三&#xff1a;Manacher算法方法四&#xff1a;暴力解法代碼實現復雜度分析測試用例完整題解代碼5. 最長回文子串 …

【圖像處理基石】如何對遙感圖像進行實例分割?

遙感圖像實例分割是指在遙感影像中&#xff0c;不僅要識別出不同類別的目標&#xff08;如建筑物、車輛、道路等&#xff09;&#xff0c;還要區分同一類別中的不同個體&#xff08;如建筑物1、建筑物2&#xff09;&#xff0c;并為每個實例生成精確的像素級掩碼。 一、遙感圖…

電子電氣架構 --- 軟件bug的管理模式

我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 簡單,單純,喜歡獨處,獨來獨往,不易合同頻過著接地氣的生活,除了生存溫飽問題之外,沒有什么過多的欲望,表面看起來很高冷,內心熱情,如果你身…

【每日一錯】Oracle 19c CDB中如何啟動一個PDB

文章目錄題目擴展學習CDB與PDB的概念CDB&#xff0c;PDB結構優勢總結題目 擴展學習 CDB與PDB的概念 在Oracle 12c及以上版本&#xff0c;Oracle引入了多租戶架構&#xff0c;這種架構讓數據庫的管理和資源使用更加高效。它由兩種主要組成部分組成&#xff1a; CDB&#xff0…

Android studio自帶的Android模擬器都是x86架構的嗎,需要把arm架構的app翻譯成x86指令?

Android studio自帶的Android模擬器都是x86架構的嗎&#xff0c;需要把arm架構的app翻譯成x86指令&#xff1f; deepseek回答&#xff1a; Android Studio 自帶的官方模擬器&#xff08;Android Emulator&#xff09;主要提供基于 x86 架構的系統鏡像。當運行 ARM 架構的應用…

Deep Learning_ Foundations and Concepts-Springer (2024)【拜讀】20章3節

Diffusion Models 擴散模型 我們已經了解到&#xff0c;構建強大的生成模型的一種有效方法是&#xff1a;先引入一個關于潛在變量z的分布p(z)&#xff0c;然后使用深度神經網絡將z變換到數據空間x。由于神經網絡具有通用性&#xff0c;能夠將簡單固定的分布轉化為關于x的高度靈…

Arduino與STM32:初學者該如何選擇?

在電子愛好者和初學者的世界里&#xff0c;Arduino和STM32是兩個經常被提及的名字。它們各自具有獨特的優勢和特點&#xff0c;適合不同類型的項目和需求。對于初學者來說&#xff0c;選擇Arduino還是STM32&#xff0c;往往取決于個人的學習目標、項目需求以及預算。本文將詳細…

創建型設計模式-工廠方法模式和抽象工廠方法模式

1、工廠方法模式 創建型設計模式之一 UML類圖2、抽象工廠模式 也是創建型設計模式之一。雖然抽象工廠方法模式的類繁多&#xff0c;但是&#xff0c;主要分為4類。 AbstractFactory&#xff1a;抽象工廠角色&#xff0c;它聲明了一組用于創建一種產品的方法&#xff0c;每一個方…

Hyperchain安全與隱私機制詳解

一、核心安全機制1. 共識算法安全RBFT共識算法&#xff1a;改進型PBFT&#xff1a;基于PBFT算法優化&#xff0c;增加動態節點管理、失效數據恢復機制&#xff0c;提升系統容錯性與可用性。性能指標&#xff1a;吞吐量穩定達3000-10000 TPS&#xff0c;交易執行時間控制在300ms…

Oracle優化學習十六

反連接反連接&#xff08;Anti Join&#xff09;是一種特殊的連接類型&#xff0c;與內連接和外連接不同&#xff0c;Oracle數據庫里并沒有相關的 關鍵字可以在SQL文本中專門表示反連接&#xff0c;所以這里把它單獨拿出來說明。為了方便說明反連接的含義&#xff0c;我們用“t…

梳理一些 Docker 常用命令

以下是一些 Docker 常用命令&#xff0c;適用于日常開發、調試、部署等場景&#xff0c;分為幾個常用類別&#xff1a;&#x1f4e6; 一、鏡像&#xff08;Image&#xff09;相關命令命令說明docker images查看本地所有鏡像docker pull <image>拉取鏡像&#xff08;如 do…

C#_ArrayList動態數組

目錄 ArrayList的特點 ArrayList 與普通數組的區別 使用示例&#xff1a; 普通數組 動態數組 主要方法和屬性 屬性&#xff1a; Count 獲取動態數組的數據個數 讀取某個位置的數據 // 索引 方法&#xff1a; Add 向集合末尾添加元素 Insert 在指定位置插入元…

Agent領域,近年來的前沿研究方向:多智能體協作、認知啟發架構、倫理安全、邊緣計算集成

Agent領域,近年來的前沿研究方向:多智能體協作、認知啟發架構、倫理安全、邊緣計算集成 在Agent領域,近年來的前沿研究方向主要集中在多智能體協作、認知啟發架構、倫理安全、邊緣計算集成以及生成式AI融合等方面。 一、多智能體協作與多模態任務 多智能體系統在復雜環境…

【安卓筆記】OOM與內存優化

0. 環境&#xff1a; 電腦&#xff1a;Windows10 Android Studio: 2024.3.2 編程語言: Java Gradle version&#xff1a;8.11.1 Compile Sdk Version&#xff1a;35 Java 版本&#xff1a;Java11 1.什么是OOM OOM即 OutOfMemoryError 內存溢出錯誤。常見于一些 資源型對…

持續集成CI與自動化測試

Python接口自動化測試零基礎入門到精通&#xff08;2025最新版&#xff09;

Spring 策略模式實現

Spring 策略模式實現&#xff1a;工廠方法與自動注入詳解 1. 背景介紹 在復雜的業務系統中,我們常常需要根據不同的場景選擇不同的處理策略。本文將詳細介紹在 Spring 框架中實現策略模式的兩種主要方法。 2. 方案一: 手動注冊工廠模式 2.1 定義工廠類 Component public class …

機器學習——線性回歸(LinearRegression)

Python 線性回歸詳解&#xff1a;從原理到實戰線性回歸&#xff08;Linear Regression&#xff09;是機器學習中最基礎也是最重要的算法之一&#xff0c;廣泛應用于預測分析領域&#xff0c;例如房價預測、銷售額預測等。本文將帶你從理論出發&#xff0c;用 Python 手把手實現…

H.264視頻的RTP有效載荷格式(翻譯自:RFC6184 第5節 RTP有效載荷格式)

RTP協議格式 RFC地址&#xff1a;https://datatracker.ietf.org/doc/html/rfc6184 RTP報頭的格式在RFC3550中指定 0 1 2 30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1------------------------…

秒級構建消息驅動架構:描述事件流程,生成 Spring Cloud Stream+RabbitMQ 代碼

在消息驅動架構開發中&#xff0c;Spring Cloud Stream 與 RabbitMQ 的整合往往需要手動配置綁定器、定義消息通道、編寫消費邏輯&#xff0c;流程繁瑣且易出錯。而飛算JavaAI 作為高效的 IDE 插件&#xff0c;能讓開發者通過自然語言描述事件流程&#xff0c;自動生成可運行的…