android 表面,扩展,实例都创建成功

This commit is contained in:
xsl
2025-10-18 17:57:55 +08:00
parent 966382a7dd
commit 2db7194305
8 changed files with 165 additions and 33 deletions
+5 -1
View File
@@ -10,13 +10,15 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android")
message(STATUS "Building for Android") message(STATUS "Building for Android")
include_directories( include_directories(
vulkan
) )
add_library(sample SHARED add_library(sample SHARED
app/src/main/cpp/main.cpp app/src/main/cpp/main.cpp
app/src/main/cpp/AndroidOut.cpp app/src/main/cpp/AndroidOut.cpp
vulkan/AppBase.h
vulkan/AppBase.cpp vulkan/AppBase.cpp
vulkan/Application.h
vulkan/Application.cpp vulkan/Application.cpp
) )
@@ -53,7 +55,9 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR WIN32)
# 将源代码添加到此项目的可执行文件。 # 将源代码添加到此项目的可执行文件。
add_executable (sample add_executable (sample
"vulkan/main.cpp" "vulkan/main.cpp"
"vulkan/AppBase.h"
"vulkan/AppBase.cpp" "vulkan/AppBase.cpp"
"vulkan/Application.h"
"vulkan/Application.cpp" "vulkan/Application.cpp"
) )
endif() endif()
+3
View File
@@ -2,6 +2,9 @@ plugins {
alias(libs.plugins.android.application) alias(libs.plugins.android.application)
} }
ext.vvl_version='1.4.321.0'
apply from: "./download_vvl.gradle"
android { android {
namespace 'com.hmwl.sample' namespace 'com.hmwl.sample'
compileSdk 35 compileSdk 35
+81
View File
@@ -0,0 +1,81 @@
apply plugin: 'com.android.application'
/*
* Copyright (c) 2022-2024, The Android Open Source Project.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* Download validation layer binary release zip file from Khronos github repo
* https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases
*
* To use this script, add the following to your module's build.gradle:
* ext.vvl_version='your-new-version'
* apply from: "${PATH-TO-THIS}/download_vvl.gradle"
* To update to a new version:
* - change the ext.vvl_version to a new version string.
* - delete directory pointed by ${VVL_JNILIB_DIR}.
* - sync gradle script in IDE and rebuild project.
*
* Note: binary release can also be manually downloaded and put it into
* the default jniLibs directory at app/src/main/jniLibs.
*/
// get the validation layer version.
def VVL_VER = "1.4.321.0"
if (ext.has("vvl_version")) {
VVL_VER = ext.vvl_version
}
// declare local variables shared between downloading and unzipping.
def VVL_SITE ="https://github.com/KhronosGroup/Vulkan-ValidationLayers"
def VVL_LIB_ROOT= rootDir.absolutePath.toString() + "/layerLib"
def VVL_JNILIB_DIR="${VVL_LIB_ROOT}/jniLibs"
def VVL_SO_NAME = "libVkLayer_khronos_validation.so"
// download the release zip file to ${VVL_LIB_ROOT}/
task download {
def VVL_ZIP_NAME = "releases/download/vulkan-sdk-${VVL_VER}/android-binaries-${VVL_VER}.zip"
mkdir "${VVL_LIB_ROOT}"
def f = new File("${VVL_LIB_ROOT}/android-binaries-${VVL_VER}.zip")
new URL("${VVL_SITE}/${VVL_ZIP_NAME}")
.withInputStream { i -> f.withOutputStream { it << i } }
}
// unzip the downloaded VVL zip archive to the ${VVL_JNILIB_DIR} for APK packaging.
task unzip(dependsOn: download, type: Copy) {
from zipTree(file("${VVL_LIB_ROOT}/android-binaries-${VVL_VER}.zip"))
into file("${VVL_JNILIB_DIR}")
}
android.sourceSets.main.jniLibs {
srcDirs += ["${VVL_JNILIB_DIR}/android-binaries-${VVL_VER}"]
}
// add vvl download as an application dependency.
dependencies {
def ARM64_VVL_FILE = "${VVL_JNILIB_DIR}/arm64-v8a/${VVL_SO_NAME}"
if(!file("${ARM64_VVL_FILE}").exists()) {
implementation files("${ARM64_VVL_FILE}") {
builtBy 'unzip'
}
}
}
project.afterEvaluate{
project.getTasks().getByName("mergeDebugJniLibFolders").dependsOn(unzip)
project.getTasks().getByName("mergeReleaseJniLibFolders").dependsOn(unzip)
}
+20 -10
View File
@@ -3,14 +3,21 @@
#include <game-activity/native_app_glue/android_native_app_glue.h> #include <game-activity/native_app_glue/android_native_app_glue.h>
#include <game-activity/GameActivity.h> #include <game-activity/GameActivity.h>
#include "AndroidOut.h" #include "AndroidOut.h"
#include "Application.h"
#include <chrono>
#include <thread>
using namespace std;
extern "C" { extern "C" {
android_app* g_android_app = nullptr;
Application* g_Application = nullptr;
void handle_cmd(android_app *pApp, int32_t cmd) { void handle_cmd(android_app *pApp, int32_t cmd) {
switch (cmd) { switch (cmd) {
case APP_CMD_INIT_WINDOW: case APP_CMD_INIT_WINDOW:
aout << "APP_CMD_INIT_WINDOW" << std::endl; aout << "APP_CMD_INIT_WINDOW" << std::endl;
g_Application->initVulkan();
break; break;
case APP_CMD_TERM_WINDOW: case APP_CMD_TERM_WINDOW:
aout << "APP_CMD_TERM_WINDOW" << std::endl; aout << "APP_CMD_TERM_WINDOW" << std::endl;
@@ -20,26 +27,24 @@ void handle_cmd(android_app *pApp, int32_t cmd) {
} }
} }
android_app* g_android_app = nullptr;
void android_main(struct android_app *pApp) { void android_main(struct android_app *pApp) {
aout << "Welcome to android_main" << std::endl; aout << "Welcome to android_main" << std::endl;
g_android_app = pApp;
Application application;
g_Application = &application;
pApp->onAppCmd = handle_cmd; pApp->onAppCmd = handle_cmd;
android_app_set_motion_event_filter(pApp, nullptr); android_app_set_motion_event_filter(pApp, nullptr);
// This sets up a typical game/event loop. It will run until the app is destroyed.
do { do {
auto ms = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
// Process all pending events before running game logic. // Process all pending events before running game logic.
bool done = false; bool done = false;
while (!done) { while (!done) {
// 0 is non-blocking.
int timeout = 0; int timeout = 0;
int events; int events;
android_poll_source *pSource; android_poll_source *pSource;
int result = ALooper_pollOnce(timeout, nullptr, &events, int result = ALooper_pollOnce(timeout, nullptr, &events, reinterpret_cast<void**>(&pSource));
reinterpret_cast<void**>(&pSource));
switch (result) { switch (result) {
case ALOOPER_POLL_TIMEOUT: case ALOOPER_POLL_TIMEOUT:
[[clang::fallthrough]]; [[clang::fallthrough]];
@@ -58,8 +63,13 @@ void android_main(struct android_app *pApp) {
} }
} }
} }
if(application.isInited())
{
application.drawFrame();
}
auto end_ms = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
this_thread::sleep_for(chrono::milliseconds((end_ms-ms)));
} while (!pApp->destroyRequested); } while (!pApp->destroyRequested);
application.cleanup();
} }
} }
+27 -1
View File
@@ -1,4 +1,11 @@
#include "AppBase.h" #include "AppBase.h"
#include <assert.h>
void VK_CHECK(VkResult ret)
{
assert(ret == VK_SUCCESS);
}
std::vector<char> AppBase::readFile(const std::string& enginePath) std::vector<char> AppBase::readFile(const std::string& enginePath)
{ {
@@ -55,6 +62,18 @@ bool AppBase::checkValidationLayerSupport() {
return true; return true;
} }
void checkInstanceExtensions() {
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
logOut << "Android Available instance extensions:" << std::endl;
for (const auto& extension : extensions) {
logOut << "ExtensionName:" << extension.extensionName << " Version:" << extension.specVersion << std::endl;
}
}
void AppBase::createInstance() void AppBase::createInstance()
{ {
@@ -84,7 +103,14 @@ void AppBase::createInstance()
for(int i = 0; i < glfwExtensionCount; i++) { for(int i = 0; i < glfwExtensionCount; i++) {
extensions.push_back(glfwExtensions[i]); extensions.push_back(glfwExtensions[i]);
} }
#else
checkInstanceExtensions();
// Android: 手动添加必要的扩展
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
// 可选:添加这些扩展以获得更好的兼容性
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
#endif #endif
if (enableValidationLayers) { if (enableValidationLayers) {
@@ -160,7 +186,7 @@ QueueFamilyIndices AppBase::findQueueFamilies(VkPhysicalDevice device, VkSurface
indices.graphicsFamily = i; indices.graphicsFamily = i;
} }
VkBool32 presentSupport = false; VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport); VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport));
if (presentSupport) { if (presentSupport) {
indices.presentFamily = i; indices.presentFamily = i;
} }
+17 -10
View File
@@ -1,23 +1,28 @@
#ifndef VULKAN_UTILS_H #ifndef VULKAN_UTILS_H
#define VULKAN_UTILS_H #define VULKAN_UTILS_H
#define VK_CHECK(x) \ //#define VK_CHECK(x) \
do \ // do \
{ \ // { \
VkResult err = x; \ // VkResult ret = x; \
if (err) \ // if (ret != VK_SUCCESS) \
{ \ // { \
assert(false); \ // assert(false); \
} \ // } \
} while (0) // } while (0)
#ifdef _WIN32 #ifdef _WIN32
#define logOut std::cout #define logOut std::cout
#define GLFW_INCLUDE_VULKAN #define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#else #else
#include "../app/src/main/cpp/AndroidOut.h"
#define logOut aout #define logOut aout
#define VK_USE_PLATFORM_ANDROID_KHR
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <vulkan/vulkan_android.h>
#include <android/native_window.h>
#endif #endif
@@ -29,7 +34,9 @@
#include <vector> #include <vector>
#include <optional> #include <optional>
#include <set> #include <set>
#include <assert.h>
void VK_CHECK(VkResult ret);
struct QueueFamilyIndices { struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily; std::optional<uint32_t> graphicsFamily;
+10 -10
View File
@@ -44,7 +44,7 @@ void Application::createSurface() {
} }
#else #else
VkSurfaceKHR surface{}; //VkSurfaceKHR surface{};
VkAndroidSurfaceCreateInfoKHR info{VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR}; VkAndroidSurfaceCreateInfoKHR info{VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR};
@@ -73,6 +73,7 @@ void Application::initVulkan()
createCommandPool(); // 创建命令池 createCommandPool(); // 创建命令池
createCommandBuffer(); // 创建命令缓冲区 createCommandBuffer(); // 创建命令缓冲区
createSyncObjects(); // 创建同步对象 createSyncObjects(); // 创建同步对象
inited = true;
} }
void Application::createImageViews() { void Application::createImageViews() {
@@ -259,6 +260,7 @@ void Application::createSwapChain() {
swapChainImageFormat = surfaceFormat.format; swapChainImageFormat = surfaceFormat.format;
swapChainExtent = extent; swapChainExtent = extent;
MAX_FRAMES_IN_FLIGHT = imageCount;
} }
void Application::createPipelineLayout() { void Application::createPipelineLayout() {
@@ -447,12 +449,11 @@ void Application::createCommandBuffer()
void Application::createSyncObjects() void Application::createSyncObjects()
{ {
int swapChainImageCount = swapChainImages.size();
imageAvailableSemaphores.resize(swapChainImageCount); imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
renderFinishedSemaphores.resize(swapChainImageCount); renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
imagesInFlight.resize(swapChainImageCount, VK_NULL_HANDLE); imagesInFlight.resize(MAX_FRAMES_IN_FLIGHT, VK_NULL_HANDLE);
VkSemaphoreCreateInfo semaphoreInfo{}; VkSemaphoreCreateInfo semaphoreInfo{};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
@@ -462,7 +463,7 @@ void Application::createSyncObjects()
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
// 为每个交换链图像创建信号量 // 为每个交换链图像创建信号量
for (size_t i = 0; i < swapChainImageCount; i++) { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS || if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS) { vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS) {
throw std::runtime_error("failed to create synchronization objects!"); throw std::runtime_error("failed to create synchronization objects!");
@@ -516,15 +517,14 @@ void Application::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t im
} }
} }
void Application::drawFrame() { void Application::drawFrame()
{
// 1. 等待前一帧完成 // 1. 等待前一帧完成
vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
// 2. 获取交换链图像 - 使用当前帧的信号量 // 2. 获取交换链图像 - 使用当前帧的信号量
uint32_t imageIndex; uint32_t imageIndex;
VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX,imageAvailableSemaphores[currentFrame],VK_NULL_HANDLE, &imageIndex);
imageAvailableSemaphores[currentFrame],
VK_NULL_HANDLE, &imageIndex);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
throw std::runtime_error("failed to acquire swap chain image!"); throw std::runtime_error("failed to acquire swap chain image!");
+2 -1
View File
@@ -11,7 +11,6 @@ class Application : public AppBase
public: public:
void run(); void run();
protected:
void initVulkan(); void initVulkan();
void initWindow(); void initWindow();
void createSurface(); void createSurface();
@@ -31,6 +30,7 @@ protected:
void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex); void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex);
void createSyncObjects(); void createSyncObjects();
void drawFrame(); void drawFrame();
bool isInited() { return inited; }
private: private:
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; // 物理设备 VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; // 物理设备
VkDevice device; // 逻辑设备 VkDevice device; // 逻辑设备
@@ -55,4 +55,5 @@ private:
std::vector<VkFence> imagesInFlight; // 跟踪每个图像的使用状态 std::vector<VkFence> imagesInFlight; // 跟踪每个图像的使用状态
int currentFrame = 0; int currentFrame = 0;
int MAX_FRAMES_IN_FLIGHT = 2; int MAX_FRAMES_IN_FLIGHT = 2;
bool inited = false;
}; };