Merge "Disconnect from surface when the RenderSurface object is removed." into qt-dev
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index a5cc0df..dbb4f22 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -534,7 +534,7 @@
}
AddRuntimeArg(target_sdk_version_arg);
if (enable_hidden_api_checks) {
- AddRuntimeArg("-Xhidden-api-checks");
+ AddRuntimeArg("-Xhidden-api-policy:enabled");
}
if (dex_metadata_fd > -1) {
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index b1c577e..70ed80d 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -66,15 +66,12 @@
const int LOCATION_VENDOR = 0x2;
/* ApplicationInfo.isProduct() == true */
const int LOCATION_PRODUCT = 0x4;
- /* ApplicationInfo.isProductServices() == true */
- const int LOCATION_PRODUCT_SERVICES = 0x8;
/**
* Returns a set of bitflags about package location.
* LOCATION_SYSTEM: getApplicationInfo(packageName).isSystemApp()
* LOCATION_VENDOR: getApplicationInfo(packageName).isVendor()
* LOCATION_PRODUCT: getApplicationInfo(packageName).isProduct()
- * LOCATION_PRODUCT_SERVICES: getApplicationInfo(packageName).isProductService()
*/
int getLocationFlags(in @utf8InCpp String packageName);
}
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 7e2b03d..16f6729 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -86,8 +86,9 @@
mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs};
}
-PhaseOffsets::Offsets PhaseOffsets::getCurrentOffsets() const {
- switch (mRefreshRateType) {
+PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(
+ android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const {
+ switch (refreshRateType) {
case RefreshRateConfigs::RefreshRateType::PERFORMANCE:
return mHighRefreshRateOffsets;
default:
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index a85660a..08747a5 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -42,6 +42,8 @@
virtual nsecs_t getCurrentAppOffset() = 0;
virtual nsecs_t getCurrentSfOffset() = 0;
+ virtual Offsets getOffsetsForRefreshRate(
+ RefreshRateConfigs::RefreshRateType refreshRateType) const = 0;
virtual Offsets getCurrentOffsets() const = 0;
virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0;
virtual void dump(std::string& result) const = 0;
@@ -55,8 +57,14 @@
nsecs_t getCurrentAppOffset() override;
nsecs_t getCurrentSfOffset() override;
+ // Returns early, early GL, and late offsets for Apps and SF for a given refresh rate.
+ Offsets getOffsetsForRefreshRate(
+ RefreshRateConfigs::RefreshRateType refreshRateType) const override;
+
// Returns early, early GL, and late offsets for Apps and SF.
- Offsets getCurrentOffsets() const override;
+ Offsets getCurrentOffsets() const override {
+ return getOffsetsForRefreshRate(mRefreshRateType);
+ }
// This function should be called when the device is switching between different
// refresh rates, to properly update the offsets.
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index eb9ae35..d730058 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -47,6 +47,8 @@
std::string name;
// Refresh rate in frames per second, rounded to the nearest integer.
uint32_t fps = 0;
+ // config Id (returned from HWC2::Display::Config::getId())
+ hwc2_config_t id;
};
// TODO(b/122916473): Get this information from configs prepared by vendors, instead of
@@ -62,13 +64,24 @@
return nullptr;
}
+ RefreshRateType getRefreshRateType(hwc2_config_t id) const {
+ for (const auto& [type, refreshRate] : mRefreshRates) {
+ if (refreshRate->id == id) {
+ return type;
+ }
+ }
+
+ return RefreshRateType::DEFAULT;
+ }
+
void populate(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
mRefreshRates.clear();
// This is the rate that HWC encapsulates right now when the device is in DOZE mode.
mRefreshRates.emplace(RefreshRateType::POWER_SAVING,
std::make_shared<RefreshRate>(
- RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}));
+ RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0,
+ HWC2_SCREEN_OFF_CONFIG_ID}));
if (configs.size() < 1) {
ALOGE("Device does not have valid configs. Config size is 0.");
@@ -91,11 +104,12 @@
nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second;
if (vsyncPeriod != 0) {
const float fps = 1e9 / vsyncPeriod;
+ const int configId = configIdToVsyncPeriod[0].first;
mRefreshRates.emplace(RefreshRateType::DEFAULT,
std::make_shared<RefreshRate>(
- RefreshRate{configIdToVsyncPeriod[0].first,
- base::StringPrintf("%2.ffps", fps),
- static_cast<uint32_t>(fps)}));
+ RefreshRate{configId, base::StringPrintf("%2.ffps", fps),
+ static_cast<uint32_t>(fps),
+ configs.at(configId)->getId()}));
}
if (configs.size() < 2) {
@@ -107,11 +121,12 @@
vsyncPeriod = configIdToVsyncPeriod[1].second;
if (vsyncPeriod != 0) {
const float fps = 1e9 / vsyncPeriod;
+ const int configId = configIdToVsyncPeriod[1].first;
mRefreshRates.emplace(RefreshRateType::PERFORMANCE,
std::make_shared<RefreshRate>(
- RefreshRate{configIdToVsyncPeriod[1].first,
- base::StringPrintf("%2.ffps", fps),
- static_cast<uint32_t>(fps)}));
+ RefreshRate{configId, base::StringPrintf("%2.ffps", fps),
+ static_cast<uint32_t>(fps),
+ configs.at(configId)->getId()}));
}
}
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index a935cac..3bf3922 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -34,6 +34,7 @@
// the config is not visible to SF, and is completely maintained by HWC. However, we would
// still like to keep track of time when the device is in this config.
static constexpr int SCREEN_OFF_CONFIG_ID = -1;
+static constexpr uint32_t HWC2_SCREEN_OFF_CONFIG_ID = 0xffffffff;
// This number is used when we try to determine how long does a given layer stay relevant.
// Currently it is set to 100ms, because that would indicate 10Hz rendering.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 53c615f..6063555 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -860,7 +860,9 @@
info.xdpi = xdpi;
info.ydpi = ydpi;
info.fps = 1e9 / hwConfig->getVsyncPeriod();
- info.appVsyncOffset = mPhaseOffsets->getCurrentAppOffset();
+ const auto refreshRateType = mRefreshRateConfigs.getRefreshRateType(hwConfig->getId());
+ const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(refreshRateType);
+ info.appVsyncOffset = offset.late.app;
// This is how far in advance a buffer must be queued for
// presentation at a given time. If you want a buffer to appear
@@ -874,8 +876,7 @@
//
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
- info.presentationDeadline =
- hwConfig->getVsyncPeriod() - mPhaseOffsets->getCurrentSfOffset() + 1000000;
+ info.presentationDeadline = hwConfig->getVsyncPeriod() - offset.late.sf + 1000000;
// All non-virtual displays are currently considered secure.
info.secure = true;
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 6b2b583..34df606 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -144,6 +144,9 @@
} else {
ALOGW("cannot find listener in mPendingTransactions");
}
+ if (listener->second.size() == 0) {
+ mPendingTransactions.erase(listener);
+ }
status_t err = addCallbackHandle(handle);
if (err != NO_ERROR) {
@@ -231,7 +234,9 @@
// If we are still waiting on the callback handles for this transaction, stop
// here because all transaction callbacks for the same listener must come in order
- if (mPendingTransactions[listener].count(transactionStats.callbackIds) != 0) {
+ auto pendingTransactions = mPendingTransactions.find(listener);
+ if (pendingTransactions != mPendingTransactions.end() &&
+ pendingTransactions->second.count(transactionStats.callbackIds) != 0) {
break;
}
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index 0739f15..cfa8337 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -33,6 +33,11 @@
nsecs_t getCurrentAppOffset() override { return FAKE_PHASE_OFFSET_NS; }
nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; }
+ PhaseOffsets::Offsets getOffsetsForRefreshRate(
+ RefreshRateConfigs::RefreshRateType /*refreshRateType*/) const override {
+ return getCurrentOffsets();
+ }
+
// Returns early, early GL, and late offsets for Apps and SF.
PhaseOffsets::Offsets getCurrentOffsets() const override {
return Offsets{{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 8b37c22..5067fe8 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -37,7 +37,9 @@
class RefreshRateConfigsTest : public testing::Test {
protected:
static constexpr int CONFIG_ID_60 = 0;
+ static constexpr hwc2_config_t HWC2_CONFIG_ID_60 = 0;
static constexpr int CONFIG_ID_90 = 1;
+ static constexpr hwc2_config_t HWC2_CONFIG_ID_90 = 1;
static constexpr int64_t VSYNC_60 = 16666667;
static constexpr int64_t VSYNC_90 = 11111111;
@@ -81,7 +83,8 @@
ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE));
ASSERT_EQ(rates.end(), rates.find(RefreshRateType::DEFAULT));
- RefreshRate expectedConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
+ RefreshRate expectedConfig =
+ RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID};
assertRatesEqual(expectedConfig, *powerSavingRate->second);
ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
@@ -109,9 +112,10 @@
ASSERT_NE(rates.end(), defaultRate);
ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE));
- RefreshRate expectedPowerSavingConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
+ RefreshRate expectedPowerSavingConfig =
+ RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID};
assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second);
- RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60};
+ RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60, HWC2_CONFIG_ID_60};
assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
@@ -145,11 +149,13 @@
ASSERT_NE(rates.end(), defaultRate);
ASSERT_NE(rates.end(), performanceRate);
- RefreshRate expectedPowerSavingConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
+ RefreshRate expectedPowerSavingConfig =
+ RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID};
assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second);
- RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60};
+ RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60, HWC2_CONFIG_ID_60};
assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
- RefreshRate expectedPerformanceConfig = RefreshRate{CONFIG_ID_90, "90fps", 90};
+ RefreshRate expectedPerformanceConfig =
+ RefreshRate{CONFIG_ID_90, "90fps", 90, HWC2_CONFIG_ID_90};
assertRatesEqual(expectedPerformanceConfig, *performanceRate->second);
ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index f04eb03..bdd3573 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -703,6 +703,7 @@
{{Macro "driver.InterceptedExtensions"}}
VK_KHR_get_physical_device_properties2
VK_ANDROID_external_memory_android_hardware_buffer
+VK_KHR_bind_memory2
{{end}}
@@ -750,6 +751,9 @@
{{else if eq $.Name "vkGetInstanceProcAddr"}}true
{{else if eq $.Name "vkGetDeviceProcAddr"}}true
+ {{/* VK_KHR_swapchain v69 requirement */}}
+ {{else if eq $.Name "vkBindImageMemory2"}}true
+ {{else if eq $.Name "vkBindImageMemory2KHR"}}true
{{end}}
{{$ext := GetAnnotation $ "extension"}}
@@ -985,6 +989,10 @@
{{else if eq $.Name "vkGetPhysicalDeviceProperties"}}true
{{else if eq $.Name "vkGetPhysicalDeviceProperties2"}}true
{{else if eq $.Name "vkGetPhysicalDeviceProperties2KHR"}}true
+
+ {{/* VK_KHR_swapchain v69 requirement */}}
+ {{else if eq $.Name "vkBindImageMemory2"}}true
+ {{else if eq $.Name "vkBindImageMemory2KHR"}}true
{{end}}
{{$ext := GetAnnotation $ "extension"}}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index b3259de..491d4d1 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -537,6 +537,7 @@
// Extensions we don't need to do anything about at this level
break;
+ case ProcHook::KHR_bind_memory2:
case ProcHook::KHR_incremental_present:
case ProcHook::KHR_shared_presentable_image:
case ProcHook::KHR_swapchain:
@@ -577,6 +578,7 @@
// return now as these extensions do not require HAL support
return;
case ProcHook::EXT_hdr_metadata:
+ case ProcHook::KHR_bind_memory2:
hook_extensions_.set(ext_bit);
break;
case ProcHook::ANDROID_external_memory_android_hardware_buffer:
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index ec98b9f..574c327 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -137,6 +137,15 @@
}
}
+VKAPI_ATTR VkResult checkedBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHR* pBindInfos) {
+ if (GetData(device).hook_extensions[ProcHook::KHR_bind_memory2]) {
+ return BindImageMemory2KHR(device, bindInfoCount, pBindInfos);
+ } else {
+ Logger(device).Err(device, "VK_KHR_bind_memory2 not enabled. vkBindImageMemory2KHR not executed.");
+ return VK_SUCCESS;
+ }
+}
+
// clang-format on
const ProcHook g_proc_hooks[] = {
@@ -170,6 +179,20 @@
nullptr,
},
{
+ "vkBindImageMemory2",
+ ProcHook::DEVICE,
+ ProcHook::EXTENSION_CORE,
+ reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2),
+ nullptr,
+ },
+ {
+ "vkBindImageMemory2KHR",
+ ProcHook::DEVICE,
+ ProcHook::KHR_bind_memory2,
+ reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2KHR),
+ reinterpret_cast<PFN_vkVoidFunction>(checkedBindImageMemory2KHR),
+ },
+ {
"vkCreateAndroidSurfaceKHR",
ProcHook::INSTANCE,
ProcHook::KHR_android_surface,
@@ -458,6 +481,7 @@
if (strcmp(name, "VK_KHR_get_surface_capabilities2") == 0) return ProcHook::KHR_get_surface_capabilities2;
if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2;
if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer;
+ if (strcmp(name, "VK_KHR_bind_memory2") == 0) return ProcHook::KHR_bind_memory2;
// clang-format on
return ProcHook::EXTENSION_UNKNOWN;
}
@@ -517,11 +541,13 @@
INIT_PROC(true, dev, CreateImage);
INIT_PROC(true, dev, DestroyImage);
INIT_PROC(true, dev, AllocateCommandBuffers);
+ INIT_PROC(false, dev, BindImageMemory2);
INIT_PROC(false, dev, GetDeviceQueue2);
INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsageANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage2ANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, true, dev, AcquireImageANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, true, dev, QueueSignalReleaseImageANDROID);
+ INIT_PROC_EXT(KHR_bind_memory2, true, dev, BindImageMemory2KHR);
// clang-format on
return success;
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 14c3aba..3faf6c0 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -46,6 +46,7 @@
KHR_get_surface_capabilities2,
KHR_get_physical_device_properties2,
ANDROID_external_memory_android_hardware_buffer,
+ KHR_bind_memory2,
EXTENSION_CORE, // valid bit
EXTENSION_COUNT,
@@ -85,11 +86,13 @@
PFN_vkCreateImage CreateImage;
PFN_vkDestroyImage DestroyImage;
PFN_vkAllocateCommandBuffers AllocateCommandBuffers;
+ PFN_vkBindImageMemory2 BindImageMemory2;
PFN_vkGetDeviceQueue2 GetDeviceQueue2;
PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
PFN_vkGetSwapchainGrallocUsage2ANDROID GetSwapchainGrallocUsage2ANDROID;
PFN_vkAcquireImageANDROID AcquireImageANDROID;
PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
+ PFN_vkBindImageMemory2KHR BindImageMemory2KHR;
// clang-format on
};
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 73fc7b2..bc00190 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -16,17 +16,19 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <algorithm>
-
+#include <android/hardware/graphics/common/1.0/types.h>
#include <grallocusage/GrallocUsageConversion.h>
#include <log/log.h>
-#include <ui/BufferQueueDefs.h>
#include <sync/sync.h>
+#include <system/window.h>
+#include <ui/BufferQueueDefs.h>
#include <utils/StrongPointer.h>
#include <utils/Trace.h>
#include <utils/Vector.h>
-#include <system/window.h>
-#include <android/hardware/graphics/common/1.0/types.h>
+
+#include <algorithm>
+#include <unordered_set>
+#include <vector>
#include "driver.h"
@@ -1818,5 +1820,106 @@
return;
}
+static void InterceptBindImageMemory2(
+ uint32_t bind_info_count,
+ const VkBindImageMemoryInfo* bind_infos,
+ std::vector<VkNativeBufferANDROID>* out_native_buffers,
+ std::vector<VkBindImageMemoryInfo>* out_bind_infos) {
+ out_native_buffers->clear();
+ out_bind_infos->clear();
+
+ if (!bind_info_count)
+ return;
+
+ std::unordered_set<uint32_t> intercepted_indexes;
+
+ for (uint32_t idx = 0; idx < bind_info_count; idx++) {
+ auto info = reinterpret_cast<const VkBindImageMemorySwapchainInfoKHR*>(
+ bind_infos[idx].pNext);
+ while (info &&
+ info->sType !=
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR) {
+ info = reinterpret_cast<const VkBindImageMemorySwapchainInfoKHR*>(
+ info->pNext);
+ }
+
+ if (!info)
+ continue;
+
+ ALOG_ASSERT(info->swapchain != VK_NULL_HANDLE,
+ "swapchain handle must not be NULL");
+ const Swapchain* swapchain = SwapchainFromHandle(info->swapchain);
+ ALOG_ASSERT(
+ info->imageIndex < swapchain->num_images,
+ "imageIndex must be less than the number of images in swapchain");
+
+ ANativeWindowBuffer* buffer =
+ swapchain->images[info->imageIndex].buffer.get();
+ VkNativeBufferANDROID native_buffer = {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+ .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
+#pragma clang diagnostic pop
+ .pNext = bind_infos[idx].pNext,
+ .handle = buffer->handle,
+ .stride = buffer->stride,
+ .format = buffer->format,
+ .usage = int(buffer->usage),
+ };
+ // Reserve enough space to avoid letting re-allocation invalidate the
+ // addresses of the elements inside.
+ out_native_buffers->reserve(bind_info_count);
+ out_native_buffers->emplace_back(native_buffer);
+
+ // Reserve the space now since we know how much is needed now.
+ out_bind_infos->reserve(bind_info_count);
+ out_bind_infos->emplace_back(bind_infos[idx]);
+ out_bind_infos->back().pNext = &out_native_buffers->back();
+
+ intercepted_indexes.insert(idx);
+ }
+
+ if (intercepted_indexes.empty())
+ return;
+
+ for (uint32_t idx = 0; idx < bind_info_count; idx++) {
+ if (intercepted_indexes.count(idx))
+ continue;
+ out_bind_infos->emplace_back(bind_infos[idx]);
+ }
+}
+
+VKAPI_ATTR
+VkResult BindImageMemory2(VkDevice device,
+ uint32_t bindInfoCount,
+ const VkBindImageMemoryInfo* pBindInfos) {
+ ATRACE_CALL();
+
+ // out_native_buffers is for maintaining the lifecycle of the constructed
+ // VkNativeBufferANDROID objects inside InterceptBindImageMemory2.
+ std::vector<VkNativeBufferANDROID> out_native_buffers;
+ std::vector<VkBindImageMemoryInfo> out_bind_infos;
+ InterceptBindImageMemory2(bindInfoCount, pBindInfos, &out_native_buffers,
+ &out_bind_infos);
+ return GetData(device).driver.BindImageMemory2(
+ device, bindInfoCount,
+ out_bind_infos.empty() ? pBindInfos : out_bind_infos.data());
+}
+
+VKAPI_ATTR
+VkResult BindImageMemory2KHR(VkDevice device,
+ uint32_t bindInfoCount,
+ const VkBindImageMemoryInfo* pBindInfos) {
+ ATRACE_CALL();
+
+ std::vector<VkNativeBufferANDROID> out_native_buffers;
+ std::vector<VkBindImageMemoryInfo> out_bind_infos;
+ InterceptBindImageMemory2(bindInfoCount, pBindInfos, &out_native_buffers,
+ &out_bind_infos);
+ return GetData(device).driver.BindImageMemory2KHR(
+ device, bindInfoCount,
+ out_bind_infos.empty() ? pBindInfos : out_bind_infos.data());
+}
+
} // namespace driver
} // namespace vulkan
diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h
index ed5718c..4912ef1 100644
--- a/vulkan/libvulkan/swapchain.h
+++ b/vulkan/libvulkan/swapchain.h
@@ -44,6 +44,8 @@
VKAPI_ATTR void SetHdrMetadataEXT(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pHdrMetadataEXTs);
VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats);
+VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
+VKAPI_ATTR VkResult BindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
// clang-format on
} // namespace driver