host_copy_formats;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index c199b5953c..5975ae13a7 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1033,6 +1033,24 @@ void TextureCache::RefreshContents(Image& image, ImageId image_id) {
QueueAsyncDecode(image, image_id);
return;
}
+ if constexpr (requires { runtime.GuestMemorySource(nullptr, size_t{}); }) {
+ if (True(image.flags & ImageFlagBits::AcceleratedUpload) && runtime.HasGuestMemory() &&
+ gpu_memory->IsContinuousRange(image.gpu_addr, image.guest_size_bytes)) {
+ const std::optional device_addr = gpu_memory->GpuToCpuAddress(image.gpu_addr);
+ if (device_addr) {
+ const auto source = runtime.GuestMemorySource(
+ device_memory.GetSpan(*device_addr, image.guest_size_bytes),
+ image.guest_size_bytes);
+ if (source) {
+ gpu_memory->FlushRegion(image.gpu_addr, image.guest_size_bytes,
+ VideoCommon::CacheType::NoTextureCache);
+ runtime.AccelerateImageUpload(
+ image, *source, FixSmallVectorADL(FullUploadSwizzles(image.info)));
+ return;
+ }
+ }
+ }
+ }
if constexpr (requires { image.UploadHostMemory(unswizzle_data_buffer, {}); }) {
if (True(image.flags & ImageFlagBits::ReorderableUpload) && image.CanUploadHostMemory()) {
Tegra::Memory::GpuGuestMemory
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index cd5e5a8412..12d7cfbba8 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -934,6 +934,15 @@ bool Device::GetSuitability(bool requires_swapchain) {
FOR_EACH_VK_FEATURE_EXT(FEATURE_EXTENSION);
FOR_EACH_VK_EXTENSION(EXTENSION);
+#ifdef __ANDROID__
+ if (supported_extensions.contains(
+ VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME) &&
+ supported_extensions.contains(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME)) {
+ loaded_extensions.insert(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
+ loaded_extensions.insert(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME);
+ has_ahb_import = true;
+ }
+#endif
extensions.depth_stencil_resolve =
extensions.depth_stencil_resolve &&
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 63a2e5b7fa..ab96421c3a 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -993,6 +993,10 @@ FN_MAX_LIMIT_LIST
return extensions.host_image_copy;
}
+ bool IsAhbImportSupported() const {
+ return has_ahb_import;
+ }
+
bool HasNullDescriptor() const {
return features.robustness2.nullDescriptor;
}
@@ -1208,6 +1212,7 @@ private:
bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest.
bool is_integrated{}; ///< Is GPU an iGPU.
bool is_uma{};
+ bool has_ahb_import{};
bool has_broken_compute{}; ///< Compute shaders can cause crashes
bool has_broken_cube_compatibility{}; ///< Has broken cube compatibility bit
bool has_broken_float16_math{};
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 01a65f95f5..1d728e9113 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -85,6 +85,12 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkAcquireNextImageKHR);
X(vkAllocateCommandBuffers);
X(vkAllocateDescriptorSets);
+ X(vkAllocateMemory);
+ X(vkBindBufferMemory);
+ X(vkFreeMemory);
+#ifdef __ANDROID__
+ X(vkGetAndroidHardwareBufferPropertiesANDROID);
+#endif
X(vkBeginCommandBuffer);
X(vkCmdBeginConditionalRenderingEXT);
X(vkCmdBeginQuery);
@@ -337,6 +343,10 @@ void Destroy(VkDevice device, VkBuffer handle, const DeviceDispatch& dld) noexce
dld.vkDestroyBuffer(device, handle, nullptr);
}
+void Destroy(VkDevice device, VkDeviceMemory handle, const DeviceDispatch& dld) noexcept {
+ dld.vkFreeMemory(device, handle, nullptr);
+}
+
void Destroy(VkDevice device, VkBufferView handle, const DeviceDispatch& dld) noexcept {
dld.vkDestroyBufferView(device, handle, nullptr);
}
@@ -616,6 +626,51 @@ BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const {
return BufferView(object, handle, *dld);
}
+ExternalBuffer Device::CreateExternalBuffer(const VkBufferCreateInfo& ci) const {
+ VkBuffer object;
+ Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object));
+ return ExternalBuffer(object, handle, *dld);
+}
+
+DeviceMemory Device::AllocateMemory(const VkMemoryAllocateInfo& ai) const {
+ VkDeviceMemory object;
+ Check(dld->vkAllocateMemory(handle, &ai, nullptr, &object));
+ return DeviceMemory(object, handle, *dld);
+}
+
+void Device::BindBufferMemory(VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize offset) const {
+ Check(dld->vkBindBufferMemory(handle, buffer, memory, offset));
+}
+
+VkMemoryRequirements Device::GetBufferMemoryRequirements(VkBuffer buffer) const noexcept {
+ const VkBufferMemoryRequirementsInfo2 info{
+ .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
+ .pNext = nullptr,
+ .buffer = buffer,
+ };
+ VkMemoryRequirements2 requirements{
+ .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
+ .pNext = nullptr,
+ .memoryRequirements = {},
+ };
+ dld->vkGetBufferMemoryRequirements2(handle, &info, &requirements);
+ return requirements.memoryRequirements;
+}
+
+#ifdef __ANDROID__
+VkAndroidHardwareBufferPropertiesANDROID Device::GetAndroidHardwareBufferProperties(
+ const AHardwareBuffer* buffer) const {
+ VkAndroidHardwareBufferPropertiesANDROID properties{
+ .sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
+ .pNext = nullptr,
+ .allocationSize = 0,
+ .memoryTypeBits = 0,
+ };
+ Check(dld->vkGetAndroidHardwareBufferPropertiesANDROID(handle, buffer, &properties));
+ return properties;
+}
+#endif
+
ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const {
VkImageView object;
Check(dld->vkCreateImageView(handle, &ci, nullptr, &object));
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h
index c896a22bad..e0bb7585ac 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -234,6 +234,12 @@ struct DeviceDispatch : InstanceDispatch {
PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR{};
PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers{};
PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets{};
+ PFN_vkAllocateMemory vkAllocateMemory{};
+ PFN_vkBindBufferMemory vkBindBufferMemory{};
+ PFN_vkFreeMemory vkFreeMemory{};
+#ifdef __ANDROID__
+ PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID{};
+#endif
PFN_vkBeginCommandBuffer vkBeginCommandBuffer{};
PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT{};
PFN_vkCmdBeginQuery vkCmdBeginQuery{};
@@ -387,6 +393,7 @@ void Destroy(VkDevice, const InstanceDispatch&) noexcept;
void Destroy(VkDevice, VkBuffer, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkBufferView, const DeviceDispatch&) noexcept;
+void Destroy(VkDevice, VkDeviceMemory, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept;
@@ -646,6 +653,8 @@ using Pipeline = Handle;
using PipelineLayout = Handle;
using QueryPool = Handle;
using Sampler = Handle;
+using DeviceMemory = Handle;
+using ExternalBuffer = Handle;
using SurfaceKHR = Handle;
using DescriptorSets = PoolAllocations;
@@ -1000,6 +1009,19 @@ public:
[[nodiscard]] BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const;
+ [[nodiscard]] ExternalBuffer CreateExternalBuffer(const VkBufferCreateInfo& ci) const;
+
+ [[nodiscard]] DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const;
+
+ void BindBufferMemory(VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize offset) const;
+
+ [[nodiscard]] VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer buffer) const noexcept;
+
+#ifdef __ANDROID__
+ [[nodiscard]] VkAndroidHardwareBufferPropertiesANDROID GetAndroidHardwareBufferProperties(
+ const AHardwareBuffer* buffer) const;
+#endif
+
[[nodiscard]] ImageView CreateImageView(const VkImageViewCreateInfo& ci) const;
[[nodiscard]] Semaphore CreateSemaphore() const;