android 表面,扩展,实例都创建成功
This commit is contained in:
+5
-1
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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!");
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user